summaryrefslogtreecommitdiff
path: root/upb/bindings/googlepb/bridge.cc
diff options
context:
space:
mode:
authorJosh Haberman <jhaberman@gmail.com>2014-01-21 18:38:49 -0800
committerJosh Haberman <jhaberman@gmail.com>2014-01-21 18:38:49 -0800
commit0fd2f830882402979a83010e89650e7245960d39 (patch)
tree0968ca9424c5fb2433047519cbd54d3dd8d0b863 /upb/bindings/googlepb/bridge.cc
parentce9bba3cb5409844f8f3d7dcc235a9ea30cad090 (diff)
Sync to internal Google development.
Diffstat (limited to 'upb/bindings/googlepb/bridge.cc')
-rw-r--r--upb/bindings/googlepb/bridge.cc279
1 files changed, 279 insertions, 0 deletions
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 <jhaberman@gmail.com>
+//
+// 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 <stdio.h>
+#include <map>
+#include <string>
+#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<EnumDef>(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<MessageDef>(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<const goog::FieldDescriptor*> 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<FieldDef> 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<FieldDef> 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<const upb::Handlers> NewWriteHandlers(const goog::Message& m) {
+ CodeCache cache;
+ return upb::reffed_ptr<const upb::Handlers>(cache.GetWriteHandlers(m));
+}
+
+} // namespace googlepb
+} // namespace upb
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback