From c0a50de92300080a1cf11bf4ff0ec3b2d6240c10 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Tue, 21 Aug 2018 14:47:50 -0700 Subject: Removed a bunch of obsolete code. A lot of this code was experimental or temporarily useful, but is no longer needed. --- upb/bindings/README | 22 +- upb/bindings/googlepb/README | 20 - upb/bindings/googlepb/bridge.cc | 281 ------- upb/bindings/googlepb/bridge.h | 255 ------- upb/bindings/googlepb/proto1.cc | 512 ------------- upb/bindings/googlepb/proto1.int.h | 39 - upb/bindings/googlepb/proto2.cc | 1395 ----------------------------------- upb/bindings/googlepb/proto2.int.h | 53 -- upb/bindings/linux/Makefile | 20 - upb/bindings/linux/assert.h | 14 - upb/bindings/linux/errno.h | 2 - upb/bindings/linux/stdint.h | 2 - upb/bindings/linux/stdio.h | 2 - upb/bindings/linux/stdlib.h | 17 - upb/bindings/linux/string.h | 7 - upb/bindings/python/setup.py | 14 - upb/bindings/python/test.py | 72 -- upb/bindings/python/upb.c | 732 ------------------ upb/bindings/python/upb/__init__.py | 0 upb/bindings/ruby/README.md | 30 - upb/bindings/ruby/extconf.rb | 13 - upb/bindings/ruby/upb.c | 1173 ----------------------------- upb/bindings/stdc++/string.h | 64 -- upb/bindings/stdc/error.c | 38 - upb/bindings/stdc/error.h | 18 - upb/bindings/stdc/io.c | 172 ----- upb/bindings/stdc/io.h | 64 -- 27 files changed, 1 insertion(+), 5030 deletions(-) delete mode 100644 upb/bindings/googlepb/README delete mode 100644 upb/bindings/googlepb/bridge.cc delete mode 100644 upb/bindings/googlepb/bridge.h delete mode 100644 upb/bindings/googlepb/proto1.cc delete mode 100644 upb/bindings/googlepb/proto1.int.h delete mode 100644 upb/bindings/googlepb/proto2.cc delete mode 100644 upb/bindings/googlepb/proto2.int.h delete mode 100644 upb/bindings/linux/Makefile delete mode 100644 upb/bindings/linux/assert.h delete mode 100644 upb/bindings/linux/errno.h delete mode 100644 upb/bindings/linux/stdint.h delete mode 100644 upb/bindings/linux/stdio.h delete mode 100644 upb/bindings/linux/stdlib.h delete mode 100644 upb/bindings/linux/string.h delete mode 100644 upb/bindings/python/setup.py delete mode 100644 upb/bindings/python/test.py delete mode 100644 upb/bindings/python/upb.c delete mode 100644 upb/bindings/python/upb/__init__.py delete mode 100644 upb/bindings/ruby/README.md delete mode 100644 upb/bindings/ruby/extconf.rb delete mode 100644 upb/bindings/ruby/upb.c delete mode 100644 upb/bindings/stdc++/string.h delete mode 100644 upb/bindings/stdc/error.c delete mode 100644 upb/bindings/stdc/error.h delete mode 100644 upb/bindings/stdc/io.c delete mode 100644 upb/bindings/stdc/io.h (limited to 'upb/bindings') diff --git a/upb/bindings/README b/upb/bindings/README index e4bf0b8..3e176c9 100644 --- a/upb/bindings/README +++ b/upb/bindings/README @@ -1,25 +1,5 @@ This directory contains code that interfaces upb with external C/C++ -libraries. For example: - - * upb/bindings/{stdc,stdc++} - interfaces between upb and the standard libraries of C and C++ (like C's - FILE/stdio, C++'s string/iostream, etc.) - - * upb/bindings/googlepb - interfaces between upb and the "protobuf" library distributed by Google. +libraries. Right now this is: * upb/bindings/lua: a Lua extension that exposes upb to Lua programs via the Lua C API. - - * upb/bindings/linux: - code and build system for building upb as a Linux kernel module. - -The two key characteristics that decide whether code belongs in upb/bindings/ -are: - - * Does the code's public API refer to types from another library? - If so it belongs in upb/bindings/. But this doesn't include code that just - happens to use another library internally, as an implementation detail. - - * Would this code be useful to someone who is not using this external library - in some other way? If so, the code probably doesn't belong in upb/bindings/. diff --git a/upb/bindings/googlepb/README b/upb/bindings/googlepb/README deleted file mode 100644 index e3140f4..0000000 --- a/upb/bindings/googlepb/README +++ /dev/null @@ -1,20 +0,0 @@ -This directory contains code to interoperate with Google's official -Protocol Buffers release. Since it doesn't really have a name -besides "protobuf," calling this directory "googlepb" seems like the -least confusing option, since it lives in the google::protobuf -namespace. - -We support writing into protobuf's generated classes (and hopefully -reading too, before long). We support both the open source protobuf -release and the Google-internal version (which is mostly the same -code, just in a different namespace). A single compile of upb can -support both (there are no conflicts thanks to function overloading). - -The internal version supports some features that are not supported in -the open-source release. Also, the internal version includes the -legacy "proto1" classes which we must support; thankfully this is -mostly relegated to its own separate file. - -Our functionality requires the full google::protobuf::Message -interface; we rely on reflection so we know what fields to read/write -and where to put them, so we can't support MessageLite. diff --git a/upb/bindings/googlepb/bridge.cc b/upb/bindings/googlepb/bridge.cc deleted file mode 100644 index adba3e7..0000000 --- a/upb/bindings/googlepb/bridge.cc +++ /dev/null @@ -1,281 +0,0 @@ - -// 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.int.h" -#include "upb/bindings/googlepb/proto2.int.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)); \ - UPB_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 upb { -namespace googlepb { - -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::googlepb::GetProto1FieldPrototype(m, f); -#endif - return ret; -} - -const goog::Message* GetFieldPrototype(const goog::Message& m, - const goog::FieldDescriptor* f) { - const goog::Message* ret = TryGetFieldPrototype(m, f); - UPB_ASSERT(ret); - return ret; -} - -/* 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(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 (size_t i = 0; i < fields.size(); i++) { - const goog::FieldDescriptor* proto2_f = fields[i]; - UPB_ASSERT(proto2_f); - md->AddField(NewFieldDef(proto2_f, m), &status); - } - ASSERT_STATUS(&status); - return md; -} - -reffed_ptr DefBuilder::NewFieldDef(const goog::FieldDescriptor* f, - const goog::Message* m) { - 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())); - upb_f->set_packed(f->options().packed()); -#ifdef UPB_GOOGLE3 - upb_f->set_lazy(f->options().lazy()); -#endif - - 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); - } - - const goog::Message* subm = NULL; - - if (m) { - subm = TryGetFieldPrototype(*m, f); - - if (upb_f->type() == UPB_TYPE_MESSAGE) { - UPB_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: - 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; -} - - -/* 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( - 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_field_iterator i = md->field_begin(); - i != md->field_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()); - } - UPB_ASSERT(proto2_f); - - bool ok = WriteHandlers::AddFieldHandler(m, proto2_f, h); - UPB_ASSERT(ok); - - if (upb_f->type() == UPB_TYPE_MESSAGE) { - const goog::Message* prototype = GetFieldPrototype(m, proto2_f); - UPB_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; -} - -} // namespace googlepb -} // namespace upb diff --git a/upb/bindings/googlepb/bridge.h b/upb/bindings/googlepb/bridge.h deleted file mode 100644 index ce55dc6..0000000 --- a/upb/bindings/googlepb/bridge.h +++ /dev/null @@ -1,255 +0,0 @@ -// -// upb::googlepb::DefBuilder -// upb::googlepb::WriteHandlers -// upb::googlepb::CodeCache -// -// This file contains functionality for constructing upb Defs and Handlers -// corresponding to proto2 messages. Using this functionality, you can use upb -// to dynamically generate parsing code that can behave exactly like proto2's -// generated parsing code. Alternatively, you can configure things to -// read/write only a subset of the fields for higher performance when only some -// fields are needed. -// -// Example usage: -// -// // JIT the parser; should only be done once ahead-of-time. -// upb::reffed_ptr write_myproto( -// upb::google::NewWriteHandlers(MyProto())); -// upb::reffed_ptr parse_myproto( -// upb::Decoder::NewDecoderHandlers(write_myproto.get(), true)); -// -// // The actual parsing. -// MyProto proto; -// upb::SeededPipeline<8192> pipeline(upb_realloc, NULL); -// upb::Sink* write_sink = pipeline.NewSink(write_myproto.get()); -// upb::Sink* parse_sink = pipeline.NewSink(parse_myproto.get()); -// upb::pb::Decoder* decoder = decoder_sink->GetObject(); -// upb::pb::ResetDecoderSink(decoder, write_sink); -// write_sink->Reset(&proto); -// -// Note that there is currently no support for -// CodedInputStream::SetExtensionRegistry(), which allows specifying a separate -// DescriptorPool and MessageFactory for extensions. Since this is a property -// of the input in proto2, it's difficult to build a plan ahead-of-time that -// can properly support this. If it's an important use case, the caller should -// probably build a upb plan explicitly. - -#ifndef UPB_GOOGLE_BRIDGE_H_ -#define UPB_GOOGLE_BRIDGE_H_ - -#include -#include -#include "upb/handlers.h" -#include "upb/upb.h" - -namespace google { -namespace protobuf { -class FieldDescriptor; -class Descriptor; -class EnumDescriptor; -class Message; -} // namespace protobuf -} // namespace google - -namespace proto2 { -class FieldDescriptor; -class Descriptor; -class EnumDescriptor; -class Message; -} - -namespace upb { - -namespace googlepb { - -// 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. -// -// This class is NOT thread-safe. -class DefBuilder { - public: - // Functions to get or create a Def from a corresponding proto2 Descriptor. - // The returned def will be frozen. - // - // The caller must take a ref on the returned value if it needs it long-term. - // The DefBuilder will retain a ref so it can keep the Def cached, but - // garbage-collection functionality may be added to DefBuilder later that - // could unref the returned pointer. - const EnumDef* GetEnumDef(const proto2::EnumDescriptor* d); - const EnumDef* GetEnumDef(const ::google::protobuf::EnumDescriptor* d); - const MessageDef* GetMessageDef(const proto2::Descriptor* d); - const MessageDef* GetMessageDef(const ::google::protobuf::Descriptor* d); - - // Gets or creates a frozen MessageDef, properly expanding weak fields. - // - // Weak fields are only represented as BYTES fields in the Descriptor (unless - // you construct your descriptors in a somewhat complicated way; see - // https://goto.google.com/weak-field-descriptor), but we can get their true - // definitions relatively easily from the proto Message class. - const MessageDef* GetMessageDefExpandWeak(const proto2::Message& m); - const MessageDef* GetMessageDefExpandWeak( - const ::google::protobuf::Message& m); - - // Static methods for converting a def without building a DefBuilder. - static reffed_ptr NewMessageDef( - const proto2::Descriptor* d) { - DefBuilder builder; - return reffed_ptr(builder.GetMessageDef(d)); - } - - private: - // Like GetMessageDef*(), except the returned def might not be frozen. - // We need this function because circular graphs of MessageDefs need to all - // be frozen together, to we have to create the graphs of defs in an unfrozen - // state first. - // - // If m is non-NULL, expands weak message fields. - const MessageDef* GetMaybeUnfrozenMessageDef(const proto2::Descriptor* d, - const proto2::Message* m); - const MessageDef* GetMaybeUnfrozenMessageDef( - const ::google::protobuf::Descriptor* d, - const ::google::protobuf::Message* m); - - // Returns a new-unfrozen FieldDef corresponding to this FieldDescriptor. - // The return value is always newly created (never cached) and the returned - // pointer is the only owner of it. - // - // If "m" is non-NULL, expands the weak field if it is one, and populates - // *subm_prototype with a prototype of the submessage if this is a weak or - // non-weak MESSAGE or GROUP field. - reffed_ptr NewFieldDef(const proto2::FieldDescriptor* f, - const proto2::Message* m); - reffed_ptr NewFieldDef(const ::google::protobuf::FieldDescriptor* f, - const ::google::protobuf::Message* m); - - // Freeze all defs that haven't been frozen yet. - void Freeze(); - - template - T* AddToCache(const void *proto2_descriptor, reffed_ptr def) { - UPB_ASSERT(def_cache_.find(proto2_descriptor) == def_cache_.end()); - def_cache_[proto2_descriptor] = def; - return def.get(); // Continued lifetime is guaranteed by cache. - } - - template - const T* FindInCache(const void *proto2_descriptor) { - DefCache::iterator iter = def_cache_.find(proto2_descriptor); - return iter == def_cache_.end() ? NULL : - upb::down_cast(iter->second.get()); - } - - private: - // Maps a proto2 descriptor to the corresponding upb Def we have constructed. - // The proto2 descriptor is void* because the proto2 descriptor types do not - // share a common base. - typedef std::map > DefCache; - DefCache def_cache_; - - // Defs that have not been frozen yet. - 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. -class CodeCache { - public: - // Gets or creates handlers for populating messages of the given message type. - // - // The caller must take a ref on the returned value if it needs it long-term. - // The CodeCache will retain a ref so it can keep the Def cached, but - // garbage-collection functionality may be added to CodeCache later that could - // unref the returned pointer. - const Handlers* GetWriteHandlers(const proto2::Message& m); - const Handlers* GetWriteHandlers(const ::google::protobuf::Message& m); - - private: - const Handlers* GetMaybeUnfrozenWriteHandlers(const MessageDef* md, - const proto2::Message& m); - const Handlers* GetMaybeUnfrozenWriteHandlers( - const MessageDef* md, const ::google::protobuf::Message& m); - - Handlers* AddToCache(const MessageDef* md, reffed_ptr handlers) { - UPB_ASSERT(handlers_cache_.find(md) == handlers_cache_.end()); - handlers_cache_[md] = handlers; - return handlers.get(); // Continue lifetime is guaranteed by the cache. - } - - const Handlers* FindInCache(const MessageDef* md) { - HandlersCache::iterator iter = handlers_cache_.find(md); - return iter == handlers_cache_.end() ? NULL : iter->second.get(); - } - - DefBuilder def_builder_; - - typedef std::map > - HandlersCache; - HandlersCache handlers_cache_; - - 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 - -#endif // UPB_GOOGLE_BRIDGE_H_ diff --git a/upb/bindings/googlepb/proto1.cc b/upb/bindings/googlepb/proto1.cc deleted file mode 100644 index c85bfca..0000000 --- a/upb/bindings/googlepb/proto1.cc +++ /dev/null @@ -1,512 +0,0 @@ -// -// This set of handlers can write into a proto2::Message whose reflection class -// is _pi::Proto2Reflection (ie. proto1 messages; while slightly confusing, the -// name "Proto2Reflection" indicates that it is a reflection class implementing -// the proto2 reflection interface, but is used for proto1 generated messages). -// -// Like FieldAccessor this depends on breaking encapsulation, and will need to -// be changed if and when the details of _pi::Proto2Reflection change. -// -// Note that we have received an exception from c-style-artiters regarding -// 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.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 - -#ifdef GOOGLE_PROTOBUF_HAS_ARENAS -namespace proto2 { class Arena; } -#endif - -#include "upb/def.h" -#include "upb/handlers.h" -#include "upb/shim/shim.h" -#include "upb/sink.h" - -// Unconditionally evaluate, but also assert in debug mode. -#define CHKRET(x) do { bool ok = (x); UPB_ASSERT(ok); } while (0) - -template static T* GetPointer(void* message, size_t offset) { - return reinterpret_cast(static_cast(message) + offset); -} - -namespace upb { -namespace googlepb { - -class P2R_Handlers { - 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 proto2::FieldDescriptor* proto2_f, - const proto2::Message& m, const upb::FieldDef* upb_f, - upb::Handlers* h) { - const proto2::Reflection* base_r = m.GetReflection(); - // See file comment re: dynamic_cast. - const _pi::Proto2Reflection* r = - dynamic_cast(base_r); - if (!r) return false; - // Extensions don't exist in proto1. - UPB_ASSERT(!proto2_f->is_extension()); - -#define PRIMITIVE(name, type_name) \ - case _pi::CREP_REQUIRED_##name: \ - case _pi::CREP_OPTIONAL_##name: \ - case _pi::CREP_REPEATED_##name: \ - SetPrimitiveHandlers(proto2_f, r, upb_f, h); \ - return true; - - switch (r->GetFieldLayout(proto2_f)->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: - SetStringHandlers(proto2_f, r, upb_f, h); - return true; - case _pi::CREP_OPTIONAL_OUTOFLINE_STRING: - SetOutOfLineStringHandlers(proto2_f, r, upb_f, h); - return true; - case _pi::CREP_REQUIRED_CORD: - case _pi::CREP_OPTIONAL_CORD: - case _pi::CREP_REPEATED_CORD: - SetCordHandlers(proto2_f, r, upb_f, h); - return true; - case _pi::CREP_REQUIRED_GROUP: - case _pi::CREP_REQUIRED_FOREIGN: - case _pi::CREP_REQUIRED_FOREIGN_PROTO2: - SetRequiredMessageHandlers(proto2_f, m, r, upb_f, h); - return true; - 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: - SetMessageHandlers(proto2_f, m, r, upb_f, h); - return true; - case _pi::CREP_OPTIONAL_FOREIGN_WEAK: - case _pi::CREP_OPTIONAL_FOREIGN_WEAK_PROTO2: - SetWeakMessageHandlers(proto2_f, m, r, upb_f, h); - return true; - default: - UPB_ASSERT(false); - return false; - } - } - -#undef PRIMITIVE - - // If the field "f" in the message "m" is a weak field, returns the prototype - // of the submessage (which may be a specific type or may be OpaqueMessage). - // Otherwise returns NULL. - static const proto2::Message* GetWeakPrototype( - const proto2::Message& m, const proto2::FieldDescriptor* f) { - // See file comment re: dynamic_cast. - const _pi::Proto2Reflection* r = - dynamic_cast(m.GetReflection()); - if (!r) return NULL; - - const _pi::Field* field = r->GetFieldLayout(f); - if (field->crep == _pi::CREP_OPTIONAL_FOREIGN_WEAK) { - return static_cast( - field->weak_layout()->default_instance); - } else if (field->crep == _pi::CREP_OPTIONAL_FOREIGN_WEAK_PROTO2) { - return field->proto2_weak_default_instance(); - } else { - return NULL; - } - } - - // If "m" is a message that uses Proto2Reflection, returns the prototype of - // the submessage (which may be OpaqueMessage for a weak field that is not - // linked in). Otherwise returns NULL. - static const proto2::Message* GetFieldPrototype( - const proto2::Message& m, const proto2::FieldDescriptor* f) { - // See file comment re: dynamic_cast. - const proto2::Message* ret = GetWeakPrototype(m, f); - if (ret) { - return ret; - } else if (dynamic_cast(m.GetReflection())) { - // Since proto1 has no dynamic message, it must be from the generated - // factory. - UPB_ASSERT(f->cpp_type() == proto2::FieldDescriptor::CPPTYPE_MESSAGE); - ret = proto2::MessageFactory::generated_factory()->GetPrototype( - f->message_type()); - UPB_ASSERT(ret); - return ret; - } else { - return NULL; - } - } - - private: - class FieldOffset { - public: - FieldOffset(const proto2::FieldDescriptor* f, - const _pi::Proto2Reflection* r) - : offset_(GetOffset(f, r)), is_repeated_(f->is_repeated()) { - if (!is_repeated_) { - int64_t hasbit = GetHasbit(f, r); - hasbyte_ = hasbit / 8; - mask_ = 1 << (hasbit % 8); - } - } - - template T* GetFieldPointer(proto2::Message* message) const { - return GetPointer(message, offset_); - } - - void SetHasbit(void* message) const { - UPB_ASSERT(!is_repeated_); - uint8_t* byte = GetPointer(message, hasbyte_); - *byte |= mask_; - } - - private: - const size_t offset_; - bool is_repeated_; - - // Only for non-repeated fields. - int32_t hasbyte_; - int8_t mask_; - }; - - static upb_selector_t GetSelector(const upb::FieldDef* f, - upb::Handlers::Type type) { - upb::Handlers::Selector selector; - bool ok = upb::Handlers::GetSelector(f, type, &selector); - UPB_ASSERT(ok); - return selector; - } - - static int16_t GetHasbit(const proto2::FieldDescriptor* f, - const _pi::Proto2Reflection* r) { - UPB_ASSERT(!f->is_repeated()); - return (r->layout_->has_bit_offset * 8) + r->GetFieldLayout(f)->has_index; - } - - static uint16_t GetOffset(const proto2::FieldDescriptor* f, - const _pi::Proto2Reflection* r) { - return r->GetFieldLayout(f)->offset; - } - - // StartSequence ///////////////////////////////////////////////////////////// - - template - static void SetStartRepeatedField( - const proto2::FieldDescriptor* proto2_f, const _pi::Proto2Reflection* r, - const upb::FieldDef* f, upb::Handlers* h) { - CHKRET(h->SetStartSequenceHandler( - f, UpbBindT(PushOffset >, - new FieldOffset(proto2_f, r)))); - } - - template - static void SetStartRepeatedPtrField( - const proto2::FieldDescriptor* proto2_f, const _pi::Proto2Reflection* r, - const upb::FieldDef* f, upb::Handlers* h) { - CHKRET(h->SetStartSequenceHandler( - f, UpbBindT(PushOffset >, - new FieldOffset(proto2_f, r)))); - } - - static void SetStartRepeatedSubmessageField( - const proto2::FieldDescriptor* proto2_f, const _pi::Proto2Reflection* r, - const upb::FieldDef* f, upb::Handlers* h) { - CHKRET(h->SetStartSequenceHandler( - f, UpbBind(PushOffset, - new FieldOffset(proto2_f, r)))); - } - - template - static T* PushOffset(proto2::Message* m, const FieldOffset* offset) { - return offset->GetFieldPointer(m); - } - - // Primitive Value (numeric, enum, bool) ///////////////////////////////////// - - template - static void SetPrimitiveHandlers(const proto2::FieldDescriptor* proto2_f, - const _pi::Proto2Reflection* r, - const upb::FieldDef* f, upb::Handlers* h) { - if (f->IsSequence()) { - SetStartRepeatedField(proto2_f, r, f, h); - CHKRET(h->SetValueHandler(f, UpbMakeHandlerT(Append))); - } else { - CHKRET( - upb::Shim::Set(h, f, GetOffset(proto2_f, r), GetHasbit(proto2_f, r))); - } - } - - template - static void Append(proto2::RepeatedField* r, T val) { - // Proto1's ProtoArray class derives from proto2::RepeatedField. - r->Add(val); - } - - // String //////////////////////////////////////////////////////////////////// - - static void SetStringHandlers(const proto2::FieldDescriptor* proto2_f, - const _pi::Proto2Reflection* r, - const upb::FieldDef* f, upb::Handlers* h) { - h->SetStringHandler(f, UpbMakeHandler(OnStringBuf)); - if (f->IsSequence()) { - SetStartRepeatedPtrField(proto2_f, r, f, h); - CHKRET(h->SetStartStringHandler(f, UpbMakeHandler(StartRepeatedString))); - } else { - CHKRET(h->SetStartStringHandler( - f, UpbBind(StartString, new FieldOffset(proto2_f, r)))); - } - } - - static string* StartString(proto2::Message* m, const FieldOffset* info, - size_t size_hint) { - info->SetHasbit(m); - string* str = info->GetFieldPointer(m); - str->clear(); - // reserve() here appears to hurt performance rather than help. - return str; - } - - static void OnStringBuf(string* s, const char* buf, size_t n) { - s->append(buf, n); - } - - static string* StartRepeatedString(proto2::RepeatedPtrField* r, - size_t size_hint) { - string* str = r->Add(); - // reserve() here appears to hurt performance rather than help. - return str; - } - - // Out-of-line string //////////////////////////////////////////////////////// - - static void SetOutOfLineStringHandlers( - const proto2::FieldDescriptor* proto2_f, const _pi::Proto2Reflection* r, - const upb::FieldDef* f, upb::Handlers* h) { - // This type is only used for non-repeated string fields. - UPB_ASSERT(!f->IsSequence()); - CHKRET(h->SetStartStringHandler( - f, UpbBind(StartOutOfLineString, new FieldOffset(proto2_f, r)))); - CHKRET(h->SetStringHandler(f, UpbMakeHandler(OnStringBuf))); - } - - static string* StartOutOfLineString(proto2::Message* m, - const FieldOffset* info, - size_t size_hint) { - info->SetHasbit(m); - string** str = info->GetFieldPointer(m); - if (*str == &::proto2::internal::GetEmptyString()) - *str = new string(); - (*str)->clear(); - // reserve() here appears to hurt performance rather than help. - return *str; - } - - // Cord ////////////////////////////////////////////////////////////////////// - - static void SetCordHandlers(const proto2::FieldDescriptor* proto2_f, - const _pi::Proto2Reflection* r, - const upb::FieldDef* f, upb::Handlers* h) { - if (f->IsSequence()) { - SetStartRepeatedField(proto2_f, r, f, h); - CHKRET(h->SetStartStringHandler(f, UpbMakeHandler(StartRepeatedCord))); - } else { - CHKRET(h->SetStartStringHandler( - f, UpbBind(StartCord, new FieldOffset(proto2_f, r)))); - } - CHKRET(h->SetStringHandler(f, UpbMakeHandler(OnCordBuf))); - } - - static Cord* StartCord(proto2::Message* m, const FieldOffset* offset, - size_t size_hint) { - UPB_UNUSED(size_hint); - offset->SetHasbit(m); - Cord* field = offset->GetFieldPointer(m); - field->Clear(); - return field; - } - - static void OnCordBuf(Cord* c, const char* buf, size_t n) { - c->Append(StringPiece(buf, n)); - } - - static Cord* StartRepeatedCord(proto2::RepeatedField* r, - size_t size_hint) { - UPB_UNUSED(size_hint); - return r->Add(); - } - - // SubMessage //////////////////////////////////////////////////////////////// - - class SubMessageHandlerData : public FieldOffset { - public: - SubMessageHandlerData(const proto2::Message& prototype, - const proto2::FieldDescriptor* f, - const _pi::Proto2Reflection* r) - : FieldOffset(f, r) { - prototype_ = GetWeakPrototype(prototype, f); - if (!prototype_) prototype_ = GetFieldPrototype(prototype, f); - } - - const proto2::Message* prototype() const { return prototype_; } - - private: - const proto2::Message* prototype_; - }; - - static void SetRequiredMessageHandlers( - const proto2::FieldDescriptor* proto2_f, const proto2::Message& m, - const _pi::Proto2Reflection* r, const upb::FieldDef* f, - upb::Handlers* h) { - if (f->IsSequence()) { - SetStartRepeatedSubmessageField(proto2_f, r, f, h); - CHKRET(h->SetStartSubMessageHandler( - f, UpbBind(StartRepeatedSubMessage, - new SubMessageHandlerData(m, proto2_f, r)))); - } else { - CHKRET(h->SetStartSubMessageHandler( - f, UpbBind(StartRequiredSubMessage, new FieldOffset(proto2_f, r)))); - } - } - - static proto2::Message* StartRequiredSubMessage(proto2::Message* m, - const FieldOffset* offset) { - offset->SetHasbit(m); - return offset->GetFieldPointer(m); - } - - static void SetMessageHandlers(const proto2::FieldDescriptor* proto2_f, - const proto2::Message& m, - const _pi::Proto2Reflection* r, - const upb::FieldDef* f, upb::Handlers* h) { - std::unique_ptr data( - new SubMessageHandlerData(m, proto2_f, r)); - if (f->IsSequence()) { - SetStartRepeatedSubmessageField(proto2_f, r, f, h); - CHKRET(h->SetStartSubMessageHandler( - f, UpbBind(StartRepeatedSubMessage, data.release()))); - } else { - CHKRET(h->SetStartSubMessageHandler( - f, UpbBind(StartSubMessage, data.release()))); - } - } - - static void SetWeakMessageHandlers(const proto2::FieldDescriptor* proto2_f, - const proto2::Message& m, - const _pi::Proto2Reflection* r, - const upb::FieldDef* f, upb::Handlers* h) { - std::unique_ptr data( - new SubMessageHandlerData(m, proto2_f, r)); - if (f->IsSequence()) { - SetStartRepeatedSubmessageField(proto2_f, r, f, h); - CHKRET(h->SetStartSubMessageHandler( - f, UpbBind(StartRepeatedSubMessage, data.release()))); - } else { - CHKRET(h->SetStartSubMessageHandler( - f, UpbBind(StartWeakSubMessage, data.release()))); - } - } - - static void* StartSubMessage(proto2::Message* m, - const SubMessageHandlerData* info) { - info->SetHasbit(m); - proto2::Message** subm = info->GetFieldPointer(m); - if (*subm == info->prototype()) *subm = (*subm)->New(); - return *subm; - } - - static void* StartWeakSubMessage(proto2::Message* m, - const SubMessageHandlerData* info) { - info->SetHasbit(m); - proto2::Message** subm = info->GetFieldPointer(m); - if (*subm == NULL) { - *subm = info->prototype()->New(); - } - return *subm; - } - - class RepeatedMessageTypeHandler { - public: - typedef proto2::Message Type; -#ifndef GOOGLE_PROTOBUF_HAS_ARENAS - // AddAllocated() calls this, but only if other objects are sitting - // around waiting for reuse, which we will not do. - static void Delete(Type* t) { - UPB_UNUSED(t); - UPB_ASSERT(false); - } -#else - static ::proto2::Arena* GetArena(Type* t) { - return t->GetArena(); - } - static void* GetMaybeArenaPointer(Type* t) { - return t->GetMaybeArenaPointer(); - } - static inline Type* NewFromPrototype( - const Type* prototype, ::proto2::Arena* arena = NULL) { - return prototype->New(arena); - } - // AddAllocated() calls this, but only if other objects are sitting - // around waiting for reuse, which we will not do. - static void Delete(Type* t, ::proto2::Arena* arena) { - UPB_UNUSED(t); - UPB_UNUSED(arena); - UPB_ASSERT(false); - } - static void Merge(const Type& from, Type* to) { - to->MergeFrom(from); - } -#endif - }; - - // Closure is a RepeatedPtrField*, but we access it through - // its base class RepeatedPtrFieldBase*. - static proto2::Message* StartRepeatedSubMessage( - proto2::internal::RepeatedPtrFieldBase* r, - const SubMessageHandlerData* info) { - proto2::Message* submsg = r->AddFromCleared(); - if (!submsg) { - submsg = info->prototype()->New(); - r->AddAllocated(submsg); - } - return submsg; - } -}; - -bool TrySetProto1WriteHandlers(const proto2::FieldDescriptor* proto2_f, - const proto2::Message& m, - const upb::FieldDef* upb_f, upb::Handlers* h) { - return googlepb::P2R_Handlers::TrySet(proto2_f, m, upb_f, h); -} - -const proto2::Message* GetProto1FieldPrototype( - const proto2::Message& m, const proto2::FieldDescriptor* 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 googlepb -} // namespace upb diff --git a/upb/bindings/googlepb/proto1.int.h b/upb/bindings/googlepb/proto1.int.h deleted file mode 100644 index d5c9cad..0000000 --- a/upb/bindings/googlepb/proto1.int.h +++ /dev/null @@ -1,39 +0,0 @@ -// 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 deleted file mode 100644 index ebfedca..0000000 --- a/upb/bindings/googlepb/proto2.cc +++ /dev/null @@ -1,1395 +0,0 @@ -// -// Note that we have received an exception from c-style-artiters regarding -// dynamic_cast<> in this file: -// https://groups.google.com/a/google.com/d/msg/c-style/7Zp_XCX0e7s/I6dpzno4l-MJ -// -// 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/bindings/googlepb/proto2.int.h" - -#include - -#include "upb/bindings/googlepb/proto1.int.h" -#include "upb/def.h" -#include "upb/handlers.h" -#include "upb/msg.h" -#include "upb/sink.h" - -namespace { - -template To CheckDownCast(From* f) { - UPB_ASSERT(f == NULL || dynamic_cast(f) != NULL); - return static_cast(f); -} - -} - -// Unconditionally evaluate, but also assert in debug mode. -#define CHKRET(x) do { bool ok = (x); UPB_ASSERT(ok); } while (0) - -namespace upb { -namespace google_google3 { class GMR_Handlers; } -namespace google_opensource { class GMR_Handlers; } -} // namespace upb - -// BEGIN DOUBLE COMPILATION TRICKERY. ////////////////////////////////////////// - -#ifdef UPB_GOOGLE3 - -// TODO(haberman): Add public functionality to ExtensionSet for populating -// LazyFields. -#define private public -#include "net/proto2/public/extension_set.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/repeated_field.h" -#include "net/proto2/public/string_piece_field_support.h" - -namespace goog = ::proto2; -namespace me = ::upb::google_google3; - -#else - -// TODO(haberman): remove these once new versions of protobuf that "friend" -// upb are pervasive in the wild. -#define protected public -#include "google/protobuf/repeated_field.h" -#undef protected - -#define private public -#include "google/protobuf/generated_message_reflection.h" -#undef private - -#define private public -#include "google/protobuf/extension_set.h" -#undef private - -#include "google/protobuf/descriptor.h" -#include "google/protobuf/descriptor.pb.h" -#include "google/protobuf/message.h" - -namespace goog = ::google::protobuf; -namespace me = ::upb::google_opensource; - -using goog::int32; -using goog::int64; -using goog::uint32; -using goog::uint64; -using goog::scoped_ptr; - -#endif // ifdef UPB_GOOGLE3 - -// END DOUBLE COMPILATION TRICKERY. //////////////////////////////////////////// - -// Have to define this manually since older versions of proto2 didn't define -// an enum value for STRING. -#define UPB_CTYPE_STRING 0 - -template static T* GetPointer(void* message, size_t offset) { - return reinterpret_cast(static_cast(message) + offset); -} -template -static const T* GetConstPointer(const void* message, size_t offset) { - return reinterpret_cast(static_cast(message) + offset); -} - -// This class contains handlers that can write into a proto2 class whose -// reflection class is GeneratedMessageReflection. (Despite the name, even -// DynamicMessage uses GeneratedMessageReflection, so this covers all proto2 -// messages generated by the compiler.) To do this it must break the -// encapsulation of GeneratedMessageReflection and therefore depends on -// internal interfaces that are not guaranteed to be stable. This class will -// need to be updated if any non-backward-compatible changes are made to -// GeneratedMessageReflection. -class me::GMR_Handlers { - 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 goog::FieldDescriptor* proto2_f, - const goog::Message& m, const upb::FieldDef* upb_f, - upb::Handlers* h) { - const goog::Reflection* base_r = m.GetReflection(); - // See file comment re: dynamic_cast. - const goog::internal::GeneratedMessageReflection* r = - dynamic_cast(base_r); - if (!r) return false; - -#define PRIMITIVE_TYPE(cpptype, cident) \ -case goog::FieldDescriptor::cpptype: \ - SetPrimitiveHandlers(proto2_f, r, upb_f, h); \ - return true; - - switch (proto2_f->cpp_type()) { - PRIMITIVE_TYPE(CPPTYPE_INT32, int32); - PRIMITIVE_TYPE(CPPTYPE_INT64, int64); - PRIMITIVE_TYPE(CPPTYPE_UINT32, uint32); - PRIMITIVE_TYPE(CPPTYPE_UINT64, uint64); - PRIMITIVE_TYPE(CPPTYPE_DOUBLE, double); - PRIMITIVE_TYPE(CPPTYPE_FLOAT, float); - PRIMITIVE_TYPE(CPPTYPE_BOOL, bool); - case goog::FieldDescriptor::CPPTYPE_ENUM: - if (proto2_f->is_extension()) { - SetEnumExtensionHandlers(proto2_f, r, upb_f, h); - } else { - SetEnumHandlers(proto2_f, r, upb_f, h); - } - return true; - case goog::FieldDescriptor::CPPTYPE_STRING: { - if (proto2_f->is_extension()) { -#ifdef UPB_GOOGLE3 - SetStringExtensionHandlers(proto2_f, r, upb_f, h); -#else - SetStringExtensionHandlers(proto2_f, r, upb_f, h); -#endif - return true; - } - - // 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; - switch (ctype) { -#ifdef UPB_GOOGLE3 - case goog::FieldOptions::STRING: - SetStringHandlers(proto2_f, r, upb_f, h); - return true; - case goog::FieldOptions::CORD: - SetCordHandlers(proto2_f, r, upb_f, h); - return true; - case goog::FieldOptions::STRING_PIECE: - SetStringPieceHandlers(proto2_f, r, upb_f, h); - return true; -#else - case UPB_CTYPE_STRING: - SetStringHandlers(proto2_f, r, upb_f, h); - return true; -#endif - default: - return false; - } - } - case goog::FieldDescriptor::CPPTYPE_MESSAGE: -#ifdef UPB_GOOGLE3 - if (proto2_f->options().lazy() && - // proto2 lets you set lazy=true on a repeated field, but doesn't - // actually support lazy repeated messages, so just ignore - // lazy=true for repeated messages. - !proto2_f->is_repeated()) { - // Supports lazy fields and lazy extensions. - SetLazyFieldHandlers(proto2_f, m, r, upb_f, h); - return true; - } -#endif - if (proto2_f->is_extension()) { - SetSubMessageExtensionHandlers(proto2_f, m, r, upb_f, h); - return true; - } - SetSubMessageHandlers(proto2_f, m, r, upb_f, h); - return true; - default: - return false; - } - } - -#undef PRIMITIVE_TYPE - - static const goog::Message* GetFieldPrototype( - const goog::Message& m, const goog::FieldDescriptor* f) { - // 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(). - // See file comment re: dynamic_cast. - const goog::internal::GeneratedMessageReflection* r = - dynamic_cast( - m.GetReflection()); - if (!r) return NULL; - return r->message_factory_->GetPrototype(f->message_type()); - } - - private: - static upb_selector_t GetSelector(const upb::FieldDef* f, - upb::Handlers::Type type) { - upb::Handlers::Selector selector; - bool ok = upb::Handlers::GetSelector(f, type, &selector); - UPB_ASSERT(ok); - return selector; - } - - static int64_t GetHasbit( - const goog::FieldDescriptor* f, - const goog::internal::GeneratedMessageReflection* r) { - // proto2 does not store hasbits for repeated fields. - UPB_ASSERT(!f->is_repeated()); - 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) { - UPB_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) { - 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]; - } - - // Base class that provides access to elements of the message as a whole, such - // as the unknown-field set, and is inherited by context classes for specific - // field handlers. - class FieldDataBase { - public: - FieldDataBase(const goog::internal::GeneratedMessageReflection* r) - : unknown_fields_offset_(r->unknown_fields_offset_) -#ifdef GOOGLE_PROTOBUF_HAS_ARENAS - , arena_offset_(r->arena_offset_) -#endif // GOOGLE_PROTOBUF_HAS_ARENAS - {} - -#ifdef GOOGLE_PROTOBUF_HAS_ARENAS - goog::Arena* GetArena(const goog::Message& message) const { - if (unknown_fields_offset_ == - goog::internal::GeneratedMessageReflection:: - kUnknownFieldSetInMetadata) { - const goog::internal::InternalMetadataWithArena* metadata = - GetConstPointer( - &message, arena_offset_); - return metadata->arena(); - } else if (arena_offset_ != - goog::internal::GeneratedMessageReflection::kNoArenaPointer) { - return *GetConstPointer(&message, arena_offset_); - } else { - return NULL; - } - } - - goog::UnknownFieldSet* GetUnknownFieldSet(goog::Message* message) const { - if (unknown_fields_offset_ == - goog::internal::GeneratedMessageReflection:: - kUnknownFieldSetInMetadata) { - goog::internal::InternalMetadataWithArena* metadata = - GetPointer( - message, arena_offset_); - return metadata->mutable_unknown_fields(); - } - return GetPointer(message, unknown_fields_offset_); - } -#else // ifdef GOOGLE_PROTOBUF_HAS_ARENAS - goog::UnknownFieldSet* GetUnknownFieldSet(goog::Message* message) const { - return GetPointer(message, unknown_fields_offset_); - } -#endif // ifdef !GOOGLE_PROTOBUF_HAS_ARENAS - private: - int unknown_fields_offset_; -#ifdef GOOGLE_PROTOBUF_HAS_ARENAS - int arena_offset_; -#endif // GOOGLE_PROTOBUF_HAS_ARENAS - }; - - class FieldOffset : public FieldDataBase { - public: - FieldOffset(const goog::FieldDescriptor* f, - const goog::internal::GeneratedMessageReflection* r) - : FieldDataBase(r), - offset_(GetOffset(f, r)), is_repeated_(f->is_repeated()) { - if (!is_repeated_) { - int64_t hasbit = GetHasbit(f, r); - hasbyte_ = hasbit / 8; - mask_ = 1 << (hasbit % 8); - } - } - - template T* GetFieldPointer(goog::Message* message) const { - return GetPointer(message, offset_); - } - - void SetHasbit(void* m) const { - UPB_ASSERT(!is_repeated_); - uint8_t* byte = GetPointer(m, hasbyte_); - *byte |= mask_; - } - - private: - const size_t offset_; - bool is_repeated_; - - // Only for non-repeated fields. - int32_t hasbyte_; - int8_t mask_; - }; - -#ifdef GOOGLE_PROTOBUF_HAS_ONEOF - class OneofFieldData : public FieldDataBase { - public: - OneofFieldData(const goog::FieldDescriptor* f, - const goog::internal::GeneratedMessageReflection* r) - : FieldDataBase(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_); - } - - void ClearOneof(goog::Message* m, const FieldOffset* ofs, - int field_number) const { -#ifdef GOOGLE_PROTOBUF_HAS_ARENAS - if (GetArena(*m) != NULL) { - return; - } -#endif - 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< - goog::internal::StringPieceField*>(m); - break; - case ONEOF_TYPE_LAZYFIELD: - delete *ofs->GetFieldPointer(m); - break; -#endif - } - } - - // 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 { - ClearOneof(m, ofs, *field_number); - *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: - UPB_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( - const goog::FieldDescriptor* proto2_f, - const goog::internal::GeneratedMessageReflection* r) - : offset_(r->extensions_offset_), - field_descriptor_(proto2_f) { - } - - int number() const { return field_descriptor_->number(); } - goog::internal::FieldType type() const { return field_descriptor_->type(); } - const goog::FieldDescriptor* field_descriptor() const { - return field_descriptor_; - } - - goog::internal::ExtensionSet* GetExtensionSet(goog::Message* m) const { - return GetPointer(m, offset_); - } - - private: - const size_t offset_; - // We know it will outlive because we require that the input message used to - // build these handlers outlives us, and the descriptor will outlive the - // message. - const goog::FieldDescriptor* field_descriptor_; - }; - - // StartSequence ///////////////////////////////////////////////////////////// - - template - static void SetStartRepeatedField( - const goog::FieldDescriptor* proto2_f, - const goog::internal::GeneratedMessageReflection* r, - const upb::FieldDef* f, upb::Handlers* h) { - CHKRET(h->SetStartSequenceHandler( - f, UpbBindT(&PushOffset >, - new FieldOffset(proto2_f, r)))); - } - - template - static void SetStartRepeatedPtrField( - const goog::FieldDescriptor* proto2_f, - const goog::internal::GeneratedMessageReflection* r, - const upb::FieldDef* f, upb::Handlers* h) { - CHKRET(h->SetStartSequenceHandler( - f, UpbBindT(&PushOffset >, - new FieldOffset(proto2_f, r)))); - } - - static void SetStartRepeatedSubmessageField( - const goog::FieldDescriptor* proto2_f, - const goog::internal::GeneratedMessageReflection* r, - const upb::FieldDef* f, upb::Handlers* h) { - CHKRET(h->SetStartSequenceHandler( - f, UpbBind(&PushOffset, - new FieldOffset(proto2_f, r)))); - } - - template - static T* PushOffset(goog::Message* message, const FieldOffset* offset) { - return offset->GetFieldPointer(message); - } - - // Primitive Value (numeric, bool) /////////////////////////////////////////// - - template static void SetPrimitiveHandlers( - const goog::FieldDescriptor* proto2_f, - const goog::internal::GeneratedMessageReflection* r, - const upb::FieldDef* f, upb::Handlers* h) { - if (proto2_f->is_extension()) { - scoped_ptr data(new ExtensionFieldData(proto2_f, r)); - if (f->IsSequence()) { - CHKRET(h->SetValueHandler( - f, UpbBindT(AppendPrimitiveExtension, data.release()))); - } else { - CHKRET(h->SetValueHandler( - f, UpbBindT(SetPrimitiveExtension, data.release()))); - } - } -#ifdef GOOGLE_PROTOBUF_HAS_ONEOF - else if (proto2_f->containing_oneof()) { - UPB_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))); - } else { - CHKRET(upb_msg_setscalarhandler(h, f, GetOffset(proto2_f, r), - GetHasbit(proto2_f, r))); - } - } - } - - template - static void AppendPrimitive(goog::RepeatedField* r, T val) { r->Add(val); } - - template - static void AppendPrimitiveExtension(goog::Message* m, - const ExtensionFieldData* data, T val) { - goog::internal::ExtensionSet* set = data->GetExtensionSet(m); - // TODO(haberman): give an accurate value for "packed" - goog::internal::RepeatedPrimitiveTypeTraits::Add( - data->number(), data->type(), true, val, set); - } - - template - static void SetPrimitiveExtension(goog::Message* m, - const ExtensionFieldData* data, T val) { - goog::internal::ExtensionSet* set = data->GetExtensionSet(m); - goog::internal::PrimitiveTypeTraits::Set(data->number(), data->type(), - 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 { - public: - EnumHandlerData(const goog::FieldDescriptor* proto2_f, - const goog::internal::GeneratedMessageReflection* r, - const upb::FieldDef* f) - : FieldOffset(proto2_f, r), - field_number_(f->number()), - enum_(upb_downcast_enumdef(f->subdef())) {} - - bool IsValidValue(int32_t val) const { - return enum_->FindValueByNumber(val) != NULL; - } - - int32_t field_number() const { return field_number_; } - - private: - int32_t field_number_; - const upb::EnumDef* enum_; - }; - - static void SetEnumHandlers( - const goog::FieldDescriptor* proto2_f, - const goog::internal::GeneratedMessageReflection* r, - const upb::FieldDef* f, upb::Handlers* h) { - UPB_ASSERT(!proto2_f->is_extension()); - scoped_ptr data(new EnumHandlerData(proto2_f, r, f)); - if (f->IsSequence()) { - CHKRET(h->SetInt32Handler(f, UpbBind(AppendEnum, data.release()))); - } else { - CHKRET(h->SetInt32Handler(f, UpbBind(SetEnum, data.release()))); - } - } - - static void SetEnum(goog::Message* m, const EnumHandlerData* data, - int32_t val) { - if (data->IsValidValue(val)) { - int32_t* message_val = data->GetFieldPointer(m); - *message_val = val; - data->SetHasbit(m); - } else { - data->GetUnknownFieldSet(m)->AddVarint(data->field_number(), val); - } - } - - static void AppendEnum(goog::Message* m, const EnumHandlerData* data, - int32_t val) { - // Closure is the enclosing message. We can't use the RepeatedField<> as - // the closure because we need to go back to the message for unrecognized - // enum values, which go into the unknown field set. - if (data->IsValidValue(val)) { - goog::RepeatedField* r = - data->GetFieldPointer >(m); - r->Add(val); - } else { - data->GetUnknownFieldSet(m)->AddVarint(data->field_number(), val); - } - } - - // EnumExtension ///////////////////////////////////////////////////////////// - - static void SetEnumExtensionHandlers( - const goog::FieldDescriptor* proto2_f, - const goog::internal::GeneratedMessageReflection* r, - const upb::FieldDef* f, upb::Handlers* h) { - UPB_ASSERT(proto2_f->is_extension()); - scoped_ptr data(new ExtensionFieldData(proto2_f, r)); - if (f->IsSequence()) { - CHKRET( - h->SetInt32Handler(f, UpbBind(AppendEnumExtension, data.release()))); - } else { - CHKRET(h->SetInt32Handler(f, UpbBind(SetEnumExtension, data.release()))); - } - } - - static void SetEnumExtension(goog::Message* m, const ExtensionFieldData* data, - int32_t val) { - goog::internal::ExtensionSet* set = data->GetExtensionSet(m); - set->SetEnum(data->number(), data->type(), val, NULL); - } - - static void AppendEnumExtension(goog::Message* m, - const ExtensionFieldData* data, int32_t val) { - goog::internal::ExtensionSet* set = data->GetExtensionSet(m); - // TODO(haberman): give an accurate value for "packed" - set->AddEnum(data->number(), data->type(), true, val, NULL); - } - - // String //////////////////////////////////////////////////////////////////// - - // For scalar (non-repeated) string fields. - template class StringHandlerData : public FieldOffset { - public: - StringHandlerData(const goog::FieldDescriptor* proto2_f, - const goog::internal::GeneratedMessageReflection* r) - : FieldOffset(proto2_f, r), - prototype_(*GetConstPointer(r->default_instance_, - GetOffset(proto2_f, r))) {} - - const T* prototype() const { return prototype_; } - - T** GetStringPointer(goog::Message* message) const { - return GetFieldPointer(message); - } - - private: - const T* prototype_; - }; - - template static void SetStringHandlers( - const goog::FieldDescriptor* proto2_f, - const goog::internal::GeneratedMessageReflection* r, - const upb::FieldDef* f, - upb::Handlers* h) { - UPB_ASSERT(!proto2_f->is_extension()); - CHKRET(h->SetStringHandler(f, UpbMakeHandlerT(&OnStringBuf))); -#ifdef GOOGLE_PROTOBUF_HAS_ONEOF - if (proto2_f->containing_oneof()) { - UPB_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))); - } else { - CHKRET(h->SetStartStringHandler( - f, UpbBindT(StartString, new StringHandlerData(proto2_f, r)))); - } - } - - // This needs to be templated because google3 string is not std::string. - template - static T* StartString(goog::Message* m, const StringHandlerData* data, - size_t size_hint) { - UPB_UNUSED(size_hint); - T** str = data->GetStringPointer(m); - data->SetHasbit(m); - // If it points to the default instance, we must create a new instance. - if (*str == data->prototype()) { - *str = new T(); -#ifdef GOOGLE_PROTOBUF_HAS_ARENAS - if (data->GetArena(*m)) { - data->GetArena(*m)->Own(*str); - } -#endif - } - (*str)->clear(); - // reserve() here appears to hurt performance rather than help. - return *str; - } - - template - static void OnStringBuf(T* str, const char* buf, size_t n) { - str->append(buf, n); - } - - template - static T* StartRepeatedString(goog::RepeatedPtrField* r, - size_t size_hint) { - UPB_UNUSED(size_hint); - T* str = r->Add(); - str->clear(); - // reserve() here appears to hurt performance rather than help. - return str; - } - -#ifdef GOOGLE_PROTOBUF_HAS_ONEOF - template - static T* StartOneofString(goog::Message* m, - const OneofFieldHandlerData* data, - size_t size_hint) { - UPB_UNUSED(size_hint); - const FieldOffset* ofs = data; - T** str = ofs->GetFieldPointer(m); - if (data->SetOneofHas(m)) { - *str = new T(); -#ifdef GOOGLE_PROTOBUF_HAS_ARENAS - // Note that in the main proto2-arenas implementation, the parsing code - // creates ArenaString instances for string field data, and the - // implementation later dynamically converts to ::string if a mutable - // version is requested. To keep complexity down in this binding, we - // create an ordinary string and allow the arena to own its destruction. - if (data->GetArena(*m) != NULL) { - data->GetArena(*m)->Own(*str); - } -#endif - } else { - (*str)->clear(); - } - return *str; - } -#endif - - // StringExtension /////////////////////////////////////////////////////////// - - template - static void SetStringExtensionHandlers( - const goog::FieldDescriptor* proto2_f, - const goog::internal::GeneratedMessageReflection* r, - const upb::FieldDef* f, upb::Handlers* h) { - UPB_ASSERT(proto2_f->is_extension()); - CHKRET(h->SetStringHandler(f, UpbMakeHandlerT(OnStringBuf))); - scoped_ptr data(new ExtensionFieldData(proto2_f, r)); - if (f->IsSequence()) { - CHKRET(h->SetStartStringHandler( - f, UpbBindT(StartRepeatedStringExtension, data.release()))); - } else { - CHKRET(h->SetStartStringHandler( - f, UpbBindT(StartStringExtension, data.release()))); - } - } - - // Templated because google3 is not std::string. - template - static T* StartStringExtension(goog::Message* m, - const ExtensionFieldData* data, - size_t size_hint) { - UPB_UNUSED(size_hint); - goog::internal::ExtensionSet* set = data->GetExtensionSet(m); - return set->MutableString(data->number(), data->type(), NULL); - } - - template - static T* StartRepeatedStringExtension(goog::Message* m, - const ExtensionFieldData* data, - size_t size_hint) { - UPB_UNUSED(size_hint); - goog::internal::ExtensionSet* set = data->GetExtensionSet(m); - return set->AddString(data->number(), data->type(), NULL); - } - - // SubMessage //////////////////////////////////////////////////////////////// - - class SubMessageHandlerData : public FieldOffset { - public: - SubMessageHandlerData(const goog::FieldDescriptor* f, - const goog::internal::GeneratedMessageReflection* r, - const goog::Message* prototype) - : FieldOffset(f, r), prototype_(prototype) {} - - const goog::Message* prototype() const { return prototype_; } - - private: - 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, - const upb::FieldDef* f, upb::Handlers* h) { - const goog::Message* field_prototype = GetFieldPrototype(m, proto2_f); - scoped_ptr data( - new SubMessageHandlerData(proto2_f, r, field_prototype)); -#ifdef GOOGLE_PROTOBUF_HAS_ONEOF - if (proto2_f->containing_oneof()) { - UPB_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()))); - } else { - CHKRET(h->SetStartSubMessageHandler( - f, UpbBind(StartSubMessage, data.release()))); - } - } - - static goog::Message* StartSubMessage(goog::Message* m, - const SubMessageHandlerData* data) { - data->SetHasbit(m); - goog::Message** subm = data->GetFieldPointer(m); - if (*subm == NULL || *subm == data->prototype()) { -#ifdef GOOGLE_PROTOBUF_HAS_ARENAS - *subm = data->prototype()->New(data->GetArena(*m)); -#else - *subm = data->prototype()->New(); -#endif - } - return *subm; - } - - class RepeatedMessageTypeHandler { - public: - typedef goog::Message Type; -#ifdef GOOGLE_PROTOBUF_HAS_ARENAS - static goog::Arena* GetArena(Type* t) { - return t->GetArena(); - } - static void* GetMaybeArenaPointer(Type* t) { - return t->GetMaybeArenaPointer(); - } - static inline Type* NewFromPrototype( - const Type* prototype, goog::Arena* arena = NULL) { - return prototype->New(arena); - } - static void Delete(Type* t, goog::Arena* arena = NULL) { - if (arena == NULL) { - delete t; - } - } -#else // ifdef GOOGLE_PROTOBUF_HAS_ARENAS - static inline Type* NewFromPrototype(const Type* prototype) { - return prototype->New(); - } - // AddAllocated() calls this, but only if other objects are sitting - // around waiting for reuse, which we will not do. - static void Delete(Type* t) { - UPB_UNUSED(t); - UPB_ASSERT(false); - } -#endif // ifdef GOOGLE_PROTOBUF_HAS_ARENAS - - static void Merge(const Type& from, Type* to) { - to->MergeFrom(from); - } - }; - - // Closure is a RepeatedPtrField*, but we access it through - // its base class RepeatedPtrFieldBase*. - static goog::Message* StartRepeatedSubMessage( - goog::internal::RepeatedPtrFieldBase* r, - const SubMessageHandlerData* data) { -#ifdef GOOGLE_PROTOBUF_HAS_ARENAS - return r->Add( - const_cast(data->prototype())); -#else - // This code path is required not because of arena-related API changes but - // because the variant of Add<>() that takes a prototype object was added - // only recently. Without the prototype, there's no way for Add<>() to - // create a new submessage with out typehandler implementation because we - // don't have New() (because we don't template-specialize our typehandler - // class on concrete message types). So we have to implement the runtime - // polymorphism externally (in this function) and then use AddAllocated to - // insert the pointer. - goog::Message* submsg = r->AddFromCleared(); - if (!submsg) { - submsg = data->prototype()->New(); - r->AddAllocated(submsg); - } - return submsg; -#endif - } - -#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)) { -#ifdef GOOGLE_PROTOBUF_HAS_ARENAS - *subm = data->prototype()->New(data->GetArena(*m)); -#else - *subm = data->prototype()->New(); -#endif - } - return *subm; - } -#endif - - // SubMessageExtension /////////////////////////////////////////////////////// - - class SubMessageExtensionHandlerData : public ExtensionFieldData { - public: - SubMessageExtensionHandlerData( - const goog::FieldDescriptor* proto2_f, - const goog::internal::GeneratedMessageReflection* r, - const goog::Message* prototype) - : ExtensionFieldData(proto2_f, r), - prototype_(prototype) { - } - - const goog::Message* prototype() const { return prototype_; } - - private: - const goog::Message* const prototype_; - }; - - static void SetSubMessageExtensionHandlers( - const goog::FieldDescriptor* proto2_f, - const goog::Message& m, - const goog::internal::GeneratedMessageReflection* r, - const upb::FieldDef* f, - upb::Handlers* h) { - const goog::Message* field_prototype = GetFieldPrototype(m, proto2_f); - scoped_ptr data( - new SubMessageExtensionHandlerData(proto2_f, r, field_prototype)); - if (f->IsSequence()) { - CHKRET(h->SetStartSubMessageHandler( - f, UpbBind(StartRepeatedSubMessageExtension, data.release()))); - } else { - CHKRET(h->SetStartSubMessageHandler( - f, UpbBind(StartSubMessageExtension, data.release()))); - } - } - - static goog::Message* StartRepeatedSubMessageExtension( - goog::Message* m, const SubMessageExtensionHandlerData* data) { - goog::internal::ExtensionSet* set = data->GetExtensionSet(m); - // Because we found this message via a descriptor, we know it has a - // descriptor and is therefore a Message and not a MessageLite. - // Alternatively we could just use goog::MessageLite everywhere to avoid - // this, but since they are in fact goog::Messages, it seems most clear - // to refer to them as such. - return CheckDownCast(set->AddMessage( - data->number(), data->type(), *data->prototype(), NULL)); - } - - static goog::Message* StartSubMessageExtension( - goog::Message* m, const SubMessageExtensionHandlerData* data) { - goog::internal::ExtensionSet* set = data->GetExtensionSet(m); - // See comment above re: this down cast. - return CheckDownCast(set->MutableMessage( - data->number(), data->type(), *data->prototype(), NULL)); - } - - // TODO(haberman): handle Unknown Fields. - -#ifdef UPB_GOOGLE3 - // Handlers for types/features only included in internal proto2 release: - // Cord, StringPiece, LazyField, and MessageSet. - // TODO(haberman): MessageSet. - - // Cord ////////////////////////////////////////////////////////////////////// - - static void AppendBufToCord(const char* buf, size_t n, - const upb::BufferHandle* handle, Cord* c) { - const Cord* source_cord = handle->GetAttachedObject(); - if (source_cord) { - // This TODO is copied from CordReader::CopyToCord(): - // "We could speed this up by using CordReader internals." - Cord piece(*source_cord); - piece.RemovePrefix(handle->object_offset() + (buf - handle->buffer())); - UPB_ASSERT(piece.size() >= n); - piece.RemoveSuffix(piece.size() - n); - - c->Append(piece); - } else { - c->Append(StringPiece(buf, n)); - } - } - - static void SetCordHandlers( - const proto2::FieldDescriptor* proto2_f, - const proto2::internal::GeneratedMessageReflection* r, - const upb::FieldDef* f, upb::Handlers* h) { - UPB_ASSERT(!proto2_f->is_extension()); - CHKRET(h->SetStringHandler(f, UpbMakeHandler(&OnCordBuf))); - if (f->IsSequence()) { - SetStartRepeatedField(proto2_f, r, f, h); - CHKRET(h->SetStartStringHandler(f, UpbMakeHandler(StartRepeatedCord))); - } else { - CHKRET(h->SetStartStringHandler( - f, UpbBind(StartCord, new FieldOffset(proto2_f, r)))); - } - } - - static Cord* StartCord(goog::Message* m, const FieldOffset* offset, - size_t size_hint) { - UPB_UNUSED(size_hint); - offset->SetHasbit(m); - Cord* field = offset->GetFieldPointer(m); - field->Clear(); - return field; - } - - static void OnCordBuf(Cord* c, const char* buf, size_t n, - const upb::BufferHandle* handle) { - AppendBufToCord(buf, n, handle, c); - } - - static Cord* StartRepeatedCord(proto2::RepeatedField* r, - size_t size_hint) { - UPB_UNUSED(size_hint); - return r->Add(); - } - - // StringPiece /////////////////////////////////////////////////////////////// - - static void SetStringPieceHandlers( - const proto2::FieldDescriptor* proto2_f, - const proto2::internal::GeneratedMessageReflection* r, - const upb::FieldDef* f, upb::Handlers* h) { - UPB_ASSERT(!proto2_f->is_extension()); - CHKRET(h->SetStringHandler(f, UpbMakeHandler(OnStringPieceBuf))); - if (f->IsSequence()) { - SetStartRepeatedPtrField(proto2_f, r, - f, h); - CHKRET(h->SetStartStringHandler( - f, UpbMakeHandler(StartRepeatedStringPiece))); - } else { - CHKRET(h->SetStartStringHandler( - f, UpbBind(StartStringPiece, new FieldOffset(proto2_f, r)))); - } - } - - static void OnStringPieceBuf(proto2::internal::StringPieceField* field, - const char* buf, size_t len) { - // 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. - size_t new_len = field->size() + len; - char* data = new char[new_len]; - memcpy(data, field->data(), field->size()); - memcpy(data + field->size(), buf, len); - field->CopyFrom(StringPiece(data, new_len)); - delete[] data; - } - - static proto2::internal::StringPieceField* StartStringPiece( - goog::Message* m, const FieldOffset* offset, size_t size_hint) { - UPB_UNUSED(size_hint); - offset->SetHasbit(m); - proto2::internal::StringPieceField* field = - offset->GetFieldPointer(m); - field->Clear(); - return field; - } - - static proto2::internal::StringPieceField* StartRepeatedStringPiece( - proto2::RepeatedPtrField* r, - size_t size_hint) { - UPB_UNUSED(size_hint); - proto2::internal::StringPieceField* field = r->Add(); - field->Clear(); - return field; - } - - // LazyField ///////////////////////////////////////////////////////////////// - - // For lazy fields we set both lazy and eager handlers. The user can - // configure the data source to call either, though lazy handlers may only be - // used when the source data is binary protobuf. - static void SetLazyFieldHandlers( - const proto2::FieldDescriptor* proto2_f, - const proto2::Message& m, - const proto2::internal::GeneratedMessageReflection* r, - const upb::FieldDef* f, upb::Handlers* h) { - UPB_ASSERT(!proto2_f->is_repeated()); - const goog::Message* field_prototype = GetFieldPrototype(m, proto2_f); - CHKRET(h->SetStringHandler(f, UpbMakeHandler(OnLazyFieldBuf))); - if (proto2_f->is_extension()) { - CHKRET(h->SetStartStringHandler( - f, UpbBind(StartLazyExtension, new ExtensionFieldData(proto2_f, r)))); - CHKRET(h->SetStartSubMessageHandler( - f, UpbBind(StartSubMessageExtension, - new SubMessageExtensionHandlerData(proto2_f, r, - field_prototype)))); - } else { - CHKRET(h->SetStartStringHandler( - f, UpbBind(StartLazyField, new FieldOffset(proto2_f, r)))); - CHKRET(h->SetStartSubMessageHandler( - f, UpbBind(StartLazyFieldEager, - new SubMessageHandlerData(proto2_f, r, field_prototype)))); - } - } - - static proto2::internal::LazyField* StartLazyField(proto2::Message* m, - const FieldOffset* offset, - size_t size_hint) { - UPB_UNUSED(size_hint); - offset->SetHasbit(m); - proto2::internal::LazyField* field = - offset->GetFieldPointer(m); - field->Clear(); - return field; - } - - // For when the field has a lazy representation but we parse it eagerly anyway - // (either because we want to or because we're parsing from a format other - // than binary protobuf). - static proto2::Message* StartLazyFieldEager( - proto2::Message* m, const SubMessageHandlerData* data) { - data->SetHasbit(m); - proto2::internal::LazyField* field = - data->GetFieldPointer(m); - return field->MutableByPrototype(*data->prototype()); - } - - class LazyMessageExtensionImpl - : public proto2::internal::ExtensionSet::LazyMessageExtension { - public: - LazyMessageExtensionImpl() {} - virtual ~LazyMessageExtensionImpl() {} - -#ifdef GOOGLE_PROTOBUF_HAS_ARENAS - virtual LazyMessageExtension* New() const { - return New(NULL); - } - - virtual LazyMessageExtension* New(proto2::Arena* arena) const { - LazyMessageExtensionImpl* message = - ::proto2::Arena::Create(arena); - return message; - } -#else // ifdef GOOGLE_PROTOBUF_HAS_ARENAS - virtual LazyMessageExtension* New() const { - return new LazyMessageExtensionImpl(); - } -#endif // ifdef GOOGLE_PROTOBUF_HAS_ARENAS - - virtual const proto2::MessageLite& GetMessage( - const proto2::MessageLite& prototype) const { - return lazy_field_.GetByPrototype( - static_cast(prototype)); - } - - virtual proto2::MessageLite* MutableMessage( - const proto2::MessageLite& prototype) { - return lazy_field_.MutableByPrototype( - static_cast(prototype)); - } - - virtual void SetAllocatedMessage(proto2::MessageLite* message) { - return lazy_field_.SetAllocated(static_cast(message)); - } - - virtual void UnsafeArenaSetAllocatedMessage(proto2::MessageLite* message) { - return lazy_field_.UnsafeArenaSetAllocated( - static_cast(message)); - } - - virtual proto2::MessageLite* ReleaseMessage( - const proto2::MessageLite& prototype) { - return lazy_field_.ReleaseByPrototype( - static_cast(prototype)); - } - - virtual proto2::MessageLite* UnsafeArenaReleaseMessage( - const proto2::MessageLite& prototype) { - return lazy_field_.UnsafeArenaReleaseByPrototype( - static_cast(prototype)); - } - - virtual bool IsInitialized() const { return true; } - - virtual int ByteSize() const { return lazy_field_.MessageByteSize(); } - - int SpaceUsed() const { - return sizeof(*this) + lazy_field_.SpaceUsedExcludingSelf(); - } - - virtual void MergeFrom(const LazyMessageExtension& other) { - MergeFrom(*static_cast(&other)); - } - - virtual void MergeFrom(const LazyMessageExtensionImpl& other) { - lazy_field_.MergeFrom(other.lazy_field_); - } - - virtual void Clear() { lazy_field_.Clear(); } - - virtual bool ReadMessage(const proto2::MessageLite& prototype, - proto2::io::CodedInputStream* input) { - return lazy_field_.Read(input); - } - - virtual void WriteMessage(int number, - proto2::io::CodedOutputStream* output) const { - lazy_field_.Write(number, output); - } - - virtual uint8* WriteMessageToArray(int number, uint8* target) const { - return lazy_field_.WriteToArray(number, target); - } - - proto2::internal::LazyField& lazy_field() { return lazy_field_; } - - private: - proto2::internal::LazyField lazy_field_; - DISALLOW_COPY_AND_ASSIGN(LazyMessageExtensionImpl); - }; - - static proto2::internal::LazyField* StartLazyExtension( - proto2::Message* m, const ExtensionFieldData* data, size_t size_hint) { - proto2::internal::ExtensionSet* set = data->GetExtensionSet(m); - - // We have to break encapsulation here since no public accessors expose the - // LazyField. - // - // TODO(haberman): add a function to ExtensionSet that allows us to set the - // lazy field directly. - proto2::internal::ExtensionSet::Extension* item; - LazyMessageExtensionImpl* lazy_extension; - if (set->MaybeNewExtension(data->number(), data->field_descriptor(), - &item)) { -#ifdef GOOGLE_PROTOBUF_HAS_ARENAS - lazy_extension = - ::proto2::Arena::Create( - m->GetArena()); -#else - lazy_extension = new LazyMessageExtensionImpl(); -#endif - item->type = UPB_DESCRIPTOR_TYPE_MESSAGE; - item->is_repeated = false; - item->is_lazy = true; - item->lazymessage_value = lazy_extension; - } else { - lazy_extension = - CheckDownCast(item->lazymessage_value); - } - - item->is_cleared = false; - - return &lazy_extension->lazy_field(); - } - - static void OnLazyFieldBuf(proto2::internal::LazyField* field, - const char* buf, size_t len, - const upb::BufferHandle* handle) { - Cord encoded(field->GetEncoded()); - AppendBufToCord(buf, len, handle, &encoded); - field->SetEncoded(encoded); - } - -#endif // UPB_GOOGLE3 -}; - -namespace upb { -namespace googlepb { - -bool TrySetWriteHandlers(const goog::FieldDescriptor* proto2_f, - const goog::Message& prototype, - const upb::FieldDef* upb_f, upb::Handlers* h) { - return me::GMR_Handlers::TrySet(proto2_f, prototype, upb_f, h); -} - -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 googlepb -} // namespace upb diff --git a/upb/bindings/googlepb/proto2.int.h b/upb/bindings/googlepb/proto2.int.h deleted file mode 100644 index 4f45efb..0000000 --- a/upb/bindings/googlepb/proto2.int.h +++ /dev/null @@ -1,53 +0,0 @@ -// 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_ diff --git a/upb/bindings/linux/Makefile b/upb/bindings/linux/Makefile deleted file mode 100644 index 1736b61..0000000 --- a/upb/bindings/linux/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -obj-m = upb.o - -upb-objs = \ - ../../upb/upb.o \ - ../../upb/bytestream.o \ - ../../upb/def.o \ - ../../upb/handlers.o \ - ../../upb/table.o \ - ../../upb/refcount.o \ - ../../upb/msg.o \ - -KVERSION = $(shell uname -r) - -ccflags-y := -I$(PWD) -I$(PWD)/../.. -Wno-declaration-after-statement -std=gnu99 - -all: - make -C /lib/modules/$(KVERSION)/build M=$(PWD) modules - -clean: - make -C /lib/modules/$(KVERSION)/build M=$(PWD) clean diff --git a/upb/bindings/linux/assert.h b/upb/bindings/linux/assert.h deleted file mode 100644 index 543f7fb..0000000 --- a/upb/bindings/linux/assert.h +++ /dev/null @@ -1,14 +0,0 @@ - -#include - -#ifndef UPB_LINUX_ASSERT_H -#define UPB_LINUX_ASSERT_H - -#ifdef NDEBUG -#define assert(x) -#else -#define assert(x) \ - if (!(x)) panic("Assertion failed: %s at %s:%d", #x, __FILE__, __LINE__); -#endif - -#endif diff --git a/upb/bindings/linux/errno.h b/upb/bindings/linux/errno.h deleted file mode 100644 index d6c56bc..0000000 --- a/upb/bindings/linux/errno.h +++ /dev/null @@ -1,2 +0,0 @@ - -#include diff --git a/upb/bindings/linux/stdint.h b/upb/bindings/linux/stdint.h deleted file mode 100644 index 2aa5144..0000000 --- a/upb/bindings/linux/stdint.h +++ /dev/null @@ -1,2 +0,0 @@ - -#include diff --git a/upb/bindings/linux/stdio.h b/upb/bindings/linux/stdio.h deleted file mode 100644 index dd22e5b..0000000 --- a/upb/bindings/linux/stdio.h +++ /dev/null @@ -1,2 +0,0 @@ - -#include // For sprintf and friends. diff --git a/upb/bindings/linux/stdlib.h b/upb/bindings/linux/stdlib.h deleted file mode 100644 index 5ae6742..0000000 --- a/upb/bindings/linux/stdlib.h +++ /dev/null @@ -1,17 +0,0 @@ -/* -** Linux-kernel implementations of some stdlib.h functions. -*/ - -#include - -#ifndef UPB_LINUX_STDLIB_H -#define UPB_LINUX_STDLIB_H - -static inline void *malloc(size_t size) { return kmalloc(size, GFP_ATOMIC); } -static inline void free(void *p) { kfree(p); } - -static inline void *realloc(void *p, size_t size) { - return krealloc(p, size, GFP_ATOMIC); -} - -#endif diff --git a/upb/bindings/linux/string.h b/upb/bindings/linux/string.h deleted file mode 100644 index 9cfd9b3..0000000 --- a/upb/bindings/linux/string.h +++ /dev/null @@ -1,7 +0,0 @@ - -#ifndef UPB_LINUX_STRING_H_ -#define UPB_LINUX_STRING_H_ - -#include - -#endif /* UPB_DEF_H_ */ diff --git a/upb/bindings/python/setup.py b/upb/bindings/python/setup.py deleted file mode 100644 index 8abaff8..0000000 --- a/upb/bindings/python/setup.py +++ /dev/null @@ -1,14 +0,0 @@ -from distutils.core import setup, Extension - -setup(name='upb', - version='0.1', - ext_modules=[ - Extension('upb.__init__', ['upb.c'], - include_dirs=['../../'], - define_macros=[("UPB_UNALIGNED_READS_OK", 1)], - library_dirs=['../../upb'], - libraries=['upb_pic'], - ), - ], - packages=['upb'] - ) diff --git a/upb/bindings/python/test.py b/upb/bindings/python/test.py deleted file mode 100644 index 29a6c45..0000000 --- a/upb/bindings/python/test.py +++ /dev/null @@ -1,72 +0,0 @@ - -import upb -import unittest - -class TestFieldDef(unittest.TestCase): - def test_construction(self): - fielddef1 = upb.FieldDef() - self.assertTrue(fielddef1.number is None) - self.assertTrue(fielddef1.name is None) - self.assertTrue(fielddef1.type is None) - self.assertEqual(fielddef1.label, upb.LABEL_OPTIONAL) - - fielddef2 = upb.FieldDef(number=5, name="field2", - label=upb.LABEL_REQUIRED, type=upb.TYPE_INT32, - type_name="MyType") - - self.assertTrue(id(fielddef1) != id(fielddef2)) - self.assertEqual(fielddef2.number, 5) - self.assertEqual(fielddef2.name, "field2") - self.assertEqual(fielddef2.label, upb.LABEL_REQUIRED) - self.assertEqual(fielddef2.type, upb.TYPE_INT32) - self.assertEqual(fielddef2.type_name, "MyType") - - fielddef2.number = 8 - self.assertEqual(fielddef2.number, 8) - - fielddef2.name = "xxx" - self.assertEqual(fielddef2.name, "xxx") - - fielddef2.label = upb.LABEL_REPEATED - self.assertEqual(fielddef2.label, upb.LABEL_REPEATED) - - fielddef2.type = upb.TYPE_FLOAT - self.assertEqual(fielddef2.type, upb.TYPE_FLOAT) - - def test_nosubclasses(self): - def create_subclass(): - class MyClass(upb.FieldDef): - pass - - self.assertRaises(TypeError, create_subclass) - - # TODO: test that assigning invalid values is properly prevented. - -class TestMessageDef(unittest.TestCase): - def test_construction(self): - msgdef1 = upb.MessageDef() - self.assertTrue(msgdef1.fqname is None) - self.assertEqual(msgdef1.fields(), []) - - fields = [upb.FieldDef(number=1, name="field1", type=upb.TYPE_INT32)] - msgdef2 = upb.MessageDef(fqname="Message2", fields=fields) - - self.assertEqual(set(msgdef2.fields()), set(fields)) - - f2 = upb.FieldDef(number=2, name="field2", type=upb.TYPE_INT64) - msgdef2.add_field(f2) - - fields.append(f2) - self.assertEqual(set(msgdef2.fields()), set(fields)) - -class TestSymbolTable(unittest.TestCase): - def test_construction(self): - s = upb.SymbolTable() - self.assertEqual(s.defs(), []); - - s.add_def(upb.MessageDef(fqname="A")) - self.assertTrue(s.lookup("A") is not None) - self.assertTrue(s.lookup("A") is s.lookup("A")) - -if __name__ == '__main__': - unittest.main() diff --git a/upb/bindings/python/upb.c b/upb/bindings/python/upb.c deleted file mode 100644 index 1646acc..0000000 --- a/upb/bindings/python/upb.c +++ /dev/null @@ -1,732 +0,0 @@ -/* -** Python extension exposing the core of upb: definitions, handlers, -** and a message type. -**/ - -#include -#include -#include "upb/def.h" -#include "upb/msg.h" - -static bool streql(const char *a, const char *b) { return strcmp(a, b) == 0; } - -PyObject *PyUpb_Error(const char *str) { - PyErr_SetString(PyExc_TypeError, str); - return NULL; -} - -int PyUpb_ErrorInt(const char *str) { - PyErr_SetString(PyExc_TypeError, str); - return -1; -} - -#define PyUpb_CheckStatus(status) \ - if (!upb_ok(status)) return PyUpb_Error((status)->str); - -static upb_accessor_vtbl *PyUpb_AccessorForField(upb_fielddef *f); - - -/* Object cache ***************************************************************/ - -// For objects that are just wrappers around a C object pointer, we keep a -// cache mapping C pointer -> wrapper object. This allows us to consistently -// vend the same Python object given the same C object. This prevents us from -// creating too many Python objects unnecessarily. Just as importantly, it -// provides the expected semantics: -// -// if field.subdef is field.subdef: -// print "Sanity prevails." -// -// If we conjured up a new wrapper object every time, the above would not be -// true. -// -// The cost is having to put all such objects in a table, but since this only -// applies to schema-level objects (defs, handlers, etc) this seems acceptable. -// We do *not* have to put all message objects in this table. -// -// We use weak refs so that the cache does not prevent the wrapper objects from -// being collected. The table is stored as a static variable; to use -// sub-interpreters this would need to change, but I believe that using -// sub-interpreters is exceedingly rare in practice. - -typedef struct { - PyObject_HEAD; - void *obj; - PyObject *weakreflist; -} PyUpb_ObjWrapper; - -static PyObject *obj_cache = NULL; -static PyObject *reverse_cache = NULL; -static PyObject *weakref_callback = NULL; - -// Utility functions for manipulating Python dictionaries keyed by pointer. - -static PyObject *PyUpb_StringForPointer(const void *ptr) { - PyObject *o = PyString_FromStringAndSize((const char *)&ptr, sizeof(void*)); - UPB_ASSERT(o); - return o; -} - -static PyObject *PyUpb_ObjCacheDeleteCallback(PyObject *self, PyObject *ref) { - // Python very unfortunately clears the weakref before running our callback. - // This prevents us from using the weakref to find the C pointer we need to - // remove from the cache. As a result we are forced to keep a second map - // mapping weakref->C pointer. - PyObject *ptr_str = PyDict_GetItem(reverse_cache, ref); - UPB_ASSERT(ptr_str); - int err = PyDict_DelItem(obj_cache, ptr_str); - UPB_ASSERT(!err); - err = PyDict_DelItem(reverse_cache, ref); - UPB_ASSERT(!err); - return Py_None; -} - -static PyObject *PyUpb_ObjCacheGet(const void *obj, PyTypeObject *type) { - PyObject *kv = PyUpb_StringForPointer(obj); - PyObject *ref = PyDict_GetItem(obj_cache, kv); - PyObject *ret; - if (ref) { - ret = PyWeakref_GetObject(ref); - UPB_ASSERT(ret != Py_None); - Py_INCREF(ret); - } else { - PyUpb_ObjWrapper *wrapper = (PyUpb_ObjWrapper*)type->tp_alloc(type, 0); - wrapper->obj = (void*)obj; - wrapper->weakreflist = NULL; - ret = (PyObject*)wrapper; - ref = PyWeakref_NewRef(ret, weakref_callback); - UPB_ASSERT(PyWeakref_GetObject(ref) == ret); - UPB_ASSERT(ref); - PyDict_SetItem(obj_cache, kv, ref); - PyDict_SetItem(reverse_cache, ref, kv); - } - UPB_ASSERT(ret); - Py_DECREF(kv); - return ret; -} - - -/* PyUpb_Def ******************************************************************/ - -static PyTypeObject *PyUpb_TypeForDef(const upb_def *def); - -static void PyUpb_Def_dealloc(PyObject *obj) { - PyUpb_ObjWrapper *wrapper = (void*)obj; - upb_def_unref((upb_def*)wrapper->obj); - obj->ob_type->tp_free(obj); -} - -PyObject *PyUpb_Def_GetOrCreate(const upb_def *def) { - return def ? PyUpb_ObjCacheGet(def, PyUpb_TypeForDef(def)) : Py_None; -} - -// Will need to expand once other kinds of defs are supported. -#define Check_Def(o, badret) Check_MessageDef(o, badret) - - -/* PyUpb_FieldDef *************************************************************/ - -static PyTypeObject PyUpb_FieldDefType; -static int PyUpb_FieldDef_setattro(PyObject *o, PyObject *key, PyObject *val); - -#define Check_FieldDef(o, badret) \ - (void*)(((PyUpb_ObjWrapper*)o)->obj); do { \ - if(!PyObject_TypeCheck(o, &PyUpb_FieldDefType)) { \ - PyErr_SetString(PyExc_TypeError, "must be a upb.FieldDef"); \ - return badret; \ - } \ - } while(0) - -static PyObject *PyUpb_FieldDef_GetOrCreate(const upb_fielddef *f) { - return PyUpb_ObjCacheGet(f, &PyUpb_FieldDefType); -} - -static PyObject *PyUpb_FieldDef_new(PyTypeObject *subtype, - PyObject *args, PyObject *kwds) { - return PyUpb_ObjCacheGet(upb_fielddef_new(), subtype); -} - -static int PyUpb_FieldDef_init(PyObject *self, PyObject *args, PyObject *kwds) { - if (!kwds) return 0; - PyObject *key, *value; - Py_ssize_t pos = 0; - while (PyDict_Next(kwds, &pos, &key, &value)) - PyUpb_FieldDef_setattro(self, key, value); - return 0; -} - -static void PyUpb_FieldDef_dealloc(PyObject *obj) { - PyUpb_ObjWrapper *wrapper = (void*)obj; - if (wrapper->weakreflist) PyObject_ClearWeakRefs(obj); - upb_fielddef_unref((upb_fielddef*)wrapper->obj); - obj->ob_type->tp_free(obj); -} - -static PyObject *PyUpb_FieldDef_getattro(PyObject *obj, PyObject *attr_name) { - upb_fielddef *f = Check_FieldDef(obj, NULL); - if (!upb_fielddef_ismutable(f)) { - PyErr_SetString(PyExc_TypeError, "fielddef is not mutable."); - return NULL; - } - const char *name = PyString_AsString(attr_name); - if (streql(name, "name")) { - const char *name = upb_fielddef_name(f); - return name == NULL ? Py_None : PyString_FromString(name); - } else if (streql(name, "number")) { - uint32_t num = upb_fielddef_number(f); - return num == 0 ? Py_None : PyInt_FromLong(num); - } else if (streql(name, "type")) { - uint8_t type = upb_fielddef_type(f); - return type == 0 ? Py_None : PyInt_FromLong(type); - } else if (streql(name, "label")) { - return PyInt_FromLong(upb_fielddef_label(f)); - } else if (streql(name, "type_name")) { - const char *name = upb_fielddef_typename(f); - return name == NULL ? Py_None : PyString_FromString(name); - } else if (streql(name, "subdef")) { - // NYI; - return NULL; - } else if (streql(name, "msgdef")) { - // NYI; - return NULL; - } else { - return PyUpb_Error("Invalid fielddef member."); - } -} - -static int PyUpb_FieldDef_setattro(PyObject *o, PyObject *key, PyObject *val) { - upb_fielddef *f = Check_FieldDef(o, -1); - const char *field = PyString_AsString(key); - if (!upb_fielddef_ismutable(f)) - return PyUpb_ErrorInt("fielddef is not mutable."); - if (streql(field, "name")) { - const char *name = PyString_AsString(val); - if (!name || !upb_fielddef_setname(f, name)) - return PyUpb_ErrorInt("Invalid name"); - } else if (streql(field, "number")) { - // TODO: should check truncation. Non-security issue. - // Non-int will return -1, which is already invalid as a field number. - if (!upb_fielddef_setnumber(f, PyInt_AsLong(val))) - return PyUpb_ErrorInt("Invalid number"); - } else if (streql(field, "type")) { - // TODO: should check truncation. Non-security issue. - if (!upb_fielddef_settype(f, PyInt_AsLong(val))) - return PyUpb_ErrorInt("Invalid type"); - } else if (streql(field, "label")) { - // TODO: should check truncation. Non-security issue. - if (!upb_fielddef_setlabel(f, PyInt_AsLong(val))) - return PyUpb_ErrorInt("Invalid label"); - } else if (streql(field, "type_name")) { - const char *name = PyString_AsString(val); - if (!name || !upb_fielddef_settypename(f, name)) - return PyUpb_ErrorInt("Invalid type_name"); - } else if (streql(field, "default_value")) { - // NYI - return -1; - } else { - return PyUpb_ErrorInt("Invalid fielddef member."); - } - return 0; -} - -static PyTypeObject PyUpb_FieldDefType = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - "upb.FieldDef", /* tp_name */ - sizeof(PyUpb_ObjWrapper), /* tp_basicsize */ - 0, /* tp_itemsize */ - &PyUpb_FieldDef_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* TODO */ /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - &PyUpb_FieldDef_getattro, /* tp_getattro */ - &PyUpb_FieldDef_setattro, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(PyUpb_ObjWrapper, weakreflist),/* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - &PyUpb_FieldDef_init, /* tp_init */ - 0, /* tp_alloc */ - &PyUpb_FieldDef_new, /* tp_new */ - 0, /* tp_free */ -}; - - -/* PyUpb_MessageDef ***********************************************************/ - -static PyTypeObject PyUpb_MessageDefType; -static int PyUpb_MessageDef_setattro(PyObject *o, PyObject *key, PyObject *val); - -#define Check_MessageDef(o, badret) \ - (void*)(((PyUpb_ObjWrapper*)o)->obj); do { \ - if(!PyObject_TypeCheck(o, &PyUpb_MessageDefType)) { \ - PyErr_SetString(PyExc_TypeError, "must be a upb.MessageDef"); \ - return badret; \ - } \ - } while(0) - -static PyObject *PyUpb_MessageDef_new(PyTypeObject *subtype, - PyObject *args, PyObject *kwds) { - return PyUpb_ObjCacheGet(upb_msgdef_new(), subtype); -} - -static PyObject *PyUpb_MessageDef_add_fields(PyObject *o, PyObject *args); - -static int PyUpb_MessageDef_init( - PyObject *self, PyObject *args, PyObject *kwds) { - if (!kwds) return 0; - PyObject *key, *value; - Py_ssize_t pos = 0; - while (PyDict_Next(kwds, &pos, &key, &value)) { - const char *field = PyString_AsString(key); - if (streql(field, "fields")) { - PyUpb_MessageDef_add_fields(self, value); - } else { - PyUpb_MessageDef_setattro(self, key, value); - } - } - return 0; -} - -static PyObject *PyUpb_MessageDef_getattro(PyObject *obj, PyObject *attr_name) { - upb_msgdef *m = Check_MessageDef(obj, NULL); - const char *name = PyString_AsString(attr_name); - if (streql(name, "fqname")) { - const char *fqname = upb_def_fqname(UPB_UPCAST(m)); - return fqname == NULL ? Py_None : PyString_FromString(fqname); - } - return PyObject_GenericGetAttr(obj, attr_name); -} - -static int PyUpb_MessageDef_setattro( - PyObject *o, PyObject *key, PyObject *val) { - upb_msgdef *m = Check_MessageDef(o, -1); - if (!upb_def_ismutable(UPB_UPCAST(m))) { - PyErr_SetString(PyExc_TypeError, "MessageDef is not mutable."); - return -1; - } - const char *name = PyString_AsString(key); - if (streql(name, "fqname")) { - const char *fqname = PyString_AsString(val); - if (!fqname || !upb_def_setfqname(UPB_UPCAST(m), fqname)) - return PyUpb_ErrorInt("Invalid fqname"); - } else { - return PyUpb_ErrorInt("Invalid MessageDef member."); - } - return 0; -} - -static PyObject *PyUpb_MessageDef_fields(PyObject *obj, PyObject *args) { - upb_msgdef *m = Check_MessageDef(obj, NULL); - PyObject *ret = PyList_New(0); - upb_msg_field_iter i; - for(upb_msg_field_begin(&i, m); - !upb_msg_field_done(&i); - upb_msg_field_next(&ii)) { - upb_fielddef *f = upb_msg_iter_field(&i); - PyList_Append(ret, PyUpb_FieldDef_GetOrCreate(f)); - } - return ret; -} - -static PyObject *PyUpb_MessageDef_add_fields(PyObject *o, PyObject *fields) { - upb_msgdef *m = Check_MessageDef(o, NULL); - if (!PySequence_Check(fields)) return PyUpb_Error("Must be a sequence"); - Py_ssize_t len = PySequence_Length(fields); - if (len > UPB_MAX_FIELDS) return PyUpb_Error("Too many fields."); - upb_fielddef *f[len]; - int i; - for (i = 0; i < len; i++) { - PyObject *field = PySequence_GetItem(fields, i); - f[i] = Check_FieldDef(field, NULL); - } - upb_msgdef_addfields(m, f, len); - return Py_None; -} - -static PyObject *PyUpb_MessageDef_add_field(PyObject *o, PyObject *field) { - upb_msgdef *m = Check_MessageDef(o, NULL); - upb_fielddef *f = Check_FieldDef(field, NULL); - upb_msgdef_addfield(m, f); - return Py_None; -} - -static PyMethodDef PyUpb_MessageDef_methods[] = { - {"add_field", &PyUpb_MessageDef_add_field, METH_O, - "Adds a list of fields."}, - {"add_fields", &PyUpb_MessageDef_add_fields, METH_O, - "Adds a list of fields."}, - {"fields", &PyUpb_MessageDef_fields, METH_NOARGS, - "Returns list of fields."}, - {NULL, NULL} -}; - -static PyTypeObject PyUpb_MessageDefType = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - "upb.MessageDef", /* tp_name */ - sizeof(PyUpb_ObjWrapper), /* tp_basicsize */ - 0, /* tp_itemsize */ - &PyUpb_Def_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* TODO */ /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - &PyUpb_MessageDef_getattro, /* tp_getattro */ - &PyUpb_MessageDef_setattro, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(PyUpb_ObjWrapper, weakreflist),/* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - PyUpb_MessageDef_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - &PyUpb_MessageDef_init, /* tp_init */ - 0, /* tp_alloc */ - &PyUpb_MessageDef_new, /* tp_new */ - 0, /* tp_free */ -}; - - -static PyTypeObject *PyUpb_TypeForDef(const upb_def *def) { - switch(def->type) { - case UPB_DEF_MSG: return &PyUpb_MessageDefType; - default: return NULL; - } -} - -/* PyUpb_SymbolTable **********************************************************/ - -static PyTypeObject PyUpb_SymbolTableType; - -#define Check_SymbolTable(o, badret) \ - (void*)(((PyUpb_ObjWrapper*)o)->obj); do { \ - if(!PyObject_TypeCheck(o, &PyUpb_SymbolTableType)) { \ - PyErr_SetString(PyExc_TypeError, "must be a upb.MessageDef"); \ - return badret; \ - } \ - } while(0) - -static PyObject *PyUpb_SymbolTable_new(PyTypeObject *subtype, - PyObject *args, PyObject *kwds) { - return PyUpb_ObjCacheGet(upb_symtab_new(), subtype); -} - -static int PyUpb_SymbolTable_init( - PyObject *self, PyObject *args, PyObject *kwds) { - return 0; -} - -static void PyUpb_SymbolTable_dealloc(PyObject *obj) { - PyUpb_ObjWrapper *wrapper = (void*)obj; - upb_symtab_unref((upb_symtab*)wrapper->obj); - obj->ob_type->tp_free(obj); -} - -// narg is a lua table containing a list of defs to add. -static PyObject *PyUpb_SymbolTable_add_defs(PyObject *o, PyObject *defs) { - upb_symtab *s = Check_SymbolTable(o, NULL); - if (!PySequence_Check(defs)) return PyUpb_Error("Must be a sequence"); - Py_ssize_t n = PySequence_Length(defs); - - // Prevent stack overflow. - if (n > 2048) return PyUpb_Error("Too many defs"); - upb_def *cdefs[n]; - - int i = 0; - for (i = 0; i < n; i++) { - PyObject *pydef = PySequence_GetItem(defs, i); - upb_def *def = Check_MessageDef(pydef, NULL); - cdefs[i++] = def; - upb_msgdef *md = upb_dyncast_msgdef(def); - if (!md) continue; - upb_msg_field_iter j; - for(upb_msg_field_begin(&j, md); - !upb_msg_field_done(&j); - upb_msg_field_next(&j)) { - upb_fielddef *f = upb_msg_iter_field(j); - upb_fielddef_setaccessor(f, PyUpb_AccessorForField(f)); - } - upb_msgdef_layout(md); - } - - upb_status status = UPB_STATUS_INIT; - upb_symtab_add(s, cdefs, n, &status); - PyUpb_CheckStatus(&status); - return Py_None; -} - -static PyObject *PyUpb_SymbolTable_add_def(PyObject *o, PyObject *def) { - PyObject *defs = PyList_New(1); - PyList_SetItem(defs, 0, def); - return PyUpb_SymbolTable_add_defs(o, defs); -} - -// TODO: update to allow user to choose type of defs. -static PyObject *PyUpb_SymbolTable_defs(PyObject *o, PyObject *none) { - upb_symtab *s = Check_SymbolTable(o, NULL); - int count; - const upb_def **defs = upb_symtab_getdefs(s, &count, UPB_DEF_ANY); - PyObject *ret = PyList_New(count); - int i; - for(i = 0; i < count; i++) - PyList_SetItem(ret, i, PyUpb_Def_GetOrCreate(defs[i])); - return ret; -} - -static PyObject *PyUpb_SymbolTable_lookup(PyObject *o, PyObject *arg) { - upb_symtab *s = Check_SymbolTable(o, NULL); - const char *name = PyString_AsString(arg); - const upb_def *def = upb_symtab_lookup(s, name); - return PyUpb_Def_GetOrCreate(def); -} - -static PyMethodDef PyUpb_SymbolTable_methods[] = { - {"add_def", &PyUpb_SymbolTable_add_def, METH_O, NULL}, - {"add_defs", &PyUpb_SymbolTable_add_defs, METH_O, NULL}, - {"defs", &PyUpb_SymbolTable_defs, METH_NOARGS, NULL}, - {"lookup", &PyUpb_SymbolTable_lookup, METH_O, NULL}, - {NULL, NULL} -}; - -static PyTypeObject PyUpb_SymbolTableType = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - "upb.SymbolTable", /* tp_name */ - sizeof(PyUpb_ObjWrapper), /* tp_basicsize */ - 0, /* tp_itemsize */ - &PyUpb_SymbolTable_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* TODO */ /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(PyUpb_ObjWrapper, weakreflist),/* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - PyUpb_SymbolTable_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - &PyUpb_SymbolTable_init, /* tp_init */ - 0, /* tp_alloc */ - &PyUpb_SymbolTable_new, /* tp_new */ - 0, /* tp_free */ -}; - - -/* Accessor and PyUpb_Message *************************************************/ - -typedef struct { - PyTypeObject type; - PyTypeObject *alt_type; -} PyUpb_MessageType; - -typedef struct { - PyObject_HEAD; - PyObject *msgdef; - char data[1]; -} PyUpb_Message; - -PyObject **PyUpb_Accessor_GetPtr(PyObject *_m, upb_value fval) { - PyUpb_Message *m = (PyUpb_Message*)_m; - const upb_fielddef *f = upb_value_getfielddef(fval); - return (PyObject**)&m->data[f->offset]; -} - -static upb_sflow_t PyUpb_Message_StartSequence(void *m, upb_value fval) { - PyObject **seq = PyUpb_Accessor_GetPtr(m, fval); - PyTypeObject *type = ((PyUpb_MessageType*)Py_TYPE(m))->alt_type; - if (!*seq) *seq = type->tp_alloc(type, 0); - upb_stdmsg_sethas(m, fval); - return UPB_CONTINUE_WITH(*seq); -} - -static upb_sflow_t PyUpb_Message_StartSubmessage(void *m, upb_value fval) { - PyObject **submsg = PyUpb_Accessor_GetPtr(m, fval); - PyTypeObject *type = Py_TYPE(m); - if (!*submsg) *submsg = type->tp_alloc(type, 0); - upb_stdmsg_sethas(m, fval); - return UPB_CONTINUE_WITH(*submsg); -} - -static upb_sflow_t PyUpb_Message_StartRepeatedSubmessage( - void *a, upb_value fval) { - (void)fval; - PyObject **elem = upb_stdarray_append(a, sizeof(void*)); - PyTypeObject *type = ((PyUpb_MessageType*)Py_TYPE(a))->alt_type; - if (!*elem) *elem = type->tp_alloc(type, 0); - return UPB_CONTINUE_WITH(*elem); -} - -static upb_flow_t PyUpb_Message_StringValue( - void *m, upb_value fval, upb_value val) { - PyObject **str = PyUpb_Accessor_GetPtr(m, fval); - if (*str) { Py_DECREF(*str); } - *str = PyString_FromStringAndSize(NULL, upb_value_getstrref(val)->len); - upb_strref_read(upb_value_getstrref(val), PyString_AsString(*str)); - upb_stdmsg_sethas(m, fval); - return UPB_CONTINUE; -} - -static upb_flow_t PyUpb_Message_AppendStringValue( - void *a, upb_value fval, upb_value val) { - (void)fval; - PyObject **elem = upb_stdarray_append(a, sizeof(void*)); - *elem = PyString_FromStringAndSize(NULL, upb_value_getstrref(val)->len); - upb_strref_read(upb_value_getstrref(val), PyString_AsString(*elem)); - return UPB_CONTINUE; -} - -#define STDMSG(type, size) static upb_accessor_vtbl vtbl = { \ - &PyUpb_Message_StartSubmessage, \ - &upb_stdmsg_set ## type, \ - &PyUpb_Message_StartSequence, \ - &PyUpb_Message_StartRepeatedSubmessage, \ - &upb_stdmsg_set ## type ## _r, \ - &upb_stdmsg_has, \ - &upb_stdmsg_getptr, \ - &upb_stdmsg_get ## type, \ - &upb_stdmsg_seqbegin, \ - &upb_stdmsg_ ## size ## byte_seqnext, \ - &upb_stdmsg_seqget ## type}; - -#define RETURN_STDMSG(type, size) { STDMSG(type, size); return &vtbl; } - -static upb_accessor_vtbl *PyUpb_AccessorForField(upb_fielddef *f) { - switch (f->type) { - case UPB_TYPE(DOUBLE): RETURN_STDMSG(double, 8) - case UPB_TYPE(FLOAT): RETURN_STDMSG(float, 4) - case UPB_TYPE(UINT64): - case UPB_TYPE(FIXED64): RETURN_STDMSG(uint64, 8) - case UPB_TYPE(INT64): - case UPB_TYPE(SFIXED64): - case UPB_TYPE(SINT64): RETURN_STDMSG(int64, 8) - case UPB_TYPE(INT32): - case UPB_TYPE(SINT32): - case UPB_TYPE(ENUM): - case UPB_TYPE(SFIXED32): RETURN_STDMSG(int32, 4) - case UPB_TYPE(UINT32): - case UPB_TYPE(FIXED32): RETURN_STDMSG(uint32, 4) - case UPB_TYPE(BOOL): { STDMSG(bool, 1); return &vtbl; } - case UPB_TYPE(GROUP): - case UPB_TYPE(MESSAGE): RETURN_STDMSG(ptr, 8) // TODO: 32-bit - case UPB_TYPE(STRING): - case UPB_TYPE(BYTES): { - STDMSG(ptr, 8); - vtbl.set = &PyUpb_Message_StringValue; - vtbl.append = &PyUpb_Message_AppendStringValue; - return &vtbl; - } - } - return NULL; -} - - -/* Toplevel *******************************************************************/ - -static PyMethodDef methods[] = { - {NULL, NULL} -}; - -// PyModule_AddObject steals a ref, but our object is statically allocated -// and must not be deleted. -#define PyUpb_AddType(mod, name, type) \ - if (PyType_Ready(type) < 0) return; \ - Py_INCREF(type); \ - PyModule_AddObject(mod, name, (PyObject*)type); - -PyMODINIT_FUNC initupb(void) { - PyObject *mod = Py_InitModule("upb", methods); - - PyUpb_AddType(mod, "FieldDef", &PyUpb_FieldDefType); - PyUpb_AddType(mod, "MessageDef", &PyUpb_MessageDefType); - PyUpb_AddType(mod, "SymbolTable", &PyUpb_SymbolTableType); - - PyModule_AddIntConstant(mod, "LABEL_OPTIONAL", UPB_LABEL(OPTIONAL)); - PyModule_AddIntConstant(mod, "LABEL_REQUIRED", UPB_LABEL(REQUIRED)); - PyModule_AddIntConstant(mod, "LABEL_REPEATED", UPB_LABEL(REPEATED)); - - PyModule_AddIntConstant(mod, "TYPE_DOUBLE", UPB_TYPE(DOUBLE)); - PyModule_AddIntConstant(mod, "TYPE_FLOAT", UPB_TYPE(FLOAT)); - PyModule_AddIntConstant(mod, "TYPE_INT64", UPB_TYPE(INT64)); - PyModule_AddIntConstant(mod, "TYPE_UINT64", UPB_TYPE(UINT64)); - PyModule_AddIntConstant(mod, "TYPE_INT32", UPB_TYPE(INT32)); - PyModule_AddIntConstant(mod, "TYPE_FIXED64", UPB_TYPE(FIXED64)); - PyModule_AddIntConstant(mod, "TYPE_FIXED32", UPB_TYPE(FIXED32)); - PyModule_AddIntConstant(mod, "TYPE_BOOL", UPB_TYPE(BOOL)); - PyModule_AddIntConstant(mod, "TYPE_STRING", UPB_TYPE(STRING)); - PyModule_AddIntConstant(mod, "TYPE_GROUP", UPB_TYPE(GROUP)); - PyModule_AddIntConstant(mod, "TYPE_MESSAGE", UPB_TYPE(MESSAGE)); - PyModule_AddIntConstant(mod, "TYPE_BYTES", UPB_TYPE(BYTES)); - PyModule_AddIntConstant(mod, "TYPE_UINT32", UPB_TYPE(UINT32)); - PyModule_AddIntConstant(mod, "TYPE_ENUM", UPB_TYPE(ENUM)); - PyModule_AddIntConstant(mod, "TYPE_SFIXED32", UPB_TYPE(SFIXED32)); - PyModule_AddIntConstant(mod, "TYPE_SFIXED64", UPB_TYPE(SFIXED64)); - PyModule_AddIntConstant(mod, "TYPE_SINT32", UPB_TYPE(SINT32)); - PyModule_AddIntConstant(mod, "TYPE_SINT64", UPB_TYPE(SINT64)); - - obj_cache = PyDict_New(); - reverse_cache = PyDict_New(); - static PyMethodDef method = { - "WeakRefCallback", &PyUpb_ObjCacheDeleteCallback, METH_O, NULL}; - PyObject *pyname = PyString_FromString(method.ml_name); - weakref_callback = PyCFunction_NewEx(&method, NULL, pyname); - Py_DECREF(pyname); -} diff --git a/upb/bindings/python/upb/__init__.py b/upb/bindings/python/upb/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/upb/bindings/ruby/README.md b/upb/bindings/ruby/README.md deleted file mode 100644 index 12a7169..0000000 --- a/upb/bindings/ruby/README.md +++ /dev/null @@ -1,30 +0,0 @@ - -# Ruby extension - -To build, run (from the top upb directory): - - $ make ruby - $ sudo make install - -To test, run: - - $ make rubytest - -The binding currently supports: - - - loading message types from descriptors. - - constructing message instances - - reading and writing their members - - parsing and serializing the messages - - all data types (including nested and repeated) - -The binding does *not* currently support: - - - defining message types directly in Ruby code. - - generating Ruby code for a .proto file. - - type-checking for setters - - homogenous / type-checked arrays - - default values - -Because code generation is not currently implemented, the interface to import -a specific message type is kind of clunky for the moment. diff --git a/upb/bindings/ruby/extconf.rb b/upb/bindings/ruby/extconf.rb deleted file mode 100644 index b105948..0000000 --- a/upb/bindings/ruby/extconf.rb +++ /dev/null @@ -1,13 +0,0 @@ -#!/usr/bin/ruby - -require 'mkmf' - -# Extra args are passed on the command-line. -$CFLAGS += (" " + ARGV[0]) - -find_header("upb/upb.h", "../../..") or raise "Can't find upb headers" -find_library("upb_pic", "upb_msgdef_new", "../../../lib") or raise "Can't find upb lib" -find_library("upb.descriptor_pic", "upb_descreader_init", "../../../lib") or raise "Can't find upb.descriptor lib" -find_library("upb.pb_pic", "upb_pbdecoder_init", "../../../lib") or raise "Can't find upb.pb lib" - -create_makefile("upb") diff --git a/upb/bindings/ruby/upb.c b/upb/bindings/ruby/upb.c deleted file mode 100644 index 7598bac..0000000 --- a/upb/bindings/ruby/upb.c +++ /dev/null @@ -1,1173 +0,0 @@ -/* -** upb (prototype) extension for Ruby. -*/ - -#include "ruby/ruby.h" -#include "ruby/vm.h" - -#include "upb/def.h" -#include "upb/handlers.h" -#include "upb/pb/decoder.h" -#include "upb/pb/encoder.h" -#include "upb/pb/glue.h" -#include "upb/shim/shim.h" -#include "upb/symtab.h" - -// References to global state. -// -// Ruby does not have multi-VM support and it is common practice to store -// references to classes and other per-VM state in global variables. -static VALUE cSymbolTable; -static VALUE cMessageDef; -static VALUE cMessage; -static VALUE message_map; -static upb_inttable objcache; -static bool objcache_initialized = false; - -struct rupb_Message; -struct rupb_MessageDef; -typedef struct rupb_Message rupb_Message; -typedef struct rupb_MessageDef rupb_MessageDef; - -#define DEREF_RAW(ptr, ofs, type) *(type*)((char*)ptr + ofs) -#define DEREF(msg, ofs, type) *(type*)(&msg->data[ofs]) - -void rupb_checkstatus(upb_status *s) { - if (!upb_ok(s)) { - rb_raise(rb_eRuntimeError, "%s", upb_status_errmsg(s)); - } -} - -static rupb_MessageDef *msgdef_get(VALUE self); -static rupb_Message *msg_get(VALUE self); -static const rupb_MessageDef *get_rbmsgdef(const upb_msgdef *md); -static const upb_handlers *new_fill_handlers(const rupb_MessageDef *rmd, - const void *owner); -static void putmsg(rupb_Message *msg, const rupb_MessageDef *rmd, - upb_sink *sink); -static VALUE msgdef_getwrapper(const upb_msgdef *md); -static VALUE new_message_class(VALUE message_def); -static VALUE get_message_class(VALUE klass, VALUE message); -static VALUE msg_new(VALUE msgdef); - -/* Ruby VALUE <-> C primitive conversions *************************************/ - -// Ruby VALUE -> C. -// TODO(haberman): add type/range/precision checks. -static float value_to_float(VALUE val) { return NUM2DBL(val); } -static double value_to_double(VALUE val) { return NUM2DBL(val); } -static bool value_to_bool(VALUE val) { return RTEST(val); } -static int32_t value_to_int32(VALUE val) { return NUM2INT(val); } -static uint32_t value_to_uint32(VALUE val) { return NUM2LONG(val); } -static int64_t value_to_int64(VALUE val) { return NUM2LONG(val); } -static uint64_t value_to_uint64(VALUE val) { return NUM2ULL(val); } - -// C -> Ruby VALUE -static VALUE float_to_value(float val) { return rb_float_new(val); } -static VALUE double_to_value(double val) { return rb_float_new(val); } -static VALUE bool_to_value(bool val) { return val ? Qtrue : Qfalse; } -static VALUE int32_to_value(int32_t val) { return INT2NUM(val); } -static VALUE uint32_to_value(uint32_t val) { return LONG2NUM(val); } -static VALUE int64_to_value(int64_t val) { return LONG2NUM(val); } -static VALUE uint64_to_value(uint64_t val) { return ULL2NUM(val); } - - -/* stringsink *****************************************************************/ - -// This should probably be factored into a common upb component. - -typedef struct { - upb_byteshandler handler; - upb_bytessink sink; - char *ptr; - size_t len, size; -} stringsink; - -static void *stringsink_start(void *_sink, const void *hd, size_t size_hint) { - stringsink *sink = _sink; - sink->len = 0; - return sink; -} - -static size_t stringsink_string(void *_sink, const void *hd, const char *ptr, - size_t len, const upb_bufhandle *handle) { - UPB_UNUSED(hd); - UPB_UNUSED(handle); - - stringsink *sink = _sink; - size_t new_size = sink->size; - - while (sink->len + len > new_size) { - new_size *= 2; - } - - if (new_size != sink->size) { - sink->ptr = realloc(sink->ptr, new_size); - sink->size = new_size; - } - - memcpy(sink->ptr + sink->len, ptr, len); - sink->len += len; - - return len; -} - -void stringsink_init(stringsink *sink) { - upb_byteshandler_init(&sink->handler); - upb_byteshandler_setstartstr(&sink->handler, stringsink_start, NULL); - upb_byteshandler_setstring(&sink->handler, stringsink_string, NULL); - - upb_bytessink_reset(&sink->sink, &sink->handler, sink); - - sink->size = 32; - sink->ptr = malloc(sink->size); -} - -void stringsink_uninit(stringsink *sink) { - free(sink->ptr); -} - - -/* object cache ***************************************************************/ - -// The object cache is a singleton mapping of void* -> Ruby Object. -// It caches Ruby objects that wrap C objects. -// -// When we are wrapping C objects it is desirable to give them identity -// semantics. In other words, if you reach the same C object via two different -// paths, it is desirable (and sometimes even required) that you get the same -// wrapper object both times. If we instead just created a new wrapper object -// every time you ask for one, we could end up with unexpected results like: -// -// f1 = msgdef.field("request_id") -// f2 = msgdef.field("request_id") -// -// # equal? tests identity equality. Returns false without a cache. -// f1.equal?(f2) -// -// We do not register the cache with Ruby's GC, so being in this map will not -// keep the object alive. This is the desired behavior, because it lets objects -// be freed if they have no references from Ruby. We do require, though, that -// objects remove themselves from the map when they are freed. In this respect -// the cache operates like a weak map where the values are weak. - -typedef VALUE createfunc(const void *obj); - -// Call to initialize the cache. Should be done once on process startup. -static void objcache_init() { - upb_inttable_init(&objcache, UPB_CTYPE_UINT64); - objcache_initialized = true; -} - -// Call to uninitialize the cache. Should be done once on process shutdown. -static void objcache_uninit(ruby_vm_t *vm) { - UPB_ASSERT(objcache_initialized); - UPB_ASSERT(upb_inttable_count(&objcache) == 0); - - objcache_initialized = false; - upb_inttable_uninit(&objcache); -} - -// Looks up the given object in the cache. If the corresponding Ruby wrapper -// object is found, returns it, otherwise creates the wrapper and returns that. -static VALUE objcache_getorcreate(const void *obj, createfunc *func) { - UPB_ASSERT(objcache_initialized); - - upb_value v; - if (!upb_inttable_lookupptr(&objcache, obj, &v)) { - v = upb_value_uint64(func(obj)); - upb_inttable_insertptr(&objcache, obj, v); - } - return upb_value_getuint64(v); -} - -// Removes the given object from the cache. Should only be called by the code -// that is freeing the wrapper object. -static void objcache_remove(const void *obj) { - UPB_ASSERT(objcache_initialized); - - bool removed = upb_inttable_removeptr(&objcache, obj, NULL); - UPB_ASSERT(removed); -} - -/* message layout *************************************************************/ - -// We layout Ruby messages using a raw block of C memory. We assign offsets for -// each member so that instances are laid out like a C struct instead of as -// instance variables. This saves both memory and CPU. - -typedef struct { - // The size of the block of memory we should allocate for instances. - size_t size; - - // Prototype to memcpy() onto new message instances. Size is "size" above. - void *prototype; - - // An offset for each member, indexed by upb_fielddef_index(f). - uint32_t *field_offsets; -} rb_msglayout; - -// Returns true for fields where the field value we store is a Ruby VALUE (ie. a -// direct pointer to another Ruby object) instead of storing the value directly -// in the message. -static bool is_ruby_value(const upb_fielddef *f) { - if (upb_fielddef_isseq(f)) { - // Repeated fields are pointers to arrays. - return true; - } - - if (upb_fielddef_issubmsg(f)) { - // Submessage fields are pointers to submessages. - return true; - } - - if (upb_fielddef_isstring(f)) { - // String fields are pointers to string objects. - return true; - } - - return false; -} - -// General alignment rules are that each type needs to be stored at an address -// that is a multiple of its size. -static size_t align_up(size_t val, size_t align) { - return val % align == 0 ? val : val + align - (val % align); -} - -// Byte size to store each upb type. -static size_t rupb_sizeof(const upb_fielddef *f) { - if (is_ruby_value(f)) { - return sizeof(VALUE); - } - - switch (upb_fielddef_type(f)) { - case UPB_TYPE_BOOL: - return 1; - case UPB_TYPE_INT32: - case UPB_TYPE_UINT32: - case UPB_TYPE_ENUM: - case UPB_TYPE_FLOAT: - return 4; - case UPB_TYPE_INT64: - case UPB_TYPE_UINT64: - case UPB_TYPE_DOUBLE: - return 8; - default: - break; - } - UPB_ASSERT(false); - return 0; -} - -// Calculates offsets for each field. -// -// This lets us pack protos like structs instead of storing them like -// dictionaries. This speeds up a parsing a lot and also saves memory -// (unless messages are very sparse). -static void assign_offsets(rb_msglayout *layout, const upb_msgdef *md) { - layout->field_offsets = ALLOC_N(uint32_t, upb_msgdef_numfields(md)); - size_t ofs = 0; - upb_msg_field_iter i; - - for (upb_msg_field_begin(&i, md); - !upb_msg_field_done(&i); - upb_msg_field_next(&i)) { - const upb_fielddef *f = upb_msg_iter_field(&i); - size_t field_size = rupb_sizeof(f); - - // Align field properly. - // - // TODO(haberman): optimize layout? For example we could sort fields - // big-to-small. - ofs = align_up(ofs, field_size); - - layout->field_offsets[upb_fielddef_index(f)] = ofs; - ofs += field_size; - } - - layout->size = ofs; -} - -// Creates a prototype; a buffer we can memcpy() onto new instances to -// initialize them. -static void make_prototype(rb_msglayout *layout, const upb_msgdef *md) { - void *prototype = ALLOC_N(char, layout->size); - - // Most members default to zero, so we'll start from that and then overwrite - // more specific initialization. - memset(prototype, 0, layout->size); - - upb_msg_field_iter i; - for (upb_msg_field_begin(&i, md); - !upb_msg_field_done(&i); - upb_msg_field_next(&i)) { - const upb_fielddef *f = upb_msg_iter_field(&i); - if (is_ruby_value(f)) { - size_t ofs = layout->field_offsets[upb_fielddef_index(f)]; - // Default all Ruby pointers to nil. - DEREF_RAW(prototype, ofs, VALUE) = Qnil; - } - } - - layout->prototype = prototype; -} - - -static void msglayout_init(rb_msglayout *layout, const upb_msgdef *m) { - assign_offsets(layout, m); - make_prototype(layout, m); -} - -static void msglayout_uninit(rb_msglayout *layout) { - free(layout->field_offsets); - free(layout->prototype); -} - - -/* Upb::MessageDef ************************************************************/ - -// C representation for Upb::MessageDef. -// -// Contains a reference to the underlying upb_msgdef, as well as associated data -// like a reference to the corresponding Ruby class. -struct rupb_MessageDef { - // We own refs on all of these. - - // The upb_msgdef we are wrapping. - const upb_msgdef *md; - - // A DecoderMethod for parsing a protobuf into this type. - const upb_pbdecodermethod *fill_method; - - // Handlers for serializing into a protobuf of this type. - const upb_handlers *serialize_handlers; - - // The Ruby class for instances of this type. - VALUE klass; - - // Layout for messages of this type. - rb_msglayout layout; -}; - -// Called by the Ruby GC when a Upb::MessageDef is being freed. -static void msgdef_free(void *_rmd) { - rupb_MessageDef *rmd = _rmd; - objcache_remove(rmd->md); - upb_msgdef_unref(rmd->md, &rmd->md); - if (rmd->fill_method) { - upb_pbdecodermethod_unref(rmd->fill_method, &rmd->fill_method); - } - if (rmd->serialize_handlers) { - upb_handlers_unref(rmd->serialize_handlers, &rmd->serialize_handlers); - } - msglayout_uninit(&rmd->layout); - free(rmd); -} - -// Called by the Ruby GC during the "mark" phase to decide what is still alive. -// We call rb_gc_mark on all Ruby VALUE pointers we reference. -static void msgdef_mark(void *_rmd) { - rupb_MessageDef *rmd = _rmd; - rb_gc_mark(rmd->klass); - - // Mark all submessage types. - upb_msg_field_iter i; - for (upb_msg_field_begin(&i, rmd->md); - !upb_msg_field_done(&i); - upb_msg_field_next(&i)) { - upb_fielddef *f = upb_msg_iter_field(&i); - if (upb_fielddef_issubmsg(f)) { - // If we were trying to be more aggressively lazy, the submessage might - // not be created and we only mark ones that are. - rb_gc_mark(msgdef_getwrapper(upb_fielddef_msgsubdef(f))); - } - } -} - -static const rb_data_type_t msgdef_type = {"Upb::MessageDef", - {msgdef_mark, msgdef_free, NULL}}; - -// TODO(haberman): do we need an alloc func? We want to prohibit dup and -// probably subclassing too. - -static rupb_MessageDef *msgdef_get(VALUE self) { - rupb_MessageDef *msgdef; - TypedData_Get_Struct(self, rupb_MessageDef, &msgdef_type, msgdef); - return msgdef; -} - -// Constructs the upb decoder method for parsing messages of this type. -const upb_pbdecodermethod *new_fillmsg_decodermethod(const rupb_MessageDef *rmd, - const void *owner) { - const upb_handlers *fill_handlers = new_fill_handlers(rmd, &fill_handlers); - upb_pbdecodermethodopts opts; - upb_pbdecodermethodopts_init(&opts, fill_handlers); - - const upb_pbdecodermethod *ret = upb_pbdecodermethod_new(&opts, owner); - upb_handlers_unref(fill_handlers, &fill_handlers); - return ret; -} - -// Constructs a new Ruby wrapper object around the given msgdef. -static VALUE make_msgdef(const void *_md) { - const upb_msgdef *md = _md; - rupb_MessageDef *rmd; - VALUE ret = - TypedData_Make_Struct(cMessageDef, rupb_MessageDef, &msgdef_type, rmd); - - upb_msgdef_ref(md, &rmd->md); - - rmd->md = md; - rmd->fill_method = NULL; - - // OPT: most of these things could be built lazily, when they are first - // needed. - msglayout_init(&rmd->layout, md); - - rmd->fill_method = NULL; - rmd->klass = new_message_class(ret); - rmd->serialize_handlers = - upb_pb_encoder_newhandlers(md, &rmd->serialize_handlers); - - return ret; -} - -// Accessor to get a decoder method for this message type. -// Constructs the decoder method lazily. -static const upb_pbdecodermethod *msgdef_decodermethod(rupb_MessageDef *rmd) { - if (!rmd->fill_method) { - rmd->fill_method = new_fillmsg_decodermethod(rmd, &rmd->fill_method); - } - - return rmd->fill_method; -} - -static VALUE msgdef_getwrapper(const upb_msgdef *md) { - return objcache_getorcreate(md, make_msgdef); -} - -static const rupb_MessageDef *get_rbmsgdef(const upb_msgdef *md) { - return msgdef_get(msgdef_getwrapper(md)); -} - - -/* Upb::Message ***************************************************************/ - -// Code to implement the Upb::Message object. -// -// A unique Ruby class is generated for each message type, but all message types -// share Upb::Message as their base class. Upb::Message contains all of the -// actual functionality; the only reason the derived class exists at all is -// for convenience. It lets Ruby users do things like: -// -// message = MyMessage.new -// if message.kind_of?(MyMessage) -// -// ... and other similar things that Ruby users expect they can do. - -// C representation of Upb::Message. -// -// Represents a message instance, laid out like a C struct in a type-specific -// layout. -// -// This will be sized according to what fields are actually present. -struct rupb_Message { - VALUE rbmsgdef; - char data[]; -}; - -// Returns the size of a message instance. -size_t msg_size(const rupb_MessageDef *rmd) { - return sizeof(rupb_Message) + rmd->layout.size; -} - -static void msg_free(void *msg) { - free(msg); -} - -// Invoked by the Ruby GC whenever it is doing a mark-and-sweep. -static void msg_mark(void *p) { - rupb_Message *msg = p; - rupb_MessageDef *rmd = msgdef_get(msg->rbmsgdef); - - // Mark the msgdef to keep it alive. - rb_gc_mark(msg->rbmsgdef); - - // We need to mark all references to other Ruby values: strings, arrays, and - // submessages that we point to. - upb_msg_field_iter i; - for (upb_msg_field_begin(&i, rmd->md); - !upb_msg_field_done(&i); - upb_msg_field_next(&i)) { - upb_fielddef *f = upb_msg_iter_field(&i); - if (is_ruby_value(f)) { - size_t ofs = rmd->layout.field_offsets[upb_fielddef_index(f)]; - rb_gc_mark(DEREF(msg, ofs, VALUE)); - } - } -} - -static const rb_data_type_t msg_type = {"Upb::Message", - {msg_mark, msg_free, NULL}}; - -static rupb_Message *msg_get(VALUE self) { - rupb_Message *msg; - TypedData_Get_Struct(self, rupb_Message, &msg_type, msg); - return msg; -} - -// Instance variable name that we use to store a reference from the Ruby class -// for a message and its Upb::MessageDef. -// -// We avoid prefixing this by "@" to make it inaccessible by Ruby. -static const char *kMessageDefMemberName = "msgdef"; - -static VALUE msg_getmsgdef(VALUE klass) { - VALUE msgdef = rb_iv_get(klass, kMessageDefMemberName); - - if (msgdef == Qnil) { - // TODO(haberman): If we want to allow subclassing, we might want to walk up - // the hierarchy looking for this member. - rb_raise(rb_eRuntimeError, - "Can't call on Upb::Message directly, only subclasses"); - } - - return msgdef; -} - -// Called by the Ruby VM when it wants to create a new message instance. -static VALUE msg_alloc(VALUE klass) { - VALUE msgdef = msg_getmsgdef(klass); - const rupb_MessageDef *rmd = msgdef_get(msgdef); - - rupb_Message *msg = (rupb_Message*)ALLOC_N(char, msg_size(rmd)); - msg->rbmsgdef = msgdef; - memcpy(&msg->data, rmd->layout.prototype, rmd->layout.size); - - VALUE ret = TypedData_Wrap_Struct(klass, &msg_type, msg); - return ret; -} - -// Creates a new Ruby class for the given Upb::MessageDef. The new class -// derives from Upb::Message but also stores a reference to the Upb::MessageDef. -static VALUE new_message_class(VALUE message_def) { - msgdef_get(message_def); // Check type. - VALUE klass = rb_class_new(cMessage); - rb_iv_set(klass, kMessageDefMemberName, message_def); - - // This shouldn't be necessary because we should inherit the alloc func from - // the base class of Message. For some reason this is not working properly - // and we are having to define it manually. - rb_define_alloc_func(klass, msg_alloc); - - return klass; -} - -// Call to create a new Message instance. -static VALUE msg_new(VALUE msgdef) { - return rb_class_new_instance(0, NULL, get_message_class(Qnil, msgdef)); -} - -// Looks up the given field. On success returns the upb_fielddef and stores the -// offset in *ofs. Otherwise raises a Ruby exception. -static const upb_fielddef *lookup_field(rupb_Message *msg, const char *field, - size_t len, size_t *ofs) { - const rupb_MessageDef *rmd = msgdef_get(msg->rbmsgdef); - const upb_fielddef *f = upb_msgdef_ntof(rmd->md, field, len); - - if (!f) { - rb_raise(rb_eArgError, "Message %s does not contain field %s", - upb_msgdef_fullname(rmd->md), field); - } - - *ofs = rmd->layout.field_offsets[upb_fielddef_index(f)]; - return f; -} - -// Sets the given field to the given value. -static void setprimitive(rupb_Message *m, size_t ofs, const upb_fielddef *f, - VALUE val) { - switch (upb_fielddef_type(f)) { - case UPB_TYPE_FLOAT: DEREF(m, ofs, float) = value_to_float(val); break; - case UPB_TYPE_DOUBLE: DEREF(m, ofs, double) = value_to_double(val); break; - case UPB_TYPE_BOOL: DEREF(m, ofs, bool) = value_to_bool(val); break; - case UPB_TYPE_ENUM: - case UPB_TYPE_INT32: DEREF(m, ofs, int32_t) = value_to_int32(val); break; - case UPB_TYPE_UINT32: DEREF(m, ofs, uint32_t) = value_to_uint32(val); break; - case UPB_TYPE_INT64: DEREF(m, ofs, int64_t) = value_to_int64(val); break; - case UPB_TYPE_UINT64: DEREF(m, ofs, uint64_t) = value_to_uint64(val); break; - default: rb_bug("Unexpected type"); - } -} - -// Returns the Ruby VALUE for the given field. -static VALUE getprimitive(rupb_Message *m, size_t ofs, const upb_fielddef *f) { - switch (upb_fielddef_type(f)) { - case UPB_TYPE_FLOAT: return float_to_value(DEREF(m, ofs, float)); - case UPB_TYPE_DOUBLE: return double_to_value(DEREF(m, ofs, double)); - case UPB_TYPE_BOOL: return bool_to_value(DEREF(m, ofs, bool)); - case UPB_TYPE_ENUM: - case UPB_TYPE_INT32: return int32_to_value(DEREF(m, ofs, int32_t)); - case UPB_TYPE_UINT32: return uint32_to_value(DEREF(m, ofs, uint32_t)); - case UPB_TYPE_INT64: return int64_to_value(DEREF(m, ofs, int64_t)); - case UPB_TYPE_UINT64: return uint64_to_value(DEREF(m, ofs, uint64_t)); - default: rb_bug("Unexpected type"); - } -} - -static VALUE msg_setter(rupb_Message *msg, VALUE field, VALUE val) { - size_t ofs; - - // fieldp is a string like "id=". But we want to look up "id". - const upb_fielddef *f = - lookup_field(msg, RSTRING_PTR(field), RSTRING_LEN(field) - 1, &ofs); - - // Possibly introduce stricter type checking. - if (is_ruby_value(f)) { - DEREF(msg, ofs, VALUE) = val; - } else { - setprimitive(msg, ofs, f, val); - } - - return val; -} - -static VALUE msg_getter(rupb_Message *msg, VALUE field) { - size_t ofs; - const upb_fielddef *f = - lookup_field(msg, RSTRING_PTR(field), RSTRING_LEN(field), &ofs); - - if (is_ruby_value(f)) { - return DEREF(msg, ofs, VALUE); - } else { - return getprimitive(msg, ofs, f); - } -} - -// This is the Message object's "method_missing" method, so it receives calls -// for any method whose name was not recognized. We use it to implement getters -// and setters for every field -// -// call-seq: -// message.field -> current value of "field" -// message.field = new_value -static VALUE msg_accessor(int argc, VALUE *argv, VALUE obj) { - rupb_Message *msg = msg_get(obj); - - // method_missing protocol: (method [, arg1, arg2, ...]) - UPB_ASSERT(argc >= 1 && SYMBOL_P(argv[0])); - // OPT(haberman): find a better way to get the method name. - // This is allocating a new string each time, which should not be necessary. - VALUE method = rb_id2str(SYM2ID(argv[0])); - const char *method_str = RSTRING_PTR(method); - size_t method_len = RSTRING_LEN(method); - - if (method_str[method_len - 1] == '=') { - // Call was: - // foo.bar = x - // - // Ruby should guarantee that we have exactly one more argument (x) - UPB_ASSERT(argc == 2); - return msg_setter(msg, method, argv[1]); - } else { - // Call was: - // foo.bar - // - // ...but may have had arguments. We want to disallow arguments. - if (argc > 1) { - rb_raise(rb_eArgError, "Accessor %s takes no arguments", method_str); - } - return msg_getter(msg, method); - } -} - -// Called when Ruby wants to turn this value into a string. -// TODO(haberman): implement. -static VALUE msg_tostring(VALUE self) { - return rb_str_new2("tostring!"); -} - -// call-seq: -// MessageClass.parse(binary_protobuf) -> message instance -// -// Parses a binary protobuf according to this message class and returns a new -// message instance of this class type. -static VALUE msg_parse(VALUE klass, VALUE binary_protobuf) { - Check_Type(binary_protobuf, T_STRING); - rupb_MessageDef *rmd = msgdef_get(msg_getmsgdef(klass)); - - VALUE msg = rb_class_new_instance(0, NULL, klass); - rupb_Message *msgp = msg_get(msg); - - const upb_pbdecodermethod *method = msgdef_decodermethod(rmd); - const upb_handlers *h = upb_pbdecodermethod_desthandlers(method); - upb_pbdecoder decoder; - upb_sink sink; - upb_status status = UPB_STATUS_INIT; - - upb_pbdecoder_init(&decoder, method, &status); - upb_sink_reset(&sink, h, msgp); - upb_pbdecoder_resetoutput(&decoder, &sink); - upb_bufsrc_putbuf(RSTRING_PTR(binary_protobuf), - RSTRING_LEN(binary_protobuf), - upb_pbdecoder_input(&decoder)); - - // TODO(haberman): make uninit optional if custom allocator for parsing - // returns GC-rooted memory. That will make decoding longjmp-safe (required - // if parsing triggers any VM errors like OOM or errors in user handlers). - upb_pbdecoder_uninit(&decoder); - rupb_checkstatus(&status); - - return msg; -} - -// call-seq: -// Message.serialize(message instance) -> serialized string -// -// Serializes the given message instance to a string. -static VALUE msg_serialize(VALUE klass, VALUE message) { - rupb_Message *msg = msg_get(message); - const rupb_MessageDef *rmd = msgdef_get(msg->rbmsgdef); - - stringsink sink; - stringsink_init(&sink); - - upb_pb_encoder encoder; - upb_pb_encoder_init(&encoder, rmd->serialize_handlers); - upb_pb_encoder_resetoutput(&encoder, &sink.sink); - - putmsg(msg, rmd, upb_pb_encoder_input(&encoder)); - - VALUE ret = rb_str_new(sink.ptr, sink.len); - - upb_pb_encoder_uninit(&encoder); - stringsink_uninit(&sink); - - return ret; -} - - -/* Upb::SymbolTable ***********************************************************/ - -// Ruby wrapper around a SymbolTable. Allows loading of descriptors and turning -// them into MessageDef objects. - -void symtab_free(void *s) { - upb_symtab_unref(s, UPB_UNTRACKED_REF); -} - -static const rb_data_type_t symtab_type = {"Upb::SymbolTable", - {NULL, symtab_free, NULL}}; - -// Called by the Ruby VM to allocate a SymbolTable object. -static VALUE symtab_alloc(VALUE klass) { - upb_symtab *symtab = upb_symtab_new(UPB_UNTRACKED_REF); - VALUE ret = TypedData_Wrap_Struct(klass, &symtab_type, symtab); - - return ret; -} - -static upb_symtab *symtab_get(VALUE self) { - upb_symtab *symtab; - TypedData_Get_Struct(self, upb_symtab, &symtab_type, symtab); - return symtab; -} - -// call-seq: -// symtab.load_descriptor(descriptor) -// -// Parses a FileDescriptorSet from the given string and adds the defs to the -// SymbolTable. Raises if there was an error. -static VALUE symtab_load_descriptor(VALUE self, VALUE descriptor) { - upb_symtab *symtab = symtab_get(self); - Check_Type(descriptor, T_STRING); - - upb_status status = UPB_STATUS_INIT; - upb_load_descriptor_into_symtab( - symtab, RSTRING_PTR(descriptor), RSTRING_LEN(descriptor), &status); - - if (!upb_ok(&status)) { - rb_raise(rb_eRuntimeError, - "Error loading descriptor: %s", upb_status_errmsg(&status)); - } - - return Qnil; -} - -// call-seq: -// symtab.lookup(name) -// -// Returns the def for this name, or nil if none. -// TODO(haberman): only support messages right now, not enums. -static VALUE symtab_lookup(VALUE self, VALUE name) { - upb_symtab *symtab = symtab_get(self); - Check_Type(name, T_STRING); - - const char *cname = RSTRING_PTR(name); - const upb_msgdef *m = upb_symtab_lookupmsg(symtab, cname); - - if (!m) { - rb_raise(rb_eRuntimeError, "Message name '%s' not found", cname); - } - - return msgdef_getwrapper(m); -} - - -/* handlers *******************************************************************/ - -// These are handlers for populating a Ruby protobuf message (rupb_Message) when -// parsing. - -// Creates a handlerdata that simply contains the offset for this field. -static const void *newhandlerdata(upb_handlers *h, uint32_t ofs) { - size_t *hd_ofs = ALLOC(size_t); - *hd_ofs = ofs; - upb_handlers_addcleanup(h, hd_ofs, free); - return hd_ofs; -} - -typedef struct { - size_t ofs; - const upb_msgdef *md; -} submsg_handlerdata_t; - -// Creates a handlerdata that contains offset and submessage type information. -static const void *newsubmsghandlerdata(upb_handlers *h, uint32_t ofs, - const upb_fielddef *f) { - submsg_handlerdata_t *hd = ALLOC(submsg_handlerdata_t); - hd->ofs = ofs; - hd->md = upb_fielddef_msgsubdef(f); - upb_handlers_addcleanup(h, hd, free); - return hd; -} - -// A handler that starts a repeated field. Gets or creates a Ruby array for the -// field. -static void *startseq_handler(void *closure, const void *hd) { - rupb_Message *msg = closure; - const size_t *ofs = hd; - - if (DEREF(msg, *ofs, VALUE) == Qnil) { - DEREF(msg, *ofs, VALUE) = rb_ary_new(); - } - - return (void*)DEREF(msg, *ofs, VALUE); -} - -// Handlers that append primitive values to a repeated field (a regular Ruby -// array for now). -#define DEFINE_APPEND_HANDLER(type, ctype) \ - static bool append##type##_handler(void *closure, const void *hd, \ - ctype val) { \ - VALUE ary = (VALUE)closure; \ - rb_ary_push(ary, type##_to_value(val)); \ - return true; \ - } - -DEFINE_APPEND_HANDLER(bool, bool) -DEFINE_APPEND_HANDLER(int32, int32_t) -DEFINE_APPEND_HANDLER(uint32, uint32_t) -DEFINE_APPEND_HANDLER(float, float) -DEFINE_APPEND_HANDLER(int64, int64_t) -DEFINE_APPEND_HANDLER(uint64, uint64_t) -DEFINE_APPEND_HANDLER(double, double) - -// Appends a string to a repeated field (a regular Ruby array for now). -static size_t appendstr_handler(void *closure, const void *hd, const char *str, - size_t len, const upb_bufhandle *handle) { - VALUE ary = (VALUE)closure; - rb_ary_push(ary, rb_str_new(str, len)); - return len; -} - -// Sets a non-repeated string field in a message. -static size_t str_handler(void *closure, const void *hd, const char *str, - size_t len, const upb_bufhandle *handle) { - rupb_Message *msg = closure; - const size_t *ofs = hd; - DEREF(msg, *ofs, VALUE) = rb_str_new(str, len); - return len; -} - -// Appends a submessage to a repeated field (a regular Ruby array for now). -static void *appendsubmsg_handler(void *closure, const void *hd) { - VALUE ary = (VALUE)closure; - const submsg_handlerdata_t *submsgdata = hd; - VALUE submsg = msg_new(msgdef_getwrapper(submsgdata->md)); - rb_ary_push(ary, submsg); - return msg_get(submsg); -} - -// Sets a non-repeated submessage field in a message. -static void *submsg_handler(void *closure, const void *hd) { - rupb_Message *msg = closure; - const submsg_handlerdata_t *submsgdata = hd; - - if (DEREF(msg, submsgdata->ofs, VALUE) == Qnil) { - DEREF(msg, submsgdata->ofs, VALUE) = - msg_new(msgdef_getwrapper(submsgdata->md)); - } - - VALUE submsg = DEREF(msg, submsgdata->ofs, VALUE); - return msg_get(submsg); -} - -static void add_handlers_for_message(const void *closure, upb_handlers *h) { - const rupb_MessageDef *rmd = get_rbmsgdef(upb_handlers_msgdef(h)); - upb_msg_field_iter i; - - for (upb_msg_field_begin(&i, rmd->md); - !upb_msg_field_done(&i); - upb_msg_field_next(&i)) { - const upb_fielddef *f = upb_msg_iter_field(&i); - size_t ofs = rmd->layout.field_offsets[upb_fielddef_index(f)]; - - if (upb_fielddef_isseq(f)) { - upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; - upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, ofs)); - upb_handlers_setstartseq(h, f, startseq_handler, &attr); - upb_handlerattr_uninit(&attr); - - switch (upb_fielddef_type(f)) { - -#define SET_HANDLER(utype, ltype) \ - case utype: \ - upb_handlers_set##ltype(h, f, append##ltype##_handler, NULL); \ - break; - - SET_HANDLER(UPB_TYPE_BOOL, bool); - SET_HANDLER(UPB_TYPE_INT32, int32); - SET_HANDLER(UPB_TYPE_UINT32, uint32); - SET_HANDLER(UPB_TYPE_ENUM, int32); - SET_HANDLER(UPB_TYPE_FLOAT, float); - SET_HANDLER(UPB_TYPE_INT64, int64); - SET_HANDLER(UPB_TYPE_UINT64, uint64); - SET_HANDLER(UPB_TYPE_DOUBLE, double); - -#undef SET_HANDLER - - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - // XXX: does't currently handle split buffers. - upb_handlers_setstring(h, f, appendstr_handler, NULL); - break; - case UPB_TYPE_MESSAGE: { - upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; - upb_handlerattr_sethandlerdata(&attr, newsubmsghandlerdata(h, 0, f)); - upb_handlers_setstartsubmsg(h, f, appendsubmsg_handler, &attr); - upb_handlerattr_uninit(&attr); - break; - } - } - } - - switch (upb_fielddef_type(f)) { - case UPB_TYPE_BOOL: - case UPB_TYPE_INT32: - case UPB_TYPE_UINT32: - case UPB_TYPE_ENUM: - case UPB_TYPE_FLOAT: - case UPB_TYPE_INT64: - case UPB_TYPE_UINT64: - case UPB_TYPE_DOUBLE: - // The shim writes directly at the given offset (instead of using - // DEREF()) so we need to add the msg overhead. - upb_shim_set(h, f, ofs + sizeof(rupb_Message), -1); - break; - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: { - upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; - upb_handlerattr_sethandlerdata(&attr, newhandlerdata(h, ofs)); - // XXX: does't currently handle split buffers. - upb_handlers_setstring(h, f, str_handler, &attr); - upb_handlerattr_uninit(&attr); - break; - } - case UPB_TYPE_MESSAGE: { - upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; - upb_handlerattr_sethandlerdata(&attr, newsubmsghandlerdata(h, ofs, f)); - upb_handlers_setstartsubmsg(h, f, submsg_handler, &attr); - upb_handlerattr_uninit(&attr); - break; - } - } - } -} - -// Creates upb handlers for populating a message. -static const upb_handlers *new_fill_handlers(const rupb_MessageDef *rmd, - const void *owner) { - return upb_handlers_newfrozen(rmd->md, owner, add_handlers_for_message, NULL); -} - - -/* msgvisitor *****************************************************************/ - -// This is code to push the contents of a Ruby message (rupb_Message) to a upb -// sink. - -static upb_selector_t getsel(const upb_fielddef *f, upb_handlertype_t type) { - upb_selector_t ret; - bool ok = upb_handlers_getselector(f, type, &ret); - UPB_ASSERT(ok); - return ret; -} - -static void putstr(VALUE str, const upb_fielddef *f, upb_sink *sink) { - if (str == Qnil) return; - - UPB_ASSERT(BUILTIN_TYPE(str) == RUBY_T_STRING); - upb_sink subsink; - - upb_sink_startstr(sink, getsel(f, UPB_HANDLER_STARTSTR), RSTRING_LEN(str), - &subsink); - upb_sink_putstring(&subsink, getsel(f, UPB_HANDLER_STRING), RSTRING_PTR(str), - RSTRING_LEN(str), NULL); - upb_sink_endstr(sink, getsel(f, UPB_HANDLER_ENDSTR)); -} - -static void putsubmsg(VALUE submsg, const upb_fielddef *f, upb_sink *sink) { - if (submsg == Qnil) return; - - upb_sink subsink; - const rupb_MessageDef *sub_rmd = get_rbmsgdef(upb_fielddef_msgsubdef(f)); - - upb_sink_startsubmsg(sink, getsel(f, UPB_HANDLER_STARTSUBMSG), &subsink); - putmsg(msg_get(submsg), sub_rmd, &subsink); - upb_sink_endsubmsg(sink, getsel(f, UPB_HANDLER_ENDSUBMSG)); -} - -static void putary(VALUE ary, const upb_fielddef *f, upb_sink *sink) { - if (ary == Qnil) return; - - UPB_ASSERT(BUILTIN_TYPE(ary) == RUBY_T_ARRAY); - upb_sink subsink; - - upb_sink_startseq(sink, getsel(f, UPB_HANDLER_STARTSEQ), &subsink); - - upb_fieldtype_t type = upb_fielddef_type(f); - upb_selector_t sel = 0; - if (upb_fielddef_isprimitive(f)) { - sel = getsel(f, upb_handlers_getprimitivehandlertype(f)); - } - - int i; - for (i = 0; i < RARRAY_LEN(ary); i++) { - VALUE val = rb_ary_entry(ary, i); - switch (type) { - -#define T(upbtypeconst, upbtype, ctype) \ - case upbtypeconst: \ - upb_sink_put##upbtype(&subsink, sel, value_to_##upbtype(val)); \ - break; - - T(UPB_TYPE_FLOAT, float, float) - T(UPB_TYPE_DOUBLE, double, double) - T(UPB_TYPE_BOOL, bool, bool) - case UPB_TYPE_ENUM: - T(UPB_TYPE_INT32, int32, int32_t) - T(UPB_TYPE_UINT32, uint32, uint32_t) - T(UPB_TYPE_INT64, int64, int64_t) - T(UPB_TYPE_UINT64, uint64, uint64_t) - - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - putstr(val, f, &subsink); - break; - case UPB_TYPE_MESSAGE: - putsubmsg(val, f, &subsink); - break; - -#undef T - - } - } - upb_sink_endseq(sink, getsel(f, UPB_HANDLER_ENDSEQ)); -} - -static void putmsg(rupb_Message *msg, const rupb_MessageDef *rmd, - upb_sink *sink) { - upb_sink_startmsg(sink); - - upb_msg_field_iter i; - for (upb_msg_field_begin(&i, rmd->md); - !upb_msg_field_done(&i); - upb_msg_field_next(&i)) { - upb_fielddef *f = upb_msg_iter_field(&i); - uint32_t ofs = rmd->layout.field_offsets[upb_fielddef_index(f)]; - - if (upb_fielddef_isseq(f)) { - VALUE ary = DEREF(msg, ofs, VALUE); - if (ary != Qnil) { - putary(ary, f, sink); - } - } else if (upb_fielddef_isstring(f)) { - putstr(DEREF(msg, ofs, VALUE), f, sink); - } else if (upb_fielddef_issubmsg(f)) { - putsubmsg(DEREF(msg, ofs, VALUE), f, sink); - } else { - upb_selector_t sel = getsel(f, upb_handlers_getprimitivehandlertype(f)); - -#define T(upbtypeconst, upbtype, ctype) \ - case upbtypeconst: \ - upb_sink_put##upbtype(sink, sel, DEREF(msg, ofs, ctype)); \ - break; - - switch (upb_fielddef_type(f)) { - T(UPB_TYPE_FLOAT, float, float) - T(UPB_TYPE_DOUBLE, double, double) - T(UPB_TYPE_BOOL, bool, bool) - case UPB_TYPE_ENUM: - T(UPB_TYPE_INT32, int32, int32_t) - T(UPB_TYPE_UINT32, uint32, uint32_t) - T(UPB_TYPE_INT64, int64, int64_t) - T(UPB_TYPE_UINT64, uint64, uint64_t) - - case UPB_TYPE_STRING: - case UPB_TYPE_BYTES: - case UPB_TYPE_MESSAGE: rb_raise(rb_eRuntimeError, "Internal error."); - } - -#undef T - - } - } - - upb_status status; - upb_sink_endmsg(sink, &status); -} - - -/* top level ******************************************************************/ - -static VALUE get_message_class(VALUE klass, VALUE message) { - rupb_MessageDef *rmd = msgdef_get(message); - return rmd->klass; -} - -void Init_upb() { - VALUE upb = rb_define_module("Upb"); - rb_define_singleton_method(upb, "get_message_class", get_message_class, 1); - rb_gc_register_address(&message_map); - - cSymbolTable = rb_define_class_under(upb, "SymbolTable", rb_cObject); - rb_define_alloc_func(cSymbolTable, symtab_alloc); - rb_define_method(cSymbolTable, "load_descriptor", symtab_load_descriptor, 1); - rb_define_method(cSymbolTable, "lookup", symtab_lookup, 1); - - cMessageDef = rb_define_class_under(upb, "MessageDef", rb_cObject); - - cMessage = rb_define_class_under(upb, "Message", rb_cObject); - rb_define_alloc_func(cMessage, msg_alloc); - rb_define_method(cMessage, "method_missing", msg_accessor, -1); - rb_define_method(cMessage, "to_s", msg_tostring, 0); - rb_define_singleton_method(cMessage, "parse", msg_parse, 1); - rb_define_singleton_method(cMessage, "serialize", msg_serialize, 1); - - objcache_init(); - - // This causes atexit crashes for unknown reasons. :( - // ruby_vm_at_exit(objcache_uninit); -} diff --git a/upb/bindings/stdc++/string.h b/upb/bindings/stdc++/string.h deleted file mode 100644 index 99efd4f..0000000 --- a/upb/bindings/stdc++/string.h +++ /dev/null @@ -1,64 +0,0 @@ - -#ifndef UPB_STDCPP_H_ -#define UPB_STDCPP_H_ - -#include "upb/sink.h" - -namespace upb { - -template -class FillStringHandler { - public: - static void SetHandler(BytesHandler* handler) { - upb_byteshandler_setstartstr(handler, &FillStringHandler::StartString, - NULL); - upb_byteshandler_setstring(handler, &FillStringHandler::StringBuf, NULL); - } - - private: - // TODO(haberman): add UpbBind/UpbMakeHandler support to BytesHandler so these - // can be prettier callbacks. - static void* StartString(void *c, const void *hd, size_t size) { - UPB_UNUSED(hd); - UPB_UNUSED(size); - - T* str = static_cast(c); - str->clear(); - return c; - } - - static size_t StringBuf(void* c, const void* hd, const char* buf, size_t n, - const BufferHandle* h) { - UPB_UNUSED(hd); - UPB_UNUSED(h); - - T* str = static_cast(c); - try { - str->append(buf, n); - return n; - } catch (const std::exception&) { - return 0; - } - } -}; - -class StringSink { - public: - template - explicit StringSink(T* target) { - // TODO(haberman): we need to avoid rebuilding a new handler every time, - // but with class globals disallowed for google3 C++ this is tricky. - FillStringHandler::SetHandler(&handler_); - input_.Reset(&handler_, target); - } - - BytesSink* input() { return &input_; } - - private: - BytesHandler handler_; - BytesSink input_; -}; - -} // namespace upb - -#endif // UPB_STDCPP_H_ diff --git a/upb/bindings/stdc/error.c b/upb/bindings/stdc/error.c deleted file mode 100644 index 521c1e4..0000000 --- a/upb/bindings/stdc/error.c +++ /dev/null @@ -1,38 +0,0 @@ -/* -** Handling of errno. -*/ - -#include "upb/stdc/error.h" - -#include - -void upb_status_fromerrno(upb_status *status, int code) { - if (code != 0 && !upb_errno_is_wouldblock(code)) { - status->error = true; - upb_status_setcode(status, &upb_stdc_errorspace, code); - } -} - -bool upb_errno_is_wouldblock(int code) { - return -#ifdef EAGAIN - code == EAGAIN || -#endif -#ifdef EWOULDBLOCK - code == EWOULDBLOCK || -#endif - false; -} - -bool upb_stdc_codetostr(int code, char *buf, size_t len) { - // strerror() may use static buffers and is not guaranteed to be thread-safe, - // but it appears that it is not subject to buffer overflows in practice, and - // it used by other portable and high-quality software like Lua. For more - // discussion see: http://thread.gmane.org/gmane.comp.lang.lua.general/89506 - char *err = strerror(code); - if (strlen(err) >= len) return false; - strcpy(buf, err); - return true; -} - -upb_errorspace upb_stdc_errorspace = {"stdc", &upb_stdc_codetostr}; diff --git a/upb/bindings/stdc/error.h b/upb/bindings/stdc/error.h deleted file mode 100644 index 69a2e2b..0000000 --- a/upb/bindings/stdc/error.h +++ /dev/null @@ -1,18 +0,0 @@ -/* -** Handling of errno. -*/ - -#include "upb/upb.h" - -#ifndef UPB_STDC_ERROR_H_ -#define UPB_STDC_ERROR_H_ - -UPB_BEGIN_EXTERN_C - -extern upb_errorspace upb_stdc_errorspace; -void upb_status_fromerrno(upb_status *status, int code); -bool upb_errno_is_wouldblock(int code); - -UPB_END_EXTERN_C - -#endif /* UPB_STDC_ERROR_H_ */ diff --git a/upb/bindings/stdc/io.c b/upb/bindings/stdc/io.c deleted file mode 100644 index fe82014..0000000 --- a/upb/bindings/stdc/io.c +++ /dev/null @@ -1,172 +0,0 @@ - -#include "upb/stdc/io.h" - -#include -#include -#include -#include "upb/stdc/error.h" - -// We can make this configurable if necessary. -#define BUF_SIZE 32768 - -/* upb_stdio ******************************************************************/ - -int upb_stdio_cmpbuf(const void *_key, const void *_elem) { - const uint64_t *ofs = _key; - const upb_stdio_buf *buf = _elem; - return (*ofs / BUF_SIZE) - (buf->ofs / BUF_SIZE); -} - -static upb_stdio_buf *upb_stdio_findbuf(const upb_stdio *s, uint64_t ofs) { - // TODO: it is probably faster to linear search short lists, and to - // special-case the last one or two bufs. - return bsearch(&ofs, s->bufs, s->nbuf, sizeof(*s->bufs), &upb_stdio_cmpbuf); -} - -static upb_stdio_buf *upb_stdio_rotatebufs(upb_stdio *s) { - upb_stdio_buf **reuse = NULL; // XXX - int num_reused = 0, num_inuse = 0; - - // Could sweep only a subset of bufs if this was a hotspot. - for (int i = 0; i < s->nbuf; i++) { - upb_stdio_buf *buf = s->bufs[i]; - if (buf->refcount > 0) { - s->bufs[num_inuse++] = buf; - } else { - reuse[num_reused++] = buf; - } - } - UPB_ASSERT(num_reused + num_inuse == s->nbuf); - memcpy(s->bufs + num_inuse, reuse, num_reused * sizeof(upb_stdio_buf*)); - if (num_reused == 0) { - ++s->nbuf; - s->bufs = realloc(s->bufs, s->nbuf * sizeof(*s->bufs)); - s->bufs[s->nbuf-1] = malloc(sizeof(upb_stdio_buf) + BUF_SIZE); - return s->bufs[s->nbuf-1]; - } - return s->bufs[s->nbuf-num_reused]; -} - -void upb_stdio_discard(void *src, uint64_t ofs) { - (void)src; - (void)ofs; -} - -upb_bytesuccess_t upb_stdio_fetch(void *src, uint64_t ofs, size_t *bytes_read) { - (void)ofs; - upb_stdio *stdio = (upb_stdio*)src; - upb_stdio_buf *buf = upb_stdio_rotatebufs(stdio); -retry: - *bytes_read = fread(&buf->data, 1, BUF_SIZE, stdio->file); - buf->len = *bytes_read; - if (*bytes_read < (size_t)BUF_SIZE) { - // Error or EOF. - if (feof(stdio->file)) { - upb_status_seteof(&stdio->src.status); - return UPB_BYTE_EOF; - } - if (ferror(stdio->file)) { -#ifdef EINTR - // If we encounter a client who doesn't want to retry EINTR, we can easily - // add a boolean property of the stdio that controls this behavior. - if (errno == EINTR) { - clearerr(stdio->file); - goto retry; - } -#endif - upb_status_fromerrno(&stdio->src.status, errno); - return upb_errno_is_wouldblock(errno) ? - UPB_BYTE_WOULDBLOCK : UPB_BYTE_ERROR; - } - UPB_ASSERT(false); - } - return UPB_BYTE_OK; -} - -void upb_stdio_copy(const void *src, uint64_t ofs, size_t len, char *dst) { - upb_stdio_buf *buf = upb_stdio_findbuf(src, ofs); - ofs -= buf->ofs; - memcpy(dst, buf->data + ofs, BUF_SIZE - ofs); - len -= (BUF_SIZE - ofs); - dst += (BUF_SIZE - ofs); - while (len > 0) { - ++buf; - size_t bytes = UPB_MIN(len, BUF_SIZE); - memcpy(dst, buf->data, bytes); - len -= bytes; - dst += bytes; - } -} - -const char *upb_stdio_getptr(const void *src, uint64_t ofs, size_t *len) { - upb_stdio_buf *buf = upb_stdio_findbuf(src, ofs); - ofs -= buf->ofs; - *len = BUF_SIZE - ofs; - return &buf->data[ofs]; -} - -#if 0 -upb_strlen_t upb_stdio_putstr(upb_bytesink *sink, upb_string *str, upb_status *status) { - upb_stdio *stdio = (upb_stdio*)((char*)sink - offsetof(upb_stdio, sink)); - upb_strlen_t len = upb_string_len(str); - upb_strlen_t written = fwrite(upb_string_getrobuf(str), 1, len, stdio->file); - if (written < len) { - upb_status_setf(status, UPB_ERROR, "Error writing to stdio stream."); - return -1; - } - return written; -} - -uint32_t upb_stdio_vprintf(upb_bytesink *sink, upb_status *status, - const char *fmt, va_list args) { - upb_stdio *stdio = (upb_stdio*)((char*)sink - offsetof(upb_stdio, sink)); - int written = vfprintf(stdio->file, fmt, args); - if (written < 0) { - upb_status_seterrf(status, "Error writing to stdio stream."); - return -1; - } - return written; -} -#endif - -void upb_stdio_init(upb_stdio *stdio) { - static upb_bytesrc_vtbl bytesrc_vtbl = { - &upb_stdio_fetch, - &upb_stdio_discard, - &upb_stdio_copy, - &upb_stdio_getptr, - }; - upb_bytesrc_init(&stdio->src, &bytesrc_vtbl); - - //static upb_bytesink_vtbl bytesink_vtbl = { - // upb_stdio_putstr, - // upb_stdio_vprintf - //}; - //upb_bytesink_init(&stdio->bytesink, &bytesink_vtbl); -} - -void upb_stdio_reset(upb_stdio* stdio, FILE *file) { - stdio->file = file; - stdio->should_close = false; -} - -void upb_stdio_open(upb_stdio *stdio, const char *filename, const char *mode, - upb_status *s) { - FILE *f = fopen(filename, mode); - if (!f) { - upb_status_fromerrno(s, errno); - return; - } - setvbuf(stdio->file, NULL, _IONBF, 0); // Disable buffering; we do our own. - upb_stdio_reset(stdio, f); - stdio->should_close = true; -} - -void upb_stdio_uninit(upb_stdio *stdio) { - // Can't report status; caller should flush() to ensure data is written. - if (stdio->should_close) fclose(stdio->file); - stdio->file = NULL; -} - -upb_bytesrc* upb_stdio_bytesrc(upb_stdio *stdio) { return &stdio->src; } -upb_bytesink* upb_stdio_bytesink(upb_stdio *stdio) { return &stdio->sink; } diff --git a/upb/bindings/stdc/io.h b/upb/bindings/stdc/io.h deleted file mode 100644 index b131500..0000000 --- a/upb/bindings/stdc/io.h +++ /dev/null @@ -1,64 +0,0 @@ -/* -** ANSI C file I/O. -*/ - -#ifndef UPB_STDC_IO_H_ -#define UPB_STDC_IO_H_ - -#include -#include "upb/bytestream.h" - -UPB_BEGIN_EXTERN_C - -/* upb_stdio ******************************************************************/ - -// bytesrc/bytesink for ANSI C stdio, which is less efficient than posixfd, but -// more portable. -// -// Specifically, stdio functions acquire locks on every operation (unless you -// use the f{read,write,...}_unlocked variants, which are not standard) and -// performs redundant buffering (unless you disable it with setvbuf(), but we -// can only do this on newly-opened filehandles). - -typedef struct { - uint64_t ofs; - size_t len; - uint32_t refcount; - char data[]; -} upb_stdio_buf; - -// We use a single object for both bytesrc and bytesink for simplicity. -// The object is still not thread-safe, and may only be used by one reader -// and one writer at a time. -typedef struct { - upb_bytesrc src; - upb_bytesink sink; - FILE *file; - bool should_close; - upb_stdio_buf **bufs; - int nbuf; - uint32_t szbuf; -} upb_stdio; - -void upb_stdio_init(upb_stdio *stdio); -// Caller should call upb_stdio_flush prior to calling this to ensure that -// all data is flushed, otherwise data can be silently dropped if an error -// occurs flushing the remaining buffers. -void upb_stdio_uninit(upb_stdio *stdio); - -// Resets the object to read/write to the given "file." The caller is -// responsible for closing the file, which must outlive this object. -void upb_stdio_reset(upb_stdio *stdio, FILE *file); - -// As an alternative to upb_stdio_reset(), initializes the object by opening a -// file, and will handle closing it. This may result in more efficient I/O -// than the previous since we can call setvbuf() to disable buffering. -void upb_stdio_open(upb_stdio *stdio, const char *filename, const char *mode, - upb_status *s); - -upb_bytesrc *upb_stdio_bytesrc(upb_stdio *stdio); -upb_bytesink *upb_stdio_bytesink(upb_stdio *stdio); - -UPB_END_EXTERN_C - -#endif /* UPB_STDC_IO_H_ */ -- cgit v1.2.3 From 1a484d353bc6b48df07473e13de3da27072beaa0 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Tue, 21 Aug 2018 14:56:02 -0700 Subject: Re-add upb/bindings/stdc++/string.h, which is still used in tests. --- upb/bindings/stdc++/string.h | 64 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 64 insertions(+) create mode 100644 upb/bindings/stdc++/string.h (limited to 'upb/bindings') diff --git a/upb/bindings/stdc++/string.h b/upb/bindings/stdc++/string.h new file mode 100644 index 0000000..99efd4f --- /dev/null +++ b/upb/bindings/stdc++/string.h @@ -0,0 +1,64 @@ + +#ifndef UPB_STDCPP_H_ +#define UPB_STDCPP_H_ + +#include "upb/sink.h" + +namespace upb { + +template +class FillStringHandler { + public: + static void SetHandler(BytesHandler* handler) { + upb_byteshandler_setstartstr(handler, &FillStringHandler::StartString, + NULL); + upb_byteshandler_setstring(handler, &FillStringHandler::StringBuf, NULL); + } + + private: + // TODO(haberman): add UpbBind/UpbMakeHandler support to BytesHandler so these + // can be prettier callbacks. + static void* StartString(void *c, const void *hd, size_t size) { + UPB_UNUSED(hd); + UPB_UNUSED(size); + + T* str = static_cast(c); + str->clear(); + return c; + } + + static size_t StringBuf(void* c, const void* hd, const char* buf, size_t n, + const BufferHandle* h) { + UPB_UNUSED(hd); + UPB_UNUSED(h); + + T* str = static_cast(c); + try { + str->append(buf, n); + return n; + } catch (const std::exception&) { + return 0; + } + } +}; + +class StringSink { + public: + template + explicit StringSink(T* target) { + // TODO(haberman): we need to avoid rebuilding a new handler every time, + // but with class globals disallowed for google3 C++ this is tricky. + FillStringHandler::SetHandler(&handler_); + input_.Reset(&handler_, target); + } + + BytesSink* input() { return &input_; } + + private: + BytesHandler handler_; + BytesSink input_; +}; + +} // namespace upb + +#endif // UPB_STDCPP_H_ -- cgit v1.2.3