diff options
Diffstat (limited to 'bindings/cpp/upb/proto2_bridge.cc')
-rw-r--r-- | bindings/cpp/upb/proto2_bridge.cc | 892 |
1 files changed, 892 insertions, 0 deletions
diff --git a/bindings/cpp/upb/proto2_bridge.cc b/bindings/cpp/upb/proto2_bridge.cc new file mode 100644 index 0000000..6119295 --- /dev/null +++ b/bindings/cpp/upb/proto2_bridge.cc @@ -0,0 +1,892 @@ +// +// upb - a minimalist implementation of protocol buffers. +// +// Copyright (c) 2011-2012 Google Inc. See LICENSE for details. +// Author: Josh Haberman <jhaberman@gmail.com> + +#include <string> +#include <typeinfo> +#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<char*>(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<const Message*>(md->prototype); + const Reflection* base_r = prototype->GetReflection(); + const GeneratedMessageReflection* r = + dynamic_cast<const GeneratedMessageReflection*>(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<const GeneratedMessageReflection*>(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<int32_t>(); + case FieldDescriptor::CPPTYPE_INT64: return Get<int64_t>(); + case FieldDescriptor::CPPTYPE_UINT32: return Get<uint32_t>(); + case FieldDescriptor::CPPTYPE_UINT64: return Get<uint64_t>(); + case FieldDescriptor::CPPTYPE_DOUBLE: return Get<double>(); + case FieldDescriptor::CPPTYPE_FLOAT: return Get<float>(); + case FieldDescriptor::CPPTYPE_BOOL: return Get<bool>(); + case FieldDescriptor::CPPTYPE_STRING: + switch (ctype) { +#ifdef UPB_GOOGLE3 + case FieldOptions::STRING: + return GetForString<string>(); + case FieldOptions::CORD: + return GetForCord(); + case FieldOptions::STRING_PIECE: + return GetForStringPiece(); +#else + case UPB_CTYPE_STRING: + return GetForString<std::string>(); +#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<const FieldDef*>(fval); + return UPB_CONTINUE_WITH(GetFieldPointer(m, f)); + } + + // Primitive Value (numeric, enum, bool) ///////////////////////////////////// + + template <typename T> static AccessorVTable *Get() { + static upb_accessor_vtbl vtbl = { + NULL, // StartSubMessage handler + GetValueHandler<T>(), + &PushOffset, // StartSequence handler + NULL, // StartRepeatedSubMessage handler + &Append<T>, + NULL, NULL, NULL, NULL, NULL, NULL}; + return &vtbl; + } + + template <typename T> + static Flow Append(void *_r, Value fval, Value val) { + (void)fval; + RepeatedField<T>* r = static_cast<RepeatedField<T>*>(_r); + r->Add(GetValue<T>(val)); + return UPB_CONTINUE; + } + + // String //////////////////////////////////////////////////////////////////// + + template <typename T> static AccessorVTable *GetForString() { + static upb_accessor_vtbl vtbl = { + NULL, // StartSubMessage handler + &SetString<T>, + &PushOffset, // StartSequence handler + NULL, // StartRepeatedSubMessage handler + &AppendString<T>, + NULL, NULL, NULL, NULL, NULL, NULL}; + return &vtbl; + } + + // This needs to be templated because google3 string is not std::string. + template <typename T> static Flow SetString(void *m, Value fval, Value val) { + const FieldDef* f = GetValue<const FieldDef*>(fval); + T **str = static_cast<T**>(GetFieldPointer(m, f)); + // If it points to the default instance, we must create a new instance. + if (*str == f->prototype) *str = new T(); + GetValue<ByteRegion*>(val)->AssignToString(*str); + return UPB_CONTINUE; + } + + template <typename T> + static Flow AppendString(void *_r, Value fval, Value val) { + (void)fval; + RepeatedPtrField<T>* r = static_cast<RepeatedPtrField<T>*>(_r); + GetValue<ByteRegion*>(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<const FieldDef*>(fval); + void **subm = static_cast<void**>(GetFieldPointer(m, f)); + if (*subm == NULL || *subm == f->prototype) { + const Message* prototype = static_cast<const Message*>(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<SubMessageType>*, but we access it through + // its base class RepeatedPtrFieldBase*. + static SubFlow StartRepeatedSubMessage(void* _r, Value fval) { + const FieldDef* f = GetValue<const FieldDef*>(fval); + RepeatedPtrFieldBase *r = static_cast<RepeatedPtrFieldBase*>(_r); + void *submsg = r->AddFromCleared<RepeatedMessageTypeHandler>(); + if (!submsg) { + const Message* prototype = static_cast<const Message*>(f->prototype); + submsg = prototype->New(); + r->AddAllocated<RepeatedMessageTypeHandler>(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<const FieldDef*>(fval); + Cord* field = static_cast<Cord*>(GetFieldPointer(m, f)); + AssignToCord(GetValue<ByteRegion*>(val), field); + return UPB_CONTINUE; + } + + static Flow AppendCord(void *_r, Value fval, Value val) { + RepeatedField<Cord>* r = static_cast<RepeatedField<Cord>*>(_r); + AssignToCord(GetValue<ByteRegion*>(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<const FieldDef*>(fval); + StringPieceField* field = + static_cast<StringPieceField*>(GetFieldPointer(m, f)); + AssignToStringPieceField(GetValue<ByteRegion*>(val), field); + return UPB_CONTINUE; + } + + static Flow AppendStringPiece(void* _r, Value fval, Value val) { + RepeatedPtrField<StringPieceField>* r = + static_cast<RepeatedPtrField<StringPieceField>*>(_r); + AssignToStringPieceField(GetValue<ByteRegion*>(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<const Message*>(md->prototype); + const proto2::Reflection* base_r = m->GetReflection(); + const _pi::Proto2Reflection* r = + dynamic_cast<const _pi::Proto2Reflection*>(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<type_name>(); + + 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<const FieldDef*>(fval); + return UPB_CONTINUE_WITH(GetFieldPointer(m, f)); + } + + // Primitive Value (numeric, enum, bool) ///////////////////////////////////// + + template <typename T> static AccessorVTable *Get() { + static upb_accessor_vtbl vtbl = { + NULL, // StartSubMessage handler + GetValueHandler<T>(), + &PushOffset, // StartSequence handler + NULL, // StartRepeatedSubMessage handler + &Append<T>, + NULL, NULL, NULL, NULL, NULL, NULL}; + return &vtbl; + } + + template <typename T> + static Flow Append(void *_r, Value fval, Value val) { + (void)fval; + // Proto1's ProtoArray class derives from RepeatedField. + RepeatedField<T>* r = static_cast<RepeatedField<T>*>(_r); + r->Add(GetValue<T>(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<const FieldDef*>(fval); + string *str = static_cast<string*>(GetFieldPointer(m, f)); + GetValue<ByteRegion*>(val)->AssignToString(str); + return UPB_CONTINUE; + } + + static Flow AppendString(void *_r, Value fval, Value val) { + (void)fval; + RepeatedPtrField<string>* r = static_cast<RepeatedPtrField<string>*>(_r); + GetValue<ByteRegion*>(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<const FieldDef*>(fval); + string **str = static_cast<string**>(GetFieldPointer(m, f)); + if (*str == &::ProtocolMessage::___empty_internal_proto_string_) + *str = new string(); + GetValue<ByteRegion*>(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<const FieldDef*>(fval); + Cord* field = static_cast<Cord*>(GetFieldPointer(m, f)); + AssignToCord(GetValue<ByteRegion*>(val), field); + return UPB_CONTINUE; + } + + static Flow AppendCord(void *_r, Value fval, Value val) { + RepeatedField<Cord>* r = static_cast<RepeatedField<Cord>*>(_r); + AssignToCord(GetValue<ByteRegion*>(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<const FieldDef*>(fval); + Message **subm = static_cast<Message**>(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<const FieldDef*>(fval); + Message **subm = static_cast<Message**>(GetFieldPointer(m, f)); + if (*subm == NULL) { + const Message* prototype = static_cast<const Message*>(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<SubMessageType>*, but we access it through + // its base class RepeatedPtrFieldBase*. + static SubFlow StartRepeatedSubMessage(void* _r, Value fval) { + const FieldDef* f = GetValue<const FieldDef*>(fval); + RepeatedPtrFieldBase *r = static_cast<RepeatedPtrFieldBase*>(_r); + void *submsg = r->AddFromCleared<RepeatedMessageTypeHandler>(); + if (!submsg) { + const Message* prototype = static_cast<const Message*>(f->prototype); + submsg = prototype->New(); + r->AddAllocated<RepeatedMessageTypeHandler>(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<const _pi::Proto2Reflection*>(m.GetReflection()); + assert(r); + const _pi::Field* field = r->GetFieldLayout(f); + assert(field->crep == _pi::CREP_OPTIONAL_FOREIGN_WEAK); + return GetPrototypeForMessage( + *static_cast<const Message*>(field->weak_layout()->default_instance)); + } else if (dynamic_cast<const _pi::Proto2Reflection*>(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<upb::Label>(f->label())); + upb_f->set_type(static_cast<upb::FieldType>(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<int64_t>(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<uint64_t>(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<const Message*>(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<std::string, upb::Def*> 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<upb::Def*> 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<int>(defs.size()); i++) { + if (defs[i] != ret->AsDef()) defs[i]->Unref(owner); + } + + return ret; +} + +} // namespace proto2_bridge +} // namespace upb |