diff options
Diffstat (limited to 'upb/google/bridge.cc')
-rw-r--r-- | upb/google/bridge.cc | 260 |
1 files changed, 260 insertions, 0 deletions
diff --git a/upb/google/bridge.cc b/upb/google/bridge.cc new file mode 100644 index 0000000..4d64ab8 --- /dev/null +++ b/upb/google/bridge.cc @@ -0,0 +1,260 @@ +// +// upb - a minimalist implementation of protocol buffers. +// +// Copyright (c) 2011-2012 Google Inc. See LICENSE for details. +// Author: Josh Haberman <jhaberman@gmail.com> +// +// IMPORTANT NOTE! This file is compiled TWICE, once with UPB_GOOGLE3 defined +// and once without! This allows us to provide functionality against proto2 +// and protobuf opensource both in a single binary without the two conflicting. +// However we must be careful not to violate the ODR. + +#include "upb/google/bridge.h" + +#include <map> +#include <string> +#include "upb/def.h" +#include "upb/google/proto1.h" +#include "upb/google/proto2.h" +#include "upb/handlers.h" + +namespace upb { +namespace proto2_bridge_google3 { class Defs; } +namespace proto2_bridge_opensource { class Defs; } +} // namespace upb + +#ifdef UPB_GOOGLE3 +#include "net/proto2/public/descriptor.h" +#include "net/proto2/public/message.h" +#include "net/proto2/proto/descriptor.pb.h" +namespace goog = ::proto2; +namespace me = ::upb::proto2_bridge_google3; +#else +#include "google/protobuf/descriptor.h" +#include "google/protobuf/message.h" +#include "google/protobuf/descriptor.pb.h" +namespace goog = ::google::protobuf; +namespace me = ::upb::proto2_bridge_opensource; +#endif + +class me::Defs { + public: + void OnMessage(Handlers* h) { + const upb::MessageDef* md = h->message_def(); + const goog::Message& m = *message_map_[md]; + const goog::Descriptor* d = m.GetDescriptor(); + for (upb::MessageDef::ConstIterator i(md); !i.Done(); i.Next()) { + const upb::FieldDef* upb_f = i.field(); + const goog::FieldDescriptor* proto2_f = + d->FindFieldByNumber(upb_f->number()); + 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); + } + } + } + + static void StaticOnMessage(void *closure, upb::Handlers* handlers) { + me::Defs* defs = static_cast<me::Defs*>(closure); + defs->OnMessage(handlers); + } + + void AddSymbol(const std::string& name, upb::Def* def) { + assert(symbol_map_.find(name) == symbol_map_.end()); + symbol_map_[name] = def; + } + + void AddMessage(const goog::Message* m, upb::MessageDef* md) { + assert(message_map_.find(md) == message_map_.end()); + message_map_[md] = m; + AddSymbol(m->GetDescriptor()->full_name(), md->Upcast()); + } + + upb::Def* FindSymbol(const std::string& name) { + SymbolMap::iterator iter = symbol_map_.find(name); + return iter != symbol_map_.end() ? iter->second : NULL; + } + + void Flatten(std::vector<upb::Def*>* defs) { + SymbolMap::iterator iter; + for (iter = symbol_map_.begin(); iter != symbol_map_.end(); ++iter) { + defs->push_back(iter->second); + } + } + + private: + // Maps a new upb::MessageDef* to a corresponding proto2 Message* whose + // derived class is of the correct type according to the message the user + // gave us. + typedef std::map<const upb::MessageDef*, const goog::Message*> MessageMap; + MessageMap message_map_; + + // Maps a type name to a upb Def we have constructed to represent it. + typedef std::map<std::string, upb::Def*> SymbolMap; + SymbolMap symbol_map_; +}; + +namespace upb { +namespace google { + +// For submessage fields, stores a pointer to an instance of the submessage in +// *subm (but it is *not* guaranteed to be a prototype). +FieldDef* AddFieldDef(const goog::Message& m, const goog::FieldDescriptor* f, + upb::MessageDef* md, const goog::Message** subm) { + // To parse weak submessages effectively, we need to represent them in the + // upb::Def schema even though they are not reflected in the proto2 + // descriptors (weak fields are represented as FieldDescriptor::TYPE_BYTES). + const goog::Message* weak_prototype = NULL; +#ifdef UPB_GOOGLE3 + weak_prototype = upb::google::GetProto1WeakPrototype(m, f); +#endif + + 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::FieldDef::Label>(f->label())); + upb_f->set_type(weak_prototype ? + UPB_TYPE_MESSAGE : static_cast<upb::FieldDef::Type>(f->type())); + + if (weak_prototype) { + upb_f->set_subdef_name(weak_prototype->GetDescriptor()->full_name()); + } else if (upb_f->IsSubMessage()) { + upb_f->set_subdef_name(f->message_type()->full_name()); + } else if (upb_f->type() == UPB_TYPE(ENUM)) { + // We set the enum default numerically. + upb_f->set_default_value( + MakeValue(static_cast<int32_t>(f->default_value_enum()->number()))); + upb_f->set_subdef_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_value(MakeValue(f->default_value_int32())); + break; + case UPB_CTYPE_INT64: + upb_f->set_default_value( + MakeValue(static_cast<int64_t>(f->default_value_int64()))); + break; + case UPB_CTYPE_UINT32: + upb_f->set_default_value(MakeValue(f->default_value_uint32())); + break; + case UPB_CTYPE_UINT64: + upb_f->set_default_value( + MakeValue(static_cast<uint64_t>(f->default_value_uint64()))); + break; + case UPB_CTYPE_DOUBLE: + upb_f->set_default_value(MakeValue(f->default_value_double())); + break; + case UPB_CTYPE_FLOAT: + upb_f->set_default_value(MakeValue(f->default_value_float())); + break; + case UPB_CTYPE_BOOL: + upb_f->set_default_value(MakeValue(f->default_value_bool())); + break; + case UPB_CTYPE_BYTEREGION: + upb_f->set_default_string(f->default_value_string()); + break; + } + } + bool ok = md->AddField(upb_f, &upb_f); + UPB_ASSERT_VAR(ok, ok); + + if (weak_prototype) { + *subm = weak_prototype; + } else if (f->cpp_type() == goog::FieldDescriptor::CPPTYPE_MESSAGE) { + *subm = upb::google::GetFieldPrototype(m, f); +#ifdef UPB_GOOGLE3 + if (!*subm) + *subm = upb::google::GetProto1FieldPrototype(m, f); +#endif + assert(*subm); + } + + return upb_f; +} + +upb::EnumDef* NewEnumDef(const goog::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 goog::EnumValueDescriptor* val = desc->value(i); + bool success = e->AddValue(val->name(), val->number(), NULL); + UPB_ASSERT_VAR(success, success); + } + return e; +} + +static upb::MessageDef* NewMessageDef(const goog::Message& m, void *owner, + me::Defs* defs) { + upb::MessageDef* md = upb::MessageDef::New(owner); + md->set_full_name(m.GetDescriptor()->full_name()); + + // Must do this before processing submessages to prevent infinite recursion. + defs->AddMessage(&m, md); + + const goog::Descriptor* d = m.GetDescriptor(); + for (int i = 0; i < d->field_count(); i++) { + const goog::FieldDescriptor* proto2_f = d->field(i); + +#ifdef UPB_GOOGLE3 + // Skip lazy fields for now since we can't properly handle them. + if (proto2_f->options().lazy()) continue; +#endif + // Extensions not supported yet. + if (proto2_f->is_extension()) continue; + + const goog::Message* subm_prototype; + upb::FieldDef* f = AddFieldDef(m, proto2_f, md, &subm_prototype); + + if (!f->HasSubDef()) continue; + + upb::Def* subdef = defs->FindSymbol(f->subdef_name()); + if (!subdef) { + if (f->type() == UPB_TYPE(ENUM)) { + subdef = NewEnumDef(proto2_f->enum_type(), owner)->Upcast(); + defs->AddSymbol(subdef->full_name(), subdef); + } else { + assert(f->IsSubMessage()); + assert(subm_prototype); + subdef = NewMessageDef(*subm_prototype, owner, defs)->Upcast(); + } + } + f->set_subdef(subdef); + } + + return md; +} + +const upb::Handlers* NewWriteHandlers(const goog::Message& m, void *owner) { + me::Defs defs; + const upb::MessageDef* md = NewMessageDef(m, owner, &defs); + + std::vector<upb::Def*> defs_vec; + defs.Flatten(&defs_vec); + Status status; + bool success = Def::Freeze(defs_vec, &status); + UPB_ASSERT_VAR(success, success); + + const upb::Handlers* ret = + upb::Handlers::NewFrozen(md, owner, me::Defs::StaticOnMessage, &defs); + + // Unref all defs, since they're now ref'd by the handlers. + for (int i = 0; i < static_cast<int>(defs_vec.size()); i++) { + defs_vec[i]->Unref(owner); + } + + return ret; +} + +} // namespace google +} // namespace upb |