From 2d10fa33071d52d7a35ce3b13bc459cd16a0aa33 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Thu, 26 Jun 2014 20:24:32 -0700 Subject: Sync from internal Google development. --- upb/bindings/googlepb/bridge.cc | 114 ++++++++-------- upb/bindings/googlepb/bridge.h | 65 ++++++++- upb/bindings/googlepb/proto1.cc | 27 ++-- upb/bindings/googlepb/proto1.h | 51 ------- upb/bindings/googlepb/proto1.int.h | 45 ++++++ upb/bindings/googlepb/proto2.cc | 271 +++++++++++++++++++++++++++++++++++-- upb/bindings/googlepb/proto2.h | 61 --------- upb/bindings/googlepb/proto2.int.h | 59 ++++++++ 8 files changed, 500 insertions(+), 193 deletions(-) delete mode 100644 upb/bindings/googlepb/proto1.h create mode 100644 upb/bindings/googlepb/proto1.int.h delete mode 100644 upb/bindings/googlepb/proto2.h create mode 100644 upb/bindings/googlepb/proto2.int.h (limited to 'upb/bindings/googlepb') diff --git a/upb/bindings/googlepb/bridge.cc b/upb/bindings/googlepb/bridge.cc index c8e3474..a666ff6 100644 --- a/upb/bindings/googlepb/bridge.cc +++ b/upb/bindings/googlepb/bridge.cc @@ -16,8 +16,8 @@ #include #include #include "upb/def.h" -#include "upb/bindings/googlepb/proto1.h" -#include "upb/bindings/googlepb/proto2.h" +#include "upb/bindings/googlepb/proto1.int.h" +#include "upb/bindings/googlepb/proto2.int.h" #include "upb/handlers.h" #define ASSERT_STATUS(status) do { \ @@ -39,31 +39,24 @@ namespace goog = ::proto2; namespace goog = ::google::protobuf; #endif -namespace { - -const goog::Message* GetPrototype(const goog::Message& m, - const goog::FieldDescriptor* f) { - const goog::Message* ret = NULL; -#ifdef UPB_GOOGLE3 - ret = upb::google::GetProto1WeakPrototype(m, f); - if (ret) return ret; -#endif +namespace upb { +namespace googlepb { - if (f->cpp_type() == goog::FieldDescriptor::CPPTYPE_MESSAGE) { - ret = upb::google::GetFieldPrototype(m, f); +const goog::Message* TryGetFieldPrototype(const goog::Message& m, + const goog::FieldDescriptor* f) { + const goog::Message* ret = upb::googlepb::GetProto2FieldPrototype(m, f); #ifdef UPB_GOOGLE3 - if (!ret) ret = upb::google::GetProto1FieldPrototype(m, f); + if (!ret) ret = upb::googlepb::GetProto1FieldPrototype(m, f); #endif - assert(ret); - } return ret; } -} // namespace - -namespace upb { -namespace googlepb { - +const goog::Message* GetFieldPrototype(const goog::Message& m, + const goog::FieldDescriptor* f) { + const goog::Message* ret = TryGetFieldPrototype(m, f); + assert(ret); + return ret; +} /* DefBuilder ****************************************************************/ @@ -117,20 +110,11 @@ const MessageDef* DefBuilder::GetMaybeUnfrozenMessageDef( reffed_ptr DefBuilder::NewFieldDef(const goog::FieldDescriptor* f, const goog::Message* m) { - const goog::Message* subm = NULL; - const goog::Message* weak_prototype = NULL; - - if (m) { -#ifdef UPB_GOOGLE3 - weak_prototype = upb::google::GetProto1WeakPrototype(*m, f); -#endif - subm = GetPrototype(*m, f); - } - reffed_ptr upb_f(FieldDef::New()); Status status; upb_f->set_number(f->number(), &status); upb_f->set_label(FieldDef::ConvertLabel(f->label())); + upb_f->set_descriptor_type(FieldDef::ConvertDescriptorType(f->type())); #ifdef UPB_GOOGLE3 upb_f->set_lazy(f->options().lazy()); #endif @@ -142,11 +126,19 @@ reffed_ptr DefBuilder::NewFieldDef(const goog::FieldDescriptor* f, upb_f->set_name(f->name(), &status); } - // For weak fields, weak_prototype will be non-NULL even though the proto2 - // descriptor does not indicate a submessage field. - upb_f->set_descriptor_type(weak_prototype - ? UPB_DESCRIPTOR_TYPE_MESSAGE - : FieldDef::ConvertDescriptorType(f->type())); + const goog::Message* subm = NULL; + + if (m) { + subm = TryGetFieldPrototype(*m, f); + + if (upb_f->type() == UPB_TYPE_MESSAGE) { + assert(subm); + } else if (subm) { + // Weak field: subm will be weak prototype even though the proto2 + // descriptor does not indicate a submessage field. + upb_f->set_descriptor_type(UPB_DESCRIPTOR_TYPE_MESSAGE); + } + } switch (upb_f->type()) { case UPB_TYPE_INT32: @@ -213,6 +205,35 @@ const MessageDef* DefBuilder::GetMessageDefExpandWeak( } +/* WriteHandlers *************************************************************/ + +// static +bool WriteHandlers::AddFieldHandler(const goog::Message& m, + const goog::FieldDescriptor* f, + upb::Handlers* h) { + const FieldDef* upb_f = h->message_def()->FindFieldByNumber(f->number()); + if (!upb_f) return false; + if (upb::googlepb::TrySetWriteHandlers(f, m, upb_f, h)) return true; +#ifdef UPB_GOOGLE3 + if (upb::googlepb::TrySetProto1WriteHandlers(f, m, upb_f, h)) return true; +#endif + + // Unsupported reflection class. + // + // Should we fall back to using the public Reflection interface in this + // case? It's unclear whether it's supported behavior for users to + // create their own Reflection classes. + return false; +} + +// static +upb::reffed_ptr WriteHandlers::New( + const goog::Message& m) { + CodeCache cache; + return upb::reffed_ptr(cache.GetWriteHandlers(m)); +} + + /* CodeCache *****************************************************************/ const Handlers* CodeCache::GetMaybeUnfrozenWriteHandlers( @@ -234,21 +255,11 @@ const Handlers* CodeCache::GetMaybeUnfrozenWriteHandlers( } assert(proto2_f); - if (!upb::google::TrySetWriteHandlers(proto2_f, m, upb_f, h) -#ifdef UPB_GOOGLE3 - && !upb::google::TrySetProto1WriteHandlers(proto2_f, m, upb_f, h) -#endif - ) { - // Unsupported reflection class. - // - // Should we fall back to using the public Reflection interface in this - // case? It's unclear whether it's supported behavior for users to - // create their own Reflection classes. - assert(false); - } + bool ok = WriteHandlers::AddFieldHandler(m, proto2_f, h); + UPB_ASSERT_VAR(ok, ok); if (upb_f->type() == UPB_TYPE_MESSAGE) { - const goog::Message* prototype = GetPrototype(m, proto2_f); + const goog::Message* prototype = GetFieldPrototype(m, proto2_f); assert(prototype); const upb::Handlers* sub_handlers = GetMaybeUnfrozenWriteHandlers(upb_f->message_subdef(), *prototype); @@ -269,10 +280,5 @@ const Handlers* CodeCache::GetWriteHandlers(const goog::Message& m) { return ret; } -upb::reffed_ptr NewWriteHandlers(const goog::Message& m) { - CodeCache cache; - return upb::reffed_ptr(cache.GetWriteHandlers(m)); -} - } // namespace googlepb } // namespace upb diff --git a/upb/bindings/googlepb/bridge.h b/upb/bindings/googlepb/bridge.h index 9eed51b..9878247 100644 --- a/upb/bindings/googlepb/bridge.h +++ b/upb/bindings/googlepb/bridge.h @@ -63,13 +63,6 @@ namespace upb { namespace googlepb { -// Returns a upb::Handlers object that can be used to populate a proto2::Message -// object of the same type as "m." For more control over handler caching and -// reuse, instantiate a CodeCache object below. -upb::reffed_ptr NewWriteHandlers(const proto2::Message& m); -upb::reffed_ptr NewWriteHandlers( - const ::google::protobuf::Message& m); - // Builds upb::Defs from proto2::Descriptors, and caches all built Defs for // reuse. CodeCache (below) uses this internally; there is no need to use this // class directly unless you only want Defs without corresponding Handlers. @@ -159,6 +152,41 @@ class DefBuilder { std::vector to_freeze_; }; +// Handlers to populate a proto2::Message with incoming data. +class WriteHandlers { + public: + // Returns a upb::Handlers object that can be used to populate a + // proto2::Message object of the same type as "m." For more control over + // handler caching and reuse, instantiate a CodeCache object below. + static upb::reffed_ptr New(const proto2::Message& m); + static upb::reffed_ptr New( + const ::google::protobuf::Message& m); + + // TODO(haberman): add an interface that takes a list of field paths, + // something like: + // + // // Returns a Handlers instance that will populate the given field paths + // // only, dropping data for all other field paths on the floor. + // static upb::reffed_ptr New( + // const proto2::Message& m, + // const std::vector& paths); + + // A lower-level interface with field granularity. + // + // Adds a handler to the given upb::Handlers for parsing the given field. If + // you only want to write certain fields into the proto2 message at parse + // time, call these methods ONLY for the fields you want to parse. + // + // The given field can be either a regular field or an extension, as long as + // its containing_type() matches this message. + static bool AddFieldHandler(const proto2::Message& m, + const proto2::FieldDescriptor* f, + upb::Handlers* h); + static bool AddFieldHandler(const ::google::protobuf::Message& m, + const ::google::protobuf::FieldDescriptor* f, + upb::Handlers* h); +}; + // Builds and caches upb::Handlers for populating proto2 generated classes. // // This class is NOT thread-safe. @@ -199,6 +227,29 @@ class CodeCache { std::vector to_freeze_; }; +// Functions for getting prototypes; these are only necessary if you are +// building handlers manually, field by field. + +// Given a message and a field descriptor for that message, returns a prototype +// for the submessage. Requires that this is a submessage field or a weak +// field. +const proto2::Message* GetFieldPrototype(const proto2::Message& m, + const proto2::FieldDescriptor* f); +const ::google::protobuf::Message* GetFieldPrototype( + const ::google::protobuf::Message& m, + const ::google::protobuf::FieldDescriptor* f); + +// Given a message and a field descriptor for that message, returns a prototype +// for the submessage, or NULL if this is not a submessage field or a weak +// field. If this returns non-NULL even though the descriptor's type is not a +// submessage, then this is a weak field. If you don't know what a weak field +// is, you are probably not using one. +const proto2::Message* TryGetFieldPrototype(const proto2::Message& m, + const proto2::FieldDescriptor* f); +const ::google::protobuf::Message* TryGetFieldPrototype( + const ::google::protobuf::Message& m, + const ::google::protobuf::FieldDescriptor* f); + } // namespace googlepb } // namespace upb diff --git a/upb/bindings/googlepb/proto1.cc b/upb/bindings/googlepb/proto1.cc index c317cdf..0b46fed 100644 --- a/upb/bindings/googlepb/proto1.cc +++ b/upb/bindings/googlepb/proto1.cc @@ -16,13 +16,20 @@ // dynamic_cast<> in this file: // https://groups.google.com/a/google.com/d/msg/c-style/7Zp_XCX0e7s/I6dpzno4l-MJ -#include "upb/bindings/googlepb/proto1.h" +#include "upb/bindings/googlepb/proto1.int.h" #include +// TEMPORARY measure until we update the friend declarations in proto1. +// Can't do in a single CL because of components. +#define private public +#define protected public #include "net/proto2/public/repeated_field.h" #include "net/proto/internal_layout.h" #include "net/proto/proto2_reflection.h" +#undef private +#undef protected + #include "upb/def.h" #include "upb/handlers.h" #include "upb/shim/shim.h" @@ -36,7 +43,7 @@ template static T* GetPointer(void* message, size_t offset) { } namespace upb { -namespace google { +namespace googlepb { class P2R_Handlers { public: @@ -466,18 +473,18 @@ class P2R_Handlers { bool TrySetProto1WriteHandlers(const proto2::FieldDescriptor* proto2_f, const proto2::Message& m, const upb::FieldDef* upb_f, upb::Handlers* h) { - return P2R_Handlers::TrySet(proto2_f, m, upb_f, h); -} - -const proto2::Message* GetProto1WeakPrototype( - const proto2::Message& m, const proto2::FieldDescriptor* f) { - return P2R_Handlers::GetWeakPrototype(m, f); + return googlepb::P2R_Handlers::TrySet(proto2_f, m, upb_f, h); } const proto2::Message* GetProto1FieldPrototype( const proto2::Message& m, const proto2::FieldDescriptor* f) { - return P2R_Handlers::GetFieldPrototype(m, f); + const proto2::Message *weak = googlepb::P2R_Handlers::GetWeakPrototype(m, f); + if (weak) return weak; + if (f->cpp_type() != proto2::FieldDescriptor::CPPTYPE_MESSAGE) { + return NULL; + } + return googlepb::P2R_Handlers::GetFieldPrototype(m, f); } -} // namespace google +} // namespace googlepb } // namespace upb diff --git a/upb/bindings/googlepb/proto1.h b/upb/bindings/googlepb/proto1.h deleted file mode 100644 index eb550ac..0000000 --- a/upb/bindings/googlepb/proto1.h +++ /dev/null @@ -1,51 +0,0 @@ -// -// upb - a minimalist implementation of protocol buffers. -// -// Copyright (c) 2011-2012 Google Inc. See LICENSE for details. -// Author: Josh Haberman -// -// Support for registering field handlers that can write into a legacy proto1 -// message. This functionality is only needed inside Google. -// -// This is a low-level interface; the high-level interface in google.h is -// more user-friendly. - -#ifndef UPB_GOOGLE_PROTO1_H_ -#define UPB_GOOGLE_PROTO1_H_ - -namespace proto2 { -class FieldDescriptor; -class Message; -} - -namespace upb { -class FieldDef; -class Handlers; -} - -namespace upb { -namespace google { - -// Sets field handlers in the given Handlers object for writing to a single -// field (as described by "proto2_f" and "upb_f") into a message constructed -// by the same factory as "prototype." Returns true if this was successful -// (this will fail if "prototype" is not a proto1 message, or if we can't -// handle it for some reason). -bool TrySetProto1WriteHandlers(const proto2::FieldDescriptor* proto2_f, - const proto2::Message& prototype, - const upb::FieldDef* upb_f, upb::Handlers* h); - -// Returns a prototype for the given field in "m", if it is weak. The returned -// message could be the linked-in message type or OpaqueMessage, if the weak -// message is *not* linked in. Otherwise returns NULL. -const proto2::Message* GetProto1WeakPrototype(const proto2::Message& m, - const proto2::FieldDescriptor* f); - -// Returns a prototype for the given non-weak field in "m". -const proto2::Message* GetProto1FieldPrototype( - const proto2::Message& m, const proto2::FieldDescriptor* f); - -} // namespace google -} // namespace upb - -#endif // UPB_GOOGLE_PROTO1_H_ diff --git a/upb/bindings/googlepb/proto1.int.h b/upb/bindings/googlepb/proto1.int.h new file mode 100644 index 0000000..64ebb2f --- /dev/null +++ b/upb/bindings/googlepb/proto1.int.h @@ -0,0 +1,45 @@ +// +// upb - a minimalist implementation of protocol buffers. +// +// Copyright (c) 2011-2012 Google Inc. See LICENSE for details. +// Author: Josh Haberman +// +// Support for registering field handlers that can write into a legacy proto1 +// message. This functionality is only needed inside Google. +// +// This is an internal-only interface. + +#ifndef UPB_GOOGLE_PROTO1_H_ +#define UPB_GOOGLE_PROTO1_H_ + +namespace proto2 { +class FieldDescriptor; +class Message; +} + +namespace upb { +class FieldDef; +class Handlers; +} + +namespace upb { +namespace googlepb { + +// Sets field handlers in the given Handlers object for writing to a single +// field (as described by "proto2_f" and "upb_f") into a message constructed +// by the same factory as "prototype." Returns true if this was successful +// (this will fail if "prototype" is not a proto1 message, or if we can't +// handle it for some reason). +bool TrySetProto1WriteHandlers(const proto2::FieldDescriptor* proto2_f, + const proto2::Message& prototype, + const upb::FieldDef* upb_f, upb::Handlers* h); + +// Returns a prototype for the given this (possibly-weak) field. Returns NULL +// if this is not a submessage field of any kind (weak or no). +const proto2::Message* GetProto1FieldPrototype( + const proto2::Message& m, const proto2::FieldDescriptor* f); + +} // namespace googlepb +} // namespace upb + +#endif // UPB_GOOGLE_PROTO1_H_ diff --git a/upb/bindings/googlepb/proto2.cc b/upb/bindings/googlepb/proto2.cc index 04e504b..224e2b9 100644 --- a/upb/bindings/googlepb/proto2.cc +++ b/upb/bindings/googlepb/proto2.cc @@ -13,10 +13,12 @@ // and protobuf opensource both in a single binary without the two conflicting. // However we must be careful not to violate the ODR. -#include "upb/bindings/googlepb/proto2.h" +#include "upb/bindings/googlepb/proto2.int.h" + +#include #include "upb/def.h" -#include "upb/bindings/googlepb/proto1.h" +#include "upb/bindings/googlepb/proto1.int.h" #include "upb/handlers.h" #include "upb/shim/shim.h" #include "upb/sink.h" @@ -237,10 +239,26 @@ case goog::FieldDescriptor::cpptype: \ return (r->has_bits_offset_ * 8) + f->index(); } +#ifdef GOOGLE_PROTOBUF_HAS_ONEOF + static size_t GetOneofDiscriminantOffset( + const goog::FieldDescriptor* f, + const goog::internal::GeneratedMessageReflection* r) { + assert(f->containing_oneof()); + return r->oneof_case_offset_ + f->containing_oneof()->index(); + } +#endif + static uint16_t GetOffset( const goog::FieldDescriptor* f, const goog::internal::GeneratedMessageReflection* r) { - return r->offsets_[f->index()]; + int index = f->index(); +#ifdef GOOGLE_PROTOBUF_HAS_ONEOF + if (f->containing_oneof()) { + index = + f->containing_type()->field_count() + f->containing_oneof()->index(); + } +#endif + return r->offsets_[index]; } class FieldOffset { @@ -274,6 +292,154 @@ case goog::FieldDescriptor::cpptype: \ int8_t mask_; }; +#ifdef GOOGLE_PROTOBUF_HAS_ONEOF + class OneofFieldData { + public: + OneofFieldData(const goog::FieldDescriptor* f, + const goog::internal::GeneratedMessageReflection* r) + : field_number_offset_(GetOneofDiscriminantOffset(f, r)), + field_number_(f->number()) { + const goog::OneofDescriptor* oneof = f->containing_oneof(); + + // Determine the type of each discriminant value, so we know what kind of + // value to delete if we are changing the type. + // + // For example, we may find that the oneof has three possible values: an + // int32, a message, and a string. For the int32 there is nothing to + // delete, but the message and the string need to be deleted when we + // switch to another oneof type, to avoid leaking it. + // + // TODO(haberman): share this map of types between all fields in the + // oneof. Right now we duplicate it for each one, which is wasteful. + for (int i = 0; i < oneof->field_count(); i++) { + const goog::FieldDescriptor* oneof_f = oneof->field(i); + OneofType& type = types_[oneof_f->number()]; + + switch (oneof_f->cpp_type()) { + case goog::FieldDescriptor::CPPTYPE_STRING: + type = GetTypeForString(oneof_f); + break; + case goog::FieldDescriptor::CPPTYPE_MESSAGE: +#ifdef UPB_GOOGLE3 + if (oneof_f->options().lazy()) { + type = ONEOF_TYPE_LAZYFIELD; + break; + } +#endif + type = ONEOF_TYPE_MESSAGE; + break; + + default: + type = ONEOF_TYPE_NONE; + break; + } + } + + // "0" indicates that the field is not set. + types_[0] = ONEOF_TYPE_NONE; + } + + int32_t* GetFieldPointer(goog::Message* message) const { + return GetPointer(message, field_number_offset_); + } + + // Returns whether this is different than the previous value of the + // field_number; this implies that the current value was freed (if + // necessary) and the caller should allocate a new instance. + bool SetOneofHas(goog::Message* m, const FieldOffset* ofs) const { + int32_t *field_number = GetFieldPointer(m); + if (*field_number == field_number_) { + return false; + } else { + switch (types_.at(*field_number)) { + case ONEOF_TYPE_NONE: + break; + case ONEOF_TYPE_STRING: + delete *ofs->GetFieldPointer(m); + break; + case ONEOF_TYPE_MESSAGE: + delete *ofs->GetFieldPointer(m); + break; +#ifdef UPB_GOOGLE3 + case ONEOF_TYPE_GLOBALSTRING: + delete *ofs->GetFieldPointer(m); + break; + case ONEOF_TYPE_CORD: + delete *ofs->GetFieldPointer(m); + break; + case ONEOF_TYPE_STRINGPIECE: + delete *ofs->GetFieldPointer(m); + break; + case ONEOF_TYPE_LAZYFIELD: + delete *ofs->GetFieldPointer(m); + break; +#endif + } + *field_number = field_number_; + return true; + } + } + + private: + enum OneofType { + ONEOF_TYPE_NONE, + ONEOF_TYPE_STRING, + ONEOF_TYPE_MESSAGE, +#ifdef UPB_GOOGLE3 + ONEOF_TYPE_GLOBALSTRING, + ONEOF_TYPE_CORD, + ONEOF_TYPE_STRINGPIECE, + ONEOF_TYPE_LAZYFIELD, +#endif + }; + + OneofType GetTypeForString(const goog::FieldDescriptor* f) { + switch (f->options().ctype()) { + case goog::FieldOptions::STRING: +#ifdef UPB_GOOGLE3 + return ONEOF_TYPE_GLOBALSTRING; +#else + return ONEOF_TYPE_STRING; +#endif + +#ifdef UPB_GOOGLE3 + case goog::FieldOptions::CORD: + return ONEOF_TYPE_CORD; + case goog::FieldOptions::STRING_PIECE: + return ONEOF_TYPE_STRINGPIECE; +#endif + default: + assert(false); + return ONEOF_TYPE_NONE; + } + } + + // Offset of the uint32 that specifies which field is set. + size_t field_number_offset_; + + // Field number for this field. + int32_t field_number_; + + // The types of the oneof fields, indexed by field_number_. + std::map types_; + }; + + class OneofFieldHandlerData : public FieldOffset { + public: + OneofFieldHandlerData(const goog::FieldDescriptor* f, + const goog::internal::GeneratedMessageReflection* r) + : FieldOffset(f, r), + oneof_data_(f, r) {} + + bool SetOneofHas(goog::Message* message) const { + return oneof_data_.SetOneofHas(message, this); + } + + public: + OneofFieldData oneof_data_; + }; +#endif // GOOGLE_PROTOBUF_HAS_ONEOF + class ExtensionFieldData { public: ExtensionFieldData( @@ -352,7 +518,16 @@ case goog::FieldDescriptor::cpptype: \ CHKRET(h->SetValueHandler( f, UpbBindT(SetPrimitiveExtension, data.release()))); } - } else { + } +#ifdef GOOGLE_PROTOBUF_HAS_ONEOF + else if (proto2_f->containing_oneof()) { + assert(!proto2_f->is_repeated()); + CHKRET(h->SetValueHandler( + f, UpbBindT(SetOneofPrimitive, + new OneofFieldHandlerData(proto2_f, r)))); + } +#endif + else { if (f->IsSequence()) { SetStartRepeatedField(proto2_f, r, f, h); CHKRET(h->SetValueHandler(f, UpbMakeHandlerT(AppendPrimitive))); @@ -383,6 +558,17 @@ case goog::FieldDescriptor::cpptype: \ val, set); } +#ifdef GOOGLE_PROTOBUF_HAS_ONEOF + template + static void SetOneofPrimitive(goog::Message* m, + const OneofFieldHandlerData* data, T val) { + data->SetOneofHas(m); + const FieldOffset* ofs = data; + T* ptr = ofs->GetFieldPointer(m); + *ptr = val; + } +#endif + // Enum ////////////////////////////////////////////////////////////////////// class EnumHandlerData : public FieldOffset { @@ -506,7 +692,15 @@ case goog::FieldDescriptor::cpptype: \ upb::Handlers* h) { assert(!proto2_f->is_extension()); CHKRET(h->SetStringHandler(f, UpbMakeHandlerT(&OnStringBuf))); - if (f->IsSequence()) { +#ifdef GOOGLE_PROTOBUF_HAS_ONEOF + if (proto2_f->containing_oneof()) { + assert(!f->IsSequence()); + CHKRET(h->SetStartStringHandler( + f, UpbBindT(&StartOneofString, + new OneofFieldHandlerData(proto2_f, r)))); + } else +#endif + if (f->IsSequence()) { SetStartRepeatedPtrField(proto2_f, r, f, h); CHKRET( h->SetStartStringHandler(f, UpbMakeHandlerT(StartRepeatedString))); @@ -545,6 +739,22 @@ case goog::FieldDescriptor::cpptype: \ return str; } +#ifdef GOOGLE_PROTOBUF_HAS_ONEOF + template + static T* StartOneofString(goog::Message* m, + const OneofFieldHandlerData* data, + size_t size_hint) { + const FieldOffset* ofs = data; + T** str = ofs->GetFieldPointer(m); + if (data->SetOneofHas(m)) { + *str = new T(); + } else { + (*str)->clear(); + } + return *str; + } +#endif + // StringExtension /////////////////////////////////////////////////////////// template @@ -598,6 +808,24 @@ case goog::FieldDescriptor::cpptype: \ const goog::Message* const prototype_; }; +#ifdef GOOGLE_PROTOBUF_HAS_ONEOF + class OneofSubMessageHandlerData : public SubMessageHandlerData { + public: + OneofSubMessageHandlerData(const goog::FieldDescriptor* f, + const goog::internal::GeneratedMessageReflection* r, + const goog::Message* prototype) + : SubMessageHandlerData(f, r, prototype), + oneof_data_(f, r) {} + + bool SetOneofHas(goog::Message* m) const { + return oneof_data_.SetOneofHas(m, this); + } + + private: + OneofFieldData oneof_data_; + }; +#endif + static void SetSubMessageHandlers( const goog::FieldDescriptor* proto2_f, const goog::Message& m, const goog::internal::GeneratedMessageReflection* r, @@ -605,7 +833,15 @@ case goog::FieldDescriptor::cpptype: \ const goog::Message* field_prototype = GetFieldPrototype(m, proto2_f); scoped_ptr data( new SubMessageHandlerData(proto2_f, r, field_prototype)); - if (f->IsSequence()) { +#ifdef GOOGLE_PROTOBUF_HAS_ONEOF + if (proto2_f->containing_oneof()) { + assert(!f->IsSequence()); + CHKRET(h->SetStartSubMessageHandler( + f, UpbBind(StartOneofSubMessage, new OneofSubMessageHandlerData( + proto2_f, r, field_prototype)))); + } else +#endif + if (f->IsSequence()) { SetStartRepeatedSubmessageField(proto2_f, r, f, h); CHKRET(h->SetStartSubMessageHandler( f, UpbBind(StartRepeatedSubMessage, data.release()))); @@ -649,6 +885,18 @@ case goog::FieldDescriptor::cpptype: \ return submsg; } +#ifdef GOOGLE_PROTOBUF_HAS_ONEOF + static goog::Message* StartOneofSubMessage( + goog::Message* m, const OneofSubMessageHandlerData* data) { + const FieldOffset* ofs = data; + goog::Message** subm = ofs->GetFieldPointer(m); + if (data->SetOneofHas(m)) { + *subm = data->prototype()->New(); + } + return *subm; + } +#endif + // SubMessageExtension /////////////////////////////////////////////////////// class SubMessageExtensionHandlerData : public ExtensionFieldData { @@ -979,7 +1227,7 @@ case goog::FieldDescriptor::cpptype: \ }; namespace upb { -namespace google { +namespace googlepb { bool TrySetWriteHandlers(const goog::FieldDescriptor* proto2_f, const goog::Message& prototype, @@ -987,10 +1235,13 @@ bool TrySetWriteHandlers(const goog::FieldDescriptor* proto2_f, return me::GMR_Handlers::TrySet(proto2_f, prototype, upb_f, h); } -const goog::Message* GetFieldPrototype(const goog::Message& m, - const goog::FieldDescriptor* f) { +const goog::Message* GetProto2FieldPrototype(const goog::Message& m, + const goog::FieldDescriptor* f) { + if (f->cpp_type() != goog::FieldDescriptor::CPPTYPE_MESSAGE) { + return NULL; + } return me::GMR_Handlers::GetFieldPrototype(m, f); } -} // namespace google +} // namespace googlepb } // namespace upb diff --git a/upb/bindings/googlepb/proto2.h b/upb/bindings/googlepb/proto2.h deleted file mode 100644 index 516b7fd..0000000 --- a/upb/bindings/googlepb/proto2.h +++ /dev/null @@ -1,61 +0,0 @@ -// -// upb - a minimalist implementation of protocol buffers. -// -// Copyright (c) 2011-2012 Google Inc. See LICENSE for details. -// Author: Josh Haberman -// -// Support for registering field handlers that can write into a proto2 -// message that uses GeneratedMessageReflection (which includes all messages -// generated by the proto2 compiler as well as DynamicMessage). -// -// This is a low-level interface; the high-level interface in google.h is -// more user-friendly. - -#ifndef UPB_GOOGLE_PROTO2_H_ -#define UPB_GOOGLE_PROTO2_H_ - -namespace proto2 { -class FieldDescriptor; -class Message; -} - -namespace google { -namespace protobuf { -class FieldDescriptor; -class Message; -} -} - -namespace upb { -class FieldDef; -class Handlers; -} - -namespace upb { -namespace google { - -// Sets field handlers in the given Handlers object for writing to a single -// field (as described by "proto2_f" and "upb_f") into a message constructed -// by the same factory as "prototype." Returns true if this was successful -// (this will fail if "prototype" is not a proto1 message, or if we can't -// handle it for some reason). -bool TrySetWriteHandlers(const proto2::FieldDescriptor* proto2_f, - const proto2::Message& prototype, - const upb::FieldDef* upb_f, upb::Handlers* h); -bool TrySetWriteHandlers(const ::google::protobuf::FieldDescriptor* proto2_f, - const ::google::protobuf::Message& prototype, - const upb::FieldDef* upb_f, upb::Handlers* h); - -// Returns a prototype for the given field in "m", if it is weak. The returned -// message could be the linked-in message type or OpaqueMessage, if the weak -// message is *not* linked in. Otherwise returns NULL. -const proto2::Message* GetFieldPrototype(const proto2::Message& m, - const proto2::FieldDescriptor* f); -const ::google::protobuf::Message* GetFieldPrototype( - const ::google::protobuf::Message& m, - const ::google::protobuf::FieldDescriptor* f); - -} // namespace google -} // namespace upb - -#endif // UPB_GOOGLE_PROTO2_H_ diff --git a/upb/bindings/googlepb/proto2.int.h b/upb/bindings/googlepb/proto2.int.h new file mode 100644 index 0000000..5ce44c4 --- /dev/null +++ b/upb/bindings/googlepb/proto2.int.h @@ -0,0 +1,59 @@ +// +// upb - a minimalist implementation of protocol buffers. +// +// Copyright (c) 2011-2012 Google Inc. See LICENSE for details. +// Author: Josh Haberman +// +// Support for registering field handlers that can write into a proto2 +// message that uses GeneratedMessageReflection (which includes all messages +// generated by the proto2 compiler as well as DynamicMessage). +// +// This is an internal-only interface. + +#ifndef UPB_GOOGLE_PROTO2_H_ +#define UPB_GOOGLE_PROTO2_H_ + +namespace proto2 { +class FieldDescriptor; +class Message; +} + +namespace google { +namespace protobuf { +class FieldDescriptor; +class Message; +} +} + +namespace upb { +class FieldDef; +class Handlers; +} + +namespace upb { +namespace googlepb { + +// Sets field handlers in the given Handlers object for writing to a single +// field (as described by "proto2_f" and "upb_f") into a message constructed +// by the same factory as "prototype." Returns true if this was successful +// (this will fail if "prototype" is not a proto1 message, or if we can't +// handle it for some reason). +bool TrySetWriteHandlers(const proto2::FieldDescriptor* proto2_f, + const proto2::Message& prototype, + const upb::FieldDef* upb_f, upb::Handlers* h); +bool TrySetWriteHandlers(const ::google::protobuf::FieldDescriptor* proto2_f, + const ::google::protobuf::Message& prototype, + const upb::FieldDef* upb_f, upb::Handlers* h); + +// Returns a prototype for the given field in "m", if the given message uses +// GeneratedMessageReflection. Otherwise returns NULL. +const proto2::Message* GetProto2FieldPrototype( + const proto2::Message& m, const proto2::FieldDescriptor* f); +const ::google::protobuf::Message* GetProto2FieldPrototype( + const ::google::protobuf::Message& m, + const ::google::protobuf::FieldDescriptor* f); + +} // namespace googlepb +} // namespace upb + +#endif // UPB_GOOGLE_PROTO2_H_ -- cgit v1.2.3