From 0fd2f830882402979a83010e89650e7245960d39 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Tue, 21 Jan 2014 18:38:49 -0800 Subject: Sync to internal Google development. --- upb/bindings/googlepb/bridge.cc | 279 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 279 insertions(+) create mode 100644 upb/bindings/googlepb/bridge.cc (limited to 'upb/bindings/googlepb/bridge.cc') diff --git a/upb/bindings/googlepb/bridge.cc b/upb/bindings/googlepb/bridge.cc new file mode 100644 index 0000000..a125249 --- /dev/null +++ b/upb/bindings/googlepb/bridge.cc @@ -0,0 +1,279 @@ +// +// upb - a minimalist implementation of protocol buffers. +// +// Copyright (c) 2011-2012 Google Inc. See LICENSE for details. +// Author: Josh Haberman +// +// IMPORTANT NOTE! Inside Google, 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/bindings/googlepb/bridge.h" + +#include +#include +#include +#include "upb/def.h" +#include "upb/bindings/googlepb/proto1.h" +#include "upb/bindings/googlepb/proto2.h" +#include "upb/handlers.h" + +#define ASSERT_STATUS(status) do { \ + if (!upb_ok(status)) { \ + fprintf(stderr, "upb status failure: %s\n", upb_status_errmsg(status)); \ + assert(upb_ok(status)); \ + } \ + } while (0) + +#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; +#else +#include "google/protobuf/descriptor.h" +#include "google/protobuf/message.h" +#include "google/protobuf/descriptor.pb.h" +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 + + if (f->cpp_type() == goog::FieldDescriptor::CPPTYPE_MESSAGE) { + ret = upb::google::GetFieldPrototype(m, f); +#ifdef UPB_GOOGLE3 + if (!ret) ret = upb::google::GetProto1FieldPrototype(m, f); +#endif + assert(ret); + } + return ret; +} + +} // namespace + +namespace upb { +namespace googlepb { + + +/* DefBuilder ****************************************************************/ + +const EnumDef* DefBuilder::GetEnumDef(const goog::EnumDescriptor* ed) { + const EnumDef* cached = FindInCache(ed); + if (cached) return cached; + + EnumDef* e = AddToCache(ed, EnumDef::New()); + + Status status; + e->set_full_name(ed->full_name(), &status); + for (int i = 0; i < ed->value_count(); i++) { + const goog::EnumValueDescriptor* val = ed->value(i); + bool success = e->AddValue(val->name(), val->number(), &status); + UPB_ASSERT_VAR(success, success); + } + + e->Freeze(&status); + + ASSERT_STATUS(&status); + return e; +} + +const MessageDef* DefBuilder::GetMaybeUnfrozenMessageDef( + const goog::Descriptor* d, const goog::Message* m) { + const MessageDef* cached = FindInCache(d); + if (cached) return cached; + + MessageDef* md = AddToCache(d, MessageDef::New()); + to_freeze_.push_back(upb::upcast(md)); + + Status status; + md->set_full_name(d->full_name(), &status); + ASSERT_STATUS(&status); + + // Find all regular fields and extensions for this message. + std::vector fields; + d->file()->pool()->FindAllExtensions(d, &fields); + for (int i = 0; i < d->field_count(); i++) { + fields.push_back(d->field(i)); + } + + for (int i = 0; i < fields.size(); i++) { + const goog::FieldDescriptor* proto2_f = fields[i]; + assert(proto2_f); +#ifdef UPB_GOOGLE3 + // Skip lazy fields for now since we can't properly handle them. + if (proto2_f->options().lazy()) continue; +#endif + md->AddField(NewFieldDef(proto2_f, m), &status); + } + ASSERT_STATUS(&status); + return md; +} + +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())); + + if (f->is_extension()) { + upb_f->set_name(f->full_name(), &status); + upb_f->set_is_extension(true); + } else { + 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())); + + switch (upb_f->type()) { + case UPB_TYPE_INT32: + upb_f->set_default_int32(f->default_value_int32()); + break; + case UPB_TYPE_INT64: + upb_f->set_default_int64(f->default_value_int64()); + break; + case UPB_TYPE_UINT32: + upb_f->set_default_uint32(f->default_value_uint32()); + break; + case UPB_TYPE_UINT64: + upb_f->set_default_uint64(f->default_value_uint64()); + break; + case UPB_TYPE_DOUBLE: + upb_f->set_default_double(f->default_value_double()); + break; + case UPB_TYPE_FLOAT: + upb_f->set_default_float(f->default_value_float()); + break; + case UPB_TYPE_BOOL: + upb_f->set_default_bool(f->default_value_bool()); + break; + case UPB_TYPE_STRING: + case UPB_TYPE_BYTES: + upb_f->set_default_string(f->default_value_string(), &status); + break; + case UPB_TYPE_MESSAGE: { + const goog::Descriptor* subd = + subm ? subm->GetDescriptor() : f->message_type(); + upb_f->set_message_subdef(GetMaybeUnfrozenMessageDef(subd, subm), + &status); + break; + } + case UPB_TYPE_ENUM: + // We set the enum default numerically. + upb_f->set_default_int32(f->default_value_enum()->number()); + upb_f->set_enum_subdef(GetEnumDef(f->enum_type()), &status); + break; + } + + ASSERT_STATUS(&status); + return upb_f; +} + +void DefBuilder::Freeze() { + upb::Status status; + upb::Def::Freeze(to_freeze_, &status); + ASSERT_STATUS(&status); + to_freeze_.clear(); +} + +const MessageDef* DefBuilder::GetMessageDef(const goog::Descriptor* d) { + const MessageDef* ret = GetMaybeUnfrozenMessageDef(d, NULL); + Freeze(); + return ret; +} + +const MessageDef* DefBuilder::GetMessageDefExpandWeak( + const goog::Message& m) { + const MessageDef* ret = GetMaybeUnfrozenMessageDef(m.GetDescriptor(), &m); + Freeze(); + return ret; +} + + +/* CodeCache *****************************************************************/ + +const Handlers* CodeCache::GetMaybeUnfrozenWriteHandlers( + const MessageDef* md, const goog::Message& m) { + const Handlers* cached = FindInCache(md); + if (cached) return cached; + + Handlers* h = AddToCache(md, upb::Handlers::New(md)); + to_freeze_.push_back(h); + const goog::Descriptor* d = m.GetDescriptor(); + + for (upb::MessageDef::const_iterator i = md->begin(); i != md->end(); ++i) { + const FieldDef* upb_f = *i; + + const goog::FieldDescriptor* proto2_f = + d->FindFieldByNumber(upb_f->number()); + if (!proto2_f) { + proto2_f = d->file()->pool()->FindExtensionByNumber(d, upb_f->number()); + } + 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); + } + + if (upb_f->type() == UPB_TYPE_MESSAGE) { + const goog::Message* prototype = GetPrototype(m, proto2_f); + assert(prototype); + const upb::Handlers* sub_handlers = + GetMaybeUnfrozenWriteHandlers(upb_f->message_subdef(), *prototype); + h->SetSubHandlers(upb_f, sub_handlers); + } + } + + return h; +} + +const Handlers* CodeCache::GetWriteHandlers(const goog::Message& m) { + const MessageDef* md = def_builder_.GetMessageDefExpandWeak(m); + const Handlers* ret = GetMaybeUnfrozenWriteHandlers(md, m); + upb::Status status; + upb::Handlers::Freeze(to_freeze_, &status); + ASSERT_STATUS(&status); + to_freeze_.clear(); + return ret; +} + +upb::reffed_ptr NewWriteHandlers(const goog::Message& m) { + CodeCache cache; + return upb::reffed_ptr(cache.GetWriteHandlers(m)); +} + +} // namespace googlepb +} // namespace upb -- cgit v1.2.3