From 7d3e2bd2c4cfd1296d1d6f996d7548de26540d41 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Fri, 15 Feb 2013 16:27:18 -0800 Subject: Sync with 8 months of Google-internal development. Many things have changed and been simplified. The memory-management story for upb_def and upb_handlers is much more robust; upb_def and upb_handlers should be fairly stable interfaces now. There is still much work to do for the runtime component (upb_sink). --- bindings/cpp/upb/proto2_bridge.cc | 892 -------------------------------------- 1 file changed, 892 deletions(-) delete mode 100644 bindings/cpp/upb/proto2_bridge.cc (limited to 'bindings/cpp/upb/proto2_bridge.cc') diff --git a/bindings/cpp/upb/proto2_bridge.cc b/bindings/cpp/upb/proto2_bridge.cc deleted file mode 100644 index 6119295..0000000 --- a/bindings/cpp/upb/proto2_bridge.cc +++ /dev/null @@ -1,892 +0,0 @@ -// -// upb - a minimalist implementation of protocol buffers. -// -// Copyright (c) 2011-2012 Google Inc. See LICENSE for details. -// Author: Josh Haberman - -#include -#include -#include "upb/bytestream.hpp" -#include "upb/def.hpp" -#include "upb/handlers.hpp" -#include "upb/msg.hpp" -#include "upb/proto2_bridge.hpp" - -namespace { - -static void* GetFieldPointer(void *message, const upb::FieldDef* f) { - return static_cast(message) + f->offset(); -} - -} // namespace - -#ifdef UPB_GOOGLE3 - -// TODO(haberman): friend upb so that this isn't required. -#define protected public -#include "net/proto2/public/repeated_field.h" -#undef private - -#define private public -#include "net/proto/proto2_reflection.h" -#undef private - -#include "net/proto2/proto/descriptor.pb.h" -#include "net/proto2/public/descriptor.h" -#include "net/proto2/public/generated_message_reflection.h" -#include "net/proto2/public/lazy_field.h" -#include "net/proto2/public/message.h" -#include "net/proto2/public/string_piece_field_support.h" -#include "net/proto/internal_layout.h" -#include "strings/cord.h" -using ::proto2::Descriptor; -using ::proto2::EnumDescriptor; -using ::proto2::EnumValueDescriptor; -using ::proto2::FieldDescriptor; -using ::proto2::FieldOptions; -using ::proto2::FileDescriptor; -using ::proto2::internal::GeneratedMessageReflection; -using ::proto2::internal::RepeatedPtrFieldBase; -using ::proto2::internal::StringPieceField; -using ::proto2::Message; -using ::proto2::MessageFactory; -using ::proto2::Reflection; -using ::proto2::RepeatedField; -using ::proto2::RepeatedPtrField; - -namespace upb { - -static const Message* GetPrototypeForField(const Message& m, - const FieldDescriptor* f); - -namespace proto2_bridge_google3 { class FieldAccessor; } - -using ::upb::proto2_bridge_google3::FieldAccessor; - -namespace proto2_bridge_google3 { - -static void AssignToCord(const ByteRegion* r, Cord* cord) { - // TODO(haberman): ref source data if source is a cord. - cord->Clear(); - uint64_t ofs = r->start_ofs(); - while (ofs < r->end_ofs()) { - size_t len; - const char *buf = r->GetPtr(ofs, &len); - cord->Append(StringPiece(buf, len)); - ofs += len; - } -} - -#else - -// TODO(haberman): friend upb so that this isn't required. -#define protected public -#include "google/protobuf/repeated_field.h" -#undef protected - -#define private public -#include "google/protobuf/generated_message_reflection.h" -#undef private - -#include "google/protobuf/descriptor.h" -#include "google/protobuf/descriptor.pb.h" -#include "google/protobuf/message.h" -using ::google::protobuf::Descriptor; -using ::google::protobuf::EnumDescriptor; -using ::google::protobuf::EnumValueDescriptor; -using ::google::protobuf::FieldDescriptor; -using ::google::protobuf::FieldOptions; -using ::google::protobuf::FileDescriptor; -using ::google::protobuf::internal::GeneratedMessageReflection; -using ::google::protobuf::internal::RepeatedPtrFieldBase; -using ::google::protobuf::Message; -using ::google::protobuf::MessageFactory; -using ::google::protobuf::Reflection; -using ::google::protobuf::RepeatedField; -using ::google::protobuf::RepeatedPtrField; - -namespace upb { -static const Message* GetPrototypeForField(const Message& m, - const FieldDescriptor* f); - -namespace proto2_bridge_opensource { class FieldAccessor; } - -using ::upb::proto2_bridge_opensource::FieldAccessor; - -namespace proto2_bridge_opensource { - -#endif // ifdef UPB_GOOGLE3 - -// Have to define this manually since older versions of proto2 didn't define -// an enum value for STRING. -#define UPB_CTYPE_STRING 0 - -// The code in this class depends on the internal representation of the proto2 -// generated classes, which is an internal implementation detail of proto2 and -// is not a public interface. As a result, this class's implementation may -// need to be changed if/when proto2 changes its internal representation. It -// is intended that this class is the only code that depends on these internal, -// non-public interfaces. -// -// This class only works with messages that use GeneratedMessageReflection. -// Other reflection classes will need other accessor implementations. -class FieldAccessor { - public: - // Returns true if we were able to set an accessor and any other properties - // of the FieldDef that are necessary to read/write this field to a - // proto2::Message. - static bool TrySet(const FieldDescriptor* proto2_f, - const upb::MessageDef* md, - upb::FieldDef* upb_f) { - const Message* prototype = static_cast(md->prototype); - const Reflection* base_r = prototype->GetReflection(); - const GeneratedMessageReflection* r = - dynamic_cast(base_r); - // Old versions of the open-source protobuf release erroneously default to - // Cord even though that has never been supported in the open-source - // release. - int32_t ctype = proto2_f->options().has_ctype() ? - proto2_f->options().ctype() : UPB_CTYPE_STRING; - if (!r) return false; - // Extensions not supported yet. - if (proto2_f->is_extension()) return false; - - upb_f->set_accessor(GetForFieldDescriptor(proto2_f, ctype)); - upb_f->set_hasbit(GetHasbit(proto2_f, r)); - upb_f->set_offset(GetOffset(proto2_f, r)); - if (upb_f->IsSubmessage()) { - upb_f->set_subtype_name(proto2_f->message_type()->full_name()); - upb_f->prototype = GetPrototypeForField(*prototype, proto2_f); - } - - if (upb_f->IsString() && !upb_f->IsSequence() && - ctype == UPB_CTYPE_STRING) { - upb_f->prototype = &r->GetStringReference(*prototype, proto2_f, NULL); - } - return true; - } - - static MessageFactory* GetMessageFactory(const Message& m) { - const GeneratedMessageReflection* r = - dynamic_cast(m.GetReflection()); - return r ? r->message_factory_ : NULL; - } - - private: - static int64_t GetHasbit(const FieldDescriptor* f, - const GeneratedMessageReflection* r) { - if (f->is_repeated()) { - // proto2 does not store hasbits for repeated fields. - return -1; - } else { - return (r->has_bits_offset_ * 8) + f->index(); - } - } - - static uint16_t GetOffset(const FieldDescriptor* f, - const GeneratedMessageReflection* r) { - return r->offsets_[f->index()]; - } - - static AccessorVTable *GetForFieldDescriptor(const FieldDescriptor* f, - int32_t ctype) { - switch (f->cpp_type()) { - case FieldDescriptor::CPPTYPE_ENUM: - // Should handlers validate enum membership to match proto2? - case FieldDescriptor::CPPTYPE_INT32: return Get(); - case FieldDescriptor::CPPTYPE_INT64: return Get(); - case FieldDescriptor::CPPTYPE_UINT32: return Get(); - case FieldDescriptor::CPPTYPE_UINT64: return Get(); - case FieldDescriptor::CPPTYPE_DOUBLE: return Get(); - case FieldDescriptor::CPPTYPE_FLOAT: return Get(); - case FieldDescriptor::CPPTYPE_BOOL: return Get(); - case FieldDescriptor::CPPTYPE_STRING: - switch (ctype) { -#ifdef UPB_GOOGLE3 - case FieldOptions::STRING: - return GetForString(); - case FieldOptions::CORD: - return GetForCord(); - case FieldOptions::STRING_PIECE: - return GetForStringPiece(); -#else - case UPB_CTYPE_STRING: - return GetForString(); -#endif - default: return NULL; - } - case FieldDescriptor::CPPTYPE_MESSAGE: -#ifdef UPB_GOOGLE3 - if (f->options().lazy()) { - return NULL; // Not yet implemented. - } else { - return GetForMessage(); - } -#else - return GetForMessage(); -#endif - default: return NULL; - } - } - - // PushOffset handler (used for StartSequence and others) /////////////////// - - static SubFlow PushOffset(void *m, Value fval) { - const FieldDef *f = GetValue(fval); - return UPB_CONTINUE_WITH(GetFieldPointer(m, f)); - } - - // Primitive Value (numeric, enum, bool) ///////////////////////////////////// - - template static AccessorVTable *Get() { - static upb_accessor_vtbl vtbl = { - NULL, // StartSubMessage handler - GetValueHandler(), - &PushOffset, // StartSequence handler - NULL, // StartRepeatedSubMessage handler - &Append, - NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - template - static Flow Append(void *_r, Value fval, Value val) { - (void)fval; - RepeatedField* r = static_cast*>(_r); - r->Add(GetValue(val)); - return UPB_CONTINUE; - } - - // String //////////////////////////////////////////////////////////////////// - - template static AccessorVTable *GetForString() { - static upb_accessor_vtbl vtbl = { - NULL, // StartSubMessage handler - &SetString, - &PushOffset, // StartSequence handler - NULL, // StartRepeatedSubMessage handler - &AppendString, - NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - // This needs to be templated because google3 string is not std::string. - template static Flow SetString(void *m, Value fval, Value val) { - const FieldDef* f = GetValue(fval); - T **str = static_cast(GetFieldPointer(m, f)); - // If it points to the default instance, we must create a new instance. - if (*str == f->prototype) *str = new T(); - GetValue(val)->AssignToString(*str); - return UPB_CONTINUE; - } - - template - static Flow AppendString(void *_r, Value fval, Value val) { - (void)fval; - RepeatedPtrField* r = static_cast*>(_r); - GetValue(val)->AssignToString(r->Add()); - return UPB_CONTINUE; - } - - // SubMessage //////////////////////////////////////////////////////////////// - - static AccessorVTable *GetForMessage() { - static upb_accessor_vtbl vtbl = { - &StartSubMessage, - NULL, // Value handler - &PushOffset, // StartSequence handler - &StartRepeatedSubMessage, - NULL, // Repeated value handler - NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - static SubFlow StartSubMessage(void *m, Value fval) { - const FieldDef* f = GetValue(fval); - void **subm = static_cast(GetFieldPointer(m, f)); - if (*subm == NULL || *subm == f->prototype) { - const Message* prototype = static_cast(f->prototype); - *subm = prototype->New(); - } - return UPB_CONTINUE_WITH(*subm); - } - - class RepeatedMessageTypeHandler { - public: - typedef void Type; - // AddAllocated() calls this, but only if other objects are sitting - // around waiting for reuse, which we will not do. - static void Delete(Type* t) { - (void)t; - assert(false); - } - }; - - // Closure is a RepeatedPtrField*, but we access it through - // its base class RepeatedPtrFieldBase*. - static SubFlow StartRepeatedSubMessage(void* _r, Value fval) { - const FieldDef* f = GetValue(fval); - RepeatedPtrFieldBase *r = static_cast(_r); - void *submsg = r->AddFromCleared(); - if (!submsg) { - const Message* prototype = static_cast(f->prototype); - submsg = prototype->New(); - r->AddAllocated(submsg); - } - return UPB_CONTINUE_WITH(submsg); - } - - // TODO(haberman): handle Extensions, Unknown Fields. - -#ifdef UPB_GOOGLE3 - // Handlers for types/features only included in internal proto2 release: - // Cord, StringPiece, LazyField, and MessageSet. - // TODO(haberman): LazyField, MessageSet. - - // Cord ////////////////////////////////////////////////////////////////////// - - static AccessorVTable *GetForCord() { - static upb_accessor_vtbl vtbl = { - NULL, // StartSubMessage handler - &SetCord, - &PushOffset, // StartSequence handler - NULL, // StartRepeatedSubMessage handler - &AppendCord, - NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - static Flow SetCord(void *m, Value fval, Value val) { - const FieldDef* f = GetValue(fval); - Cord* field = static_cast(GetFieldPointer(m, f)); - AssignToCord(GetValue(val), field); - return UPB_CONTINUE; - } - - static Flow AppendCord(void *_r, Value fval, Value val) { - RepeatedField* r = static_cast*>(_r); - AssignToCord(GetValue(val), r->Add()); - return UPB_CONTINUE; - } - - // StringPiece /////////////////////////////////////////////////////////////// - - static AccessorVTable *GetForStringPiece() { - static upb_accessor_vtbl vtbl = { - NULL, // StartSubMessage handler - &SetStringPiece, - &PushOffset, // StartSequence handler - NULL, // StartRepeatedSubMessage handler - &AppendStringPiece, - NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - static void AssignToStringPieceField(const ByteRegion* r, - proto2::internal::StringPieceField* f) { - // TODO(haberman): alias if possible and enabled on the input stream. - // TODO(haberman): add a method to StringPieceField that lets us avoid - // this copy/malloc/free. - char *data = new char[r->Length()]; - r->Copy(r->start_ofs(), r->Length(), data); - f->CopyFrom(StringPiece(data, r->Length())); - delete[] data; - } - - static Flow SetStringPiece(void *m, Value fval, Value val) { - const FieldDef* f = GetValue(fval); - StringPieceField* field = - static_cast(GetFieldPointer(m, f)); - AssignToStringPieceField(GetValue(val), field); - return UPB_CONTINUE; - } - - static Flow AppendStringPiece(void* _r, Value fval, Value val) { - RepeatedPtrField* r = - static_cast*>(_r); - AssignToStringPieceField(GetValue(val), r->Add()); - return UPB_CONTINUE; - } - -#endif // UPB_GOOGLE3 -}; - -#ifdef UPB_GOOGLE3 - -// Proto1 accessor -- only needed inside Google. -class Proto1FieldAccessor { - public: - // Returns true if we were able to set an accessor and any other properties - // of the FieldDef that are necessary to read/write this field to a - // proto2::Message. - static bool TrySet(const FieldDescriptor* proto2_f, - const upb::MessageDef* md, - upb::FieldDef* upb_f) { - const Message* m = static_cast(md->prototype); - const proto2::Reflection* base_r = m->GetReflection(); - const _pi::Proto2Reflection* r = - dynamic_cast(base_r); - if (!r) return false; - // Extensions not supported yet. - if (proto2_f->is_extension()) return false; - - const _pi::Field* f = r->GetFieldLayout(proto2_f); - - if (f->crep == _pi::CREP_OPTIONAL_FOREIGN_WEAK) { - // Override the BYTES type that proto2 descriptors have for weak fields. - upb_f->set_type(UPB_TYPE(MESSAGE)); - } - - if (upb_f->IsSubmessage()) { - const Message* prototype = upb::GetPrototypeForField(*m, proto2_f); - upb_f->set_subtype_name(prototype->GetDescriptor()->full_name()); - upb_f->prototype = prototype; - } - - upb_f->set_accessor(GetForCrep(f->crep)); - upb_f->set_hasbit(GetHasbit(proto2_f, r)); - upb_f->set_offset(GetOffset(proto2_f, r)); - return true; - } - - private: - static int16_t GetHasbit(const FieldDescriptor* f, - const _pi::Proto2Reflection* r) { - if (f->is_repeated()) { - // proto1 does not store hasbits for repeated fields. - return -1; - } else { - return (r->layout_->has_bit_offset * 8) + r->GetFieldLayout(f)->has_index; - } - } - - static uint16_t GetOffset(const FieldDescriptor* f, - const _pi::Proto2Reflection* r) { - return r->GetFieldLayout(f)->offset; - } - - static AccessorVTable *GetForCrep(int crep) { -#define PRIMITIVE(name, type_name) \ - case _pi::CREP_REQUIRED_ ## name: \ - case _pi::CREP_OPTIONAL_ ## name: \ - case _pi::CREP_REPEATED_ ## name: return Get(); - - switch (crep) { - PRIMITIVE(DOUBLE, double); - PRIMITIVE(FLOAT, float); - PRIMITIVE(INT64, int64_t); - PRIMITIVE(UINT64, uint64_t); - PRIMITIVE(INT32, int32_t); - PRIMITIVE(FIXED64, uint64_t); - PRIMITIVE(FIXED32, uint32_t); - PRIMITIVE(BOOL, bool); - case _pi::CREP_REQUIRED_STRING: - case _pi::CREP_OPTIONAL_STRING: - case _pi::CREP_REPEATED_STRING: return GetForString(); - case _pi::CREP_OPTIONAL_OUTOFLINE_STRING: return GetForOutOfLineString(); - case _pi::CREP_REQUIRED_CORD: - case _pi::CREP_OPTIONAL_CORD: - case _pi::CREP_REPEATED_CORD: return GetForCord(); - case _pi::CREP_REQUIRED_GROUP: - case _pi::CREP_REQUIRED_FOREIGN: - case _pi::CREP_REQUIRED_FOREIGN_PROTO2: return GetForRequiredMessage(); - case _pi::CREP_OPTIONAL_GROUP: - case _pi::CREP_REPEATED_GROUP: - case _pi::CREP_OPTIONAL_FOREIGN: - case _pi::CREP_REPEATED_FOREIGN: - case _pi::CREP_OPTIONAL_FOREIGN_PROTO2: - case _pi::CREP_REPEATED_FOREIGN_PROTO2: return GetForMessage(); - case _pi::CREP_OPTIONAL_FOREIGN_WEAK: return GetForWeakMessage(); - default: assert(false); return NULL; - } -#undef PRIMITIVE - } - - // PushOffset handler (used for StartSequence and others) /////////////////// - - // We can find a RepeatedField* or a RepeatedPtrField* at f->offset(). - static SubFlow PushOffset(void *m, Value fval) { - const FieldDef *f = GetValue(fval); - return UPB_CONTINUE_WITH(GetFieldPointer(m, f)); - } - - // Primitive Value (numeric, enum, bool) ///////////////////////////////////// - - template static AccessorVTable *Get() { - static upb_accessor_vtbl vtbl = { - NULL, // StartSubMessage handler - GetValueHandler(), - &PushOffset, // StartSequence handler - NULL, // StartRepeatedSubMessage handler - &Append, - NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - template - static Flow Append(void *_r, Value fval, Value val) { - (void)fval; - // Proto1's ProtoArray class derives from RepeatedField. - RepeatedField* r = static_cast*>(_r); - r->Add(GetValue(val)); - return UPB_CONTINUE; - } - - // String //////////////////////////////////////////////////////////////////// - - static AccessorVTable *GetForString() { - static upb_accessor_vtbl vtbl = { - NULL, // StartSubMessage handler - &SetString, - &PushOffset, // StartSequence handler - NULL, // StartRepeatedSubMessage handler - &AppendString, - NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - static Flow SetString(void *m, Value fval, Value val) { - const FieldDef* f = GetValue(fval); - string *str = static_cast(GetFieldPointer(m, f)); - GetValue(val)->AssignToString(str); - return UPB_CONTINUE; - } - - static Flow AppendString(void *_r, Value fval, Value val) { - (void)fval; - RepeatedPtrField* r = static_cast*>(_r); - GetValue(val)->AssignToString(r->Add()); - return UPB_CONTINUE; - } - - // Out-of-line string //////////////////////////////////////////////////////// - - static AccessorVTable *GetForOutOfLineString() { - static upb_accessor_vtbl vtbl = { - NULL, &SetOutOfLineString, - // This type is only used for non-repeated string fields. - NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - static Flow SetOutOfLineString(void *m, Value fval, Value val) { - const FieldDef* f = GetValue(fval); - string **str = static_cast(GetFieldPointer(m, f)); - if (*str == &::ProtocolMessage::___empty_internal_proto_string_) - *str = new string(); - GetValue(val)->AssignToString(*str); - return UPB_CONTINUE; - } - - // Cord ////////////////////////////////////////////////////////////////////// - - static AccessorVTable *GetForCord() { - static upb_accessor_vtbl vtbl = { - NULL, // StartSubMessage handler - &SetCord, - &PushOffset, // StartSequence handler - NULL, // StartRepeatedSubMessage handler - &AppendCord, - NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - static Flow SetCord(void *m, Value fval, Value val) { - const FieldDef* f = GetValue(fval); - Cord* field = static_cast(GetFieldPointer(m, f)); - AssignToCord(GetValue(val), field); - return UPB_CONTINUE; - } - - static Flow AppendCord(void *_r, Value fval, Value val) { - RepeatedField* r = static_cast*>(_r); - AssignToCord(GetValue(val), r->Add()); - return UPB_CONTINUE; - } - - // SubMessage //////////////////////////////////////////////////////////////// - - static AccessorVTable *GetForRequiredMessage() { - static upb_accessor_vtbl vtbl = { - &PushOffset, // StartSubMessage handler - NULL, // Value handler - &PushOffset, // StartSequence handler - &StartRepeatedSubMessage, - NULL, // Repeated value handler - NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - static AccessorVTable *GetForWeakMessage() { - static upb_accessor_vtbl vtbl = { - &StartWeakSubMessage, // StartSubMessage handler - NULL, // Value handler - &PushOffset, // StartSequence handler - &StartRepeatedSubMessage, - NULL, // Repeated value handler - NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - static AccessorVTable *GetForMessage() { - static upb_accessor_vtbl vtbl = { - &StartSubMessage, - NULL, // Value handler - &PushOffset, // StartSequence handler - &StartRepeatedSubMessage, - NULL, // Repeated value handler - NULL, NULL, NULL, NULL, NULL, NULL}; - return &vtbl; - } - - static SubFlow StartSubMessage(void *m, Value fval) { - const FieldDef* f = GetValue(fval); - Message **subm = static_cast(GetFieldPointer(m, f)); - if (*subm == f->prototype) *subm = (*subm)->New(); - return UPB_CONTINUE_WITH(*subm); - } - - static SubFlow StartWeakSubMessage(void *m, Value fval) { - const FieldDef* f = GetValue(fval); - Message **subm = static_cast(GetFieldPointer(m, f)); - if (*subm == NULL) { - const Message* prototype = static_cast(f->prototype); - *subm = prototype->New(); - } - return UPB_CONTINUE_WITH(*subm); - } - - class RepeatedMessageTypeHandler { - public: - typedef void Type; - // AddAllocated() calls this, but only if other objects are sitting - // around waiting for reuse, which we will not do. - static void Delete(Type* t) { - (void)t; - assert(false); - } - }; - - // Closure is a RepeatedPtrField*, but we access it through - // its base class RepeatedPtrFieldBase*. - static SubFlow StartRepeatedSubMessage(void* _r, Value fval) { - const FieldDef* f = GetValue(fval); - RepeatedPtrFieldBase *r = static_cast(_r); - void *submsg = r->AddFromCleared(); - if (!submsg) { - const Message* prototype = static_cast(f->prototype); - submsg = prototype->New(); - r->AddAllocated(submsg); - } - return UPB_CONTINUE_WITH(submsg); - } -}; - -#endif - -} // namespace proto2_bridge_{google3,opensource} - -static const Message* GetPrototypeForMessage(const Message& m) { - const Message* ret = NULL; - MessageFactory* factory = FieldAccessor::GetMessageFactory(m); - if (factory) { - // proto2 generated message or DynamicMessage. - ret = factory->GetPrototype(m.GetDescriptor()); - assert(ret); - } else { - // Proto1 message; since proto1 has no dynamic message, it must be - // from the generated factory. - ret = MessageFactory::generated_factory()->GetPrototype(m.GetDescriptor()); - assert(ret); // If NULL, then wasn't a proto1 message, can't handle it. - } - assert(ret->GetReflection() == m.GetReflection()); - return ret; -} - -static const Message* GetPrototypeForField(const Message& m, - const FieldDescriptor* f) { -#ifdef UPB_GOOGLE3 - if (f->type() == FieldDescriptor::TYPE_BYTES) { - // Proto1 weak field: the proto2 descriptor says their type is BYTES. - const _pi::Proto2Reflection* r = - dynamic_cast(m.GetReflection()); - assert(r); - const _pi::Field* field = r->GetFieldLayout(f); - assert(field->crep == _pi::CREP_OPTIONAL_FOREIGN_WEAK); - return GetPrototypeForMessage( - *static_cast(field->weak_layout()->default_instance)); - } else if (dynamic_cast(m.GetReflection())) { - // Proto1 message; since proto1 has no dynamic message, it must be from - // the generated factory. - const Message* ret = - MessageFactory::generated_factory()->GetPrototype(f->message_type()); - assert(ret); - return ret; - } -#endif - assert(f->cpp_type() == FieldDescriptor::CPPTYPE_MESSAGE); - // We assume that all submessages (and extensions) will be constructed using - // the same MessageFactory as this message. This doesn't cover the case of - // CodedInputStream::SetExtensionRegistry(). - MessageFactory* factory = FieldAccessor::GetMessageFactory(m); - assert(factory); // If neither proto1 nor proto2 we can't handle it. - const Message* ret = factory->GetPrototype(f->message_type()); - assert(ret); - return ret; -} - -namespace proto2_bridge { - -upb::FieldDef* AddFieldDef(const FieldDescriptor* f, upb::MessageDef* md) { - upb::FieldDef* upb_f = upb::FieldDef::New(&upb_f); - upb_f->set_number(f->number()); - upb_f->set_name(f->name()); - upb_f->set_label(static_cast(f->label())); - upb_f->set_type(static_cast(f->type())); - - if (!FieldAccessor::TrySet(f, md, upb_f) -#ifdef UPB_GOOGLE3 - && !proto2_bridge_google3::Proto1FieldAccessor::TrySet(f, md, upb_f) -#endif - ) { - // Unsupported reflection class. - assert(false); - } - - if (upb_f->type() == UPB_TYPE(ENUM)) { - // We set the enum default symbolically. - upb_f->set_default(f->default_value_enum()->name()); - upb_f->set_subtype_name(f->enum_type()->full_name()); - } else { - // Set field default for primitive types. Need to switch on the upb type - // rather than the proto2 type, because upb_f->type() may have been changed - // from BYTES to MESSAGE for a weak field. - switch (upb_types[upb_f->type()].inmemory_type) { - case UPB_CTYPE_INT32: - upb_f->set_default(MakeValue(f->default_value_int32())); - break; - case UPB_CTYPE_INT64: - upb_f->set_default( - MakeValue(static_cast(f->default_value_int64()))); - break; - case UPB_CTYPE_UINT32: - upb_f->set_default(MakeValue(f->default_value_uint32())); - break; - case UPB_CTYPE_UINT64: - upb_f->set_default( - MakeValue(static_cast(f->default_value_uint64()))); - break; - case UPB_CTYPE_DOUBLE: - upb_f->set_default(MakeValue(f->default_value_double())); - break; - case UPB_CTYPE_FLOAT: - upb_f->set_default(MakeValue(f->default_value_float())); - break; - case UPB_CTYPE_BOOL: - upb_f->set_default(MakeValue(f->default_value_bool())); - break; - case UPB_CTYPE_BYTEREGION: - upb_f->set_default(f->default_value_string()); - break; - } - } - return md->AddField(upb_f, &upb_f) ? upb_f : NULL; -} - -upb::MessageDef *NewEmptyMessageDef(const Message& m, void *owner) { - upb::MessageDef *md = upb::MessageDef::New(owner); - md->set_full_name(m.GetDescriptor()->full_name()); - md->prototype = GetPrototypeForMessage(m); - return md; -} - -upb::EnumDef* NewEnumDef(const EnumDescriptor* desc, void *owner) { - upb::EnumDef* e = upb::EnumDef::New(owner); - e->set_full_name(desc->full_name()); - for (int i = 0; i < desc->value_count(); i++) { - const EnumValueDescriptor* val = desc->value(i); - bool success = e->AddValue(val->name(), val->number()); - assert(success); - (void)success; - } - return e; -} - -void AddAllFields(upb::MessageDef* md) { - const Descriptor* d = - static_cast(md->prototype)->GetDescriptor(); - for (int i = 0; i < d->field_count(); i++) { -#ifdef UPB_GOOGLE3 - // Skip lazy fields for now since we can't properly handle them. - if (d->field(i)->options().lazy()) continue; -#endif - // Extensions not supported yet. - if (d->field(i)->is_extension()) continue; - AddFieldDef(d->field(i), md); - } -} - -upb::MessageDef *NewFullMessageDef(const Message& m, void *owner) { - upb::MessageDef* md = NewEmptyMessageDef(m, owner); - AddAllFields(md); - // TODO(haberman): add unknown field handler and extensions. - return md; -} - -typedef std::map SymbolMap; - -static upb::MessageDef* NewFinalMessageDefHelper(const Message& m, void *owner, - SymbolMap* symbols) { - upb::MessageDef* md = NewFullMessageDef(m, owner); - // Must do this before processing submessages to prevent infinite recursion. - (*symbols)[std::string(md->full_name())] = md->AsDef(); - - for (upb::MessageDef::Iterator i(md); !i.Done(); i.Next()) { - upb::FieldDef* f = i.field(); - if (!f->HasSubDef()) continue; - SymbolMap::iterator iter = symbols->find(f->subtype_name()); - upb::Def* subdef; - if (iter != symbols->end()) { - subdef = iter->second; - } else { - const FieldDescriptor* proto2_f = - m.GetDescriptor()->FindFieldByNumber(f->number()); - if (f->type() == UPB_TYPE(ENUM)) { - subdef = NewEnumDef(proto2_f->enum_type(), owner)->AsDef(); - (*symbols)[std::string(subdef->full_name())] = subdef; - } else { - assert(f->IsSubmessage()); - const Message* prototype = GetPrototypeForField(m, proto2_f); - subdef = NewFinalMessageDefHelper(*prototype, owner, symbols)->AsDef(); - } - } - f->set_subdef(subdef); - } - return md; -} - -const upb::MessageDef* NewFinalMessageDef(const Message& m, void *owner) { - SymbolMap symbols; - upb::MessageDef* ret = NewFinalMessageDefHelper(m, owner, &symbols); - - // Finalize defs. - std::vector defs; - SymbolMap::iterator iter; - for (iter = symbols.begin(); iter != symbols.end(); ++iter) { - defs.push_back(iter->second); - } - Status status; - bool success = Def::Finalize(defs, &status); - assert(success); - (void)success; - - // Unref all defs except the top-level one that we are returning. - for (int i = 0; i < static_cast(defs.size()); i++) { - if (defs[i] != ret->AsDef()) defs[i]->Unref(owner); - } - - return ret; -} - -} // namespace proto2_bridge -} // namespace upb -- cgit v1.2.3