diff options
Diffstat (limited to 'upb')
46 files changed, 3949 insertions, 535 deletions
diff --git a/upb/bindings/README b/upb/bindings/README new file mode 100644 index 0000000..e4bf0b8 --- /dev/null +++ b/upb/bindings/README @@ -0,0 +1,25 @@ +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. + + * 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 new file mode 100644 index 0000000..e3140f4 --- /dev/null +++ b/upb/bindings/googlepb/README @@ -0,0 +1,20 @@ +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/google/bridge.cc b/upb/bindings/googlepb/bridge.cc index bb5c631..a125249 100644 --- a/upb/google/bridge.cc +++ b/upb/bindings/googlepb/bridge.cc @@ -10,14 +10,14 @@ // without the two conflicting. However we must be careful not to violate the // ODR. -#include "upb/google/bridge.h" +#include "upb/bindings/googlepb/bridge.h" #include <stdio.h> #include <map> #include <string> #include "upb/def.h" -#include "upb/google/proto1.h" -#include "upb/google/proto2.h" +#include "upb/bindings/googlepb/proto1.h" +#include "upb/bindings/googlepb/proto2.h" #include "upb/handlers.h" #define ASSERT_STATUS(status) do { \ @@ -62,12 +62,12 @@ const goog::Message* GetPrototype(const goog::Message& m, } // namespace namespace upb { -namespace google { +namespace googlepb { /* DefBuilder ****************************************************************/ -const EnumDef* DefBuilder::GetOrCreateEnumDef(const goog::EnumDescriptor* ed) { +const EnumDef* DefBuilder::GetEnumDef(const goog::EnumDescriptor* ed) { const EnumDef* cached = FindInCache<EnumDef>(ed); if (cached) return cached; @@ -87,7 +87,7 @@ const EnumDef* DefBuilder::GetOrCreateEnumDef(const goog::EnumDescriptor* ed) { return e; } -const MessageDef* DefBuilder::GetOrCreateMaybeUnfrozenMessageDef( +const MessageDef* DefBuilder::GetMaybeUnfrozenMessageDef( const goog::Descriptor* d, const goog::Message* m) { const MessageDef* cached = FindInCache<MessageDef>(d); if (cached) return cached; @@ -134,9 +134,15 @@ reffed_ptr<FieldDef> DefBuilder::NewFieldDef(const goog::FieldDescriptor* f, reffed_ptr<FieldDef> upb_f(FieldDef::New()); Status status; upb_f->set_number(f->number(), &status); - upb_f->set_name(f->name(), &status); upb_f->set_label(FieldDef::ConvertLabel(f->label())); + if (f->is_extension()) { + upb_f->set_name(f->full_name(), &status); + upb_f->set_is_extension(true); + } else { + upb_f->set_name(f->name(), &status); + } + // For weak fields, weak_prototype will be non-NULL even though the proto2 // descriptor does not indicate a submessage field. upb_f->set_descriptor_type(weak_prototype @@ -169,15 +175,17 @@ reffed_ptr<FieldDef> DefBuilder::NewFieldDef(const goog::FieldDescriptor* f, case UPB_TYPE_BYTES: upb_f->set_default_string(f->default_value_string(), &status); break; - case UPB_TYPE_MESSAGE: - upb_f->set_message_subdef( - GetOrCreateMaybeUnfrozenMessageDef(subm->GetDescriptor(), subm), - &status); + 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(GetOrCreateEnumDef(f->enum_type()), &status); + upb_f->set_enum_subdef(GetEnumDef(f->enum_type()), &status); break; } @@ -192,16 +200,15 @@ void DefBuilder::Freeze() { to_freeze_.clear(); } -const MessageDef* DefBuilder::GetOrCreateMessageDef(const goog::Descriptor* d) { - const MessageDef* ret = GetOrCreateMaybeUnfrozenMessageDef(d, NULL); +const MessageDef* DefBuilder::GetMessageDef(const goog::Descriptor* d) { + const MessageDef* ret = GetMaybeUnfrozenMessageDef(d, NULL); Freeze(); return ret; } -const MessageDef* DefBuilder::GetOrCreateMessageDefExpandWeak( +const MessageDef* DefBuilder::GetMessageDefExpandWeak( const goog::Message& m) { - const MessageDef* ret = - GetOrCreateMaybeUnfrozenMessageDef(m.GetDescriptor(), &m); + const MessageDef* ret = GetMaybeUnfrozenMessageDef(m.GetDescriptor(), &m); Freeze(); return ret; } @@ -209,7 +216,7 @@ const MessageDef* DefBuilder::GetOrCreateMessageDefExpandWeak( /* CodeCache *****************************************************************/ -const Handlers* CodeCache::GetOrCreateMaybeUnfrozenWriteHandlers( +const Handlers* CodeCache::GetMaybeUnfrozenWriteHandlers( const MessageDef* md, const goog::Message& m) { const Handlers* cached = FindInCache(md); if (cached) return cached; @@ -244,8 +251,8 @@ const Handlers* CodeCache::GetOrCreateMaybeUnfrozenWriteHandlers( if (upb_f->type() == UPB_TYPE_MESSAGE) { const goog::Message* prototype = GetPrototype(m, proto2_f); assert(prototype); - const upb::Handlers* sub_handlers = GetOrCreateMaybeUnfrozenWriteHandlers( - upb_f->message_subdef(), *prototype); + const upb::Handlers* sub_handlers = + GetMaybeUnfrozenWriteHandlers(upb_f->message_subdef(), *prototype); h->SetSubHandlers(upb_f, sub_handlers); } } @@ -253,9 +260,9 @@ const Handlers* CodeCache::GetOrCreateMaybeUnfrozenWriteHandlers( return h; } -const Handlers* CodeCache::GetOrCreateWriteHandlers(const goog::Message& m) { - const MessageDef* md = def_builder_.GetOrCreateMessageDefExpandWeak(m); - const Handlers* ret = GetOrCreateMaybeUnfrozenWriteHandlers(md, m); +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); @@ -265,9 +272,8 @@ const Handlers* CodeCache::GetOrCreateWriteHandlers(const goog::Message& m) { upb::reffed_ptr<const upb::Handlers> NewWriteHandlers(const goog::Message& m) { CodeCache cache; - return upb::reffed_ptr<const upb::Handlers>( - cache.GetOrCreateWriteHandlers(m)); + return upb::reffed_ptr<const upb::Handlers>(cache.GetWriteHandlers(m)); } -} // namespace google +} // namespace googlepb } // namespace upb diff --git a/upb/google/bridge.h b/upb/bindings/googlepb/bridge.h index c8bdd47..9eed51b 100644 --- a/upb/google/bridge.h +++ b/upb/bindings/googlepb/bridge.h @@ -40,6 +40,7 @@ #include <map> #include <vector> +#include "upb/handlers.h" #include "upb/upb.h" namespace google { @@ -60,13 +61,7 @@ class Message; namespace upb { -class Def; -class EnumDef; -class FieldDef; -class MessageDef; -class Handlers; - -namespace google { +namespace googlepb { // Returns a upb::Handlers object that can be used to populate a proto2::Message // object of the same type as "m." For more control over handler caching and @@ -89,12 +84,10 @@ class DefBuilder { // 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* GetOrCreateEnumDef(const proto2::EnumDescriptor* d); - const EnumDef* GetOrCreateEnumDef( - const ::google::protobuf::EnumDescriptor* d); - const MessageDef* GetOrCreateMessageDef(const proto2::Descriptor* d); - const MessageDef* GetOrCreateMessageDef( - const ::google::protobuf::Descriptor* d); + 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. // @@ -102,20 +95,27 @@ class DefBuilder { // 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* GetOrCreateMessageDefExpandWeak(const proto2::Message& m); - const MessageDef* GetOrCreateMessageDefExpandWeak( + 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<const MessageDef> NewMessageDef( + const proto2::Descriptor* d) { + DefBuilder builder; + return reffed_ptr<const MessageDef>(builder.GetMessageDef(d)); + } + private: - // Like GetOrCreateMessageDef*(), except the returned def might not be frozen. + // 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* GetOrCreateMaybeUnfrozenMessageDef( - const proto2::Descriptor* d, const proto2::Message* m); - const MessageDef* GetOrCreateMaybeUnfrozenMessageDef( + const MessageDef* GetMaybeUnfrozenMessageDef(const proto2::Descriptor* d, + const proto2::Message* m); + const MessageDef* GetMaybeUnfrozenMessageDef( const ::google::protobuf::Descriptor* d, const ::google::protobuf::Message* m); @@ -156,7 +156,7 @@ class DefBuilder { DefCache def_cache_; // Defs that have not been frozen yet. - vector<Def*> to_freeze_; + std::vector<Def*> to_freeze_; }; // Builds and caches upb::Handlers for populating proto2 generated classes. @@ -170,14 +170,13 @@ class CodeCache { // 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* GetOrCreateWriteHandlers(const proto2::Message& m); - const Handlers* GetOrCreateWriteHandlers( - const ::google::protobuf::Message& m); + const Handlers* GetWriteHandlers(const proto2::Message& m); + const Handlers* GetWriteHandlers(const ::google::protobuf::Message& m); private: - const Handlers* GetOrCreateMaybeUnfrozenWriteHandlers( - const MessageDef* md, const proto2::Message& m); - const Handlers* GetOrCreateMaybeUnfrozenWriteHandlers( + 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> handlers) { @@ -197,10 +196,10 @@ class CodeCache { HandlersCache; HandlersCache handlers_cache_; - vector<Handlers*> to_freeze_; + std::vector<Handlers*> to_freeze_; }; -} // namespace google +} // namespace googlepb } // namespace upb #endif // UPB_GOOGLE_BRIDGE_H_ diff --git a/upb/google/proto1.cc b/upb/bindings/googlepb/proto1.cc index 80a44d8..c317cdf 100644 --- a/upb/google/proto1.cc +++ b/upb/bindings/googlepb/proto1.cc @@ -16,7 +16,7 @@ // dynamic_cast<> in this file: // https://groups.google.com/a/google.com/d/msg/c-style/7Zp_XCX0e7s/I6dpzno4l-MJ -#include "upb/google/proto1.h" +#include "upb/bindings/googlepb/proto1.h" #include <memory> @@ -28,6 +28,9 @@ #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_UNUSED(ok); assert(ok); } while (0) + template <class T> static T* GetPointer(void* message, size_t offset) { return reinterpret_cast<T*>(static_cast<char*>(message) + offset); } @@ -161,7 +164,7 @@ class P2R_Handlers { } } - template <class T> T* GetFieldPointer(void* message) const { + template <class T> T* GetFieldPointer(proto2::Message* message) const { return GetPointer<T>(message, offset_); } @@ -201,16 +204,35 @@ class P2R_Handlers { // StartSequence ///////////////////////////////////////////////////////////// - static void SetStartSequenceHandler( + template <class T> + 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<proto2::RepeatedField<T> >, + new FieldOffset(proto2_f, r)))); + } + + template <class T> + static void SetStartRepeatedPtrField( const proto2::FieldDescriptor* proto2_f, const _pi::Proto2Reflection* r, const upb::FieldDef* f, upb::Handlers* h) { - assert(f->IsSequence()); - h->SetStartSequenceHandler( - f, UpbBind(PushOffset, new FieldOffset(proto2_f, r))); + CHKRET(h->SetStartSequenceHandler( + f, UpbBindT(PushOffset<proto2::RepeatedPtrField<T> >, + new FieldOffset(proto2_f, r)))); } - static void* PushOffset(void* m, const FieldOffset* offset) { - return offset->GetFieldPointer<void>(m); + 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<proto2::internal::RepeatedPtrFieldBase>, + new FieldOffset(proto2_f, r)))); + } + + template <class T> + static T* PushOffset(proto2::Message* m, const FieldOffset* offset) { + return offset->GetFieldPointer<T>(m); } // Primitive Value (numeric, enum, bool) ///////////////////////////////////// @@ -220,10 +242,11 @@ class P2R_Handlers { const _pi::Proto2Reflection* r, const upb::FieldDef* f, upb::Handlers* h) { if (f->IsSequence()) { - SetStartSequenceHandler(proto2_f, r, f, h); - h->SetValueHandler<T>(f, UpbMakeHandlerT(Append<T>)); + SetStartRepeatedField<T>(proto2_f, r, f, h); + CHKRET(h->SetValueHandler<T>(f, UpbMakeHandlerT(Append<T>))); } else { - upb::Shim::Set(h, f, GetOffset(proto2_f, r), GetHasbit(proto2_f, r)); + CHKRET( + upb::Shim::Set(h, f, GetOffset(proto2_f, r), GetHasbit(proto2_f, r))); } } @@ -240,11 +263,11 @@ class P2R_Handlers { const upb::FieldDef* f, upb::Handlers* h) { h->SetStringHandler(f, UpbMakeHandler(OnStringBuf)); if (f->IsSequence()) { - SetStartSequenceHandler(proto2_f, r, f, h); - h->SetStartStringHandler(f, UpbMakeHandler(StartRepeatedString)); + SetStartRepeatedPtrField<string>(proto2_f, r, f, h); + CHKRET(h->SetStartStringHandler(f, UpbMakeHandler(StartRepeatedString))); } else { - h->SetStartStringHandler( - f, UpbBind(StartString, new FieldOffset(proto2_f, r))); + CHKRET(h->SetStartStringHandler( + f, UpbBind(StartString, new FieldOffset(proto2_f, r)))); } } @@ -257,9 +280,8 @@ class P2R_Handlers { return str; } - static size_t OnStringBuf(string* s, const char* buf, size_t n) { + static void OnStringBuf(string* s, const char* buf, size_t n) { s->append(buf, n); - return n; } static string* StartRepeatedString(proto2::RepeatedPtrField<string>* r, @@ -276,9 +298,9 @@ class P2R_Handlers { const upb::FieldDef* f, upb::Handlers* h) { // This type is only used for non-repeated string fields. assert(!f->IsSequence()); - h->SetStartStringHandler( - f, UpbBind(StartOutOfLineString, new FieldOffset(proto2_f, r))); - h->SetStringHandler(f, UpbMakeHandler(OnStringBuf)); + CHKRET(h->SetStartStringHandler( + f, UpbBind(StartOutOfLineString, new FieldOffset(proto2_f, r)))); + CHKRET(h->SetStringHandler(f, UpbMakeHandler(OnStringBuf))); } static string* StartOutOfLineString(proto2::Message* m, @@ -299,13 +321,13 @@ class P2R_Handlers { const _pi::Proto2Reflection* r, const upb::FieldDef* f, upb::Handlers* h) { if (f->IsSequence()) { - SetStartSequenceHandler(proto2_f, r, f, h); - h->SetStartStringHandler(f, UpbMakeHandler(StartRepeatedCord)); + SetStartRepeatedField<Cord>(proto2_f, r, f, h); + CHKRET(h->SetStartStringHandler(f, UpbMakeHandler(StartRepeatedCord))); } else { - h->SetStartStringHandler( - f, UpbBind(StartCord, new FieldOffset(proto2_f, r))); + CHKRET(h->SetStartStringHandler( + f, UpbBind(StartCord, new FieldOffset(proto2_f, r)))); } - h->SetStringHandler(f, UpbMakeHandler(OnCordBuf)); + CHKRET(h->SetStringHandler(f, UpbMakeHandler(OnCordBuf))); } static Cord* StartCord(proto2::Message* m, const FieldOffset* offset, @@ -350,13 +372,13 @@ class P2R_Handlers { const _pi::Proto2Reflection* r, const upb::FieldDef* f, upb::Handlers* h) { if (f->IsSequence()) { - SetStartSequenceHandler(proto2_f, r, f, h); - h->SetStartSubMessageHandler( + SetStartRepeatedSubmessageField(proto2_f, r, f, h); + CHKRET(h->SetStartSubMessageHandler( f, UpbBind(StartRepeatedSubMessage, - new SubMessageHandlerData(m, proto2_f, r))); + new SubMessageHandlerData(m, proto2_f, r)))); } else { - h->SetStartSubMessageHandler( - f, UpbBind(StartRequiredSubMessage, new FieldOffset(proto2_f, r))); + CHKRET(h->SetStartSubMessageHandler( + f, UpbBind(StartRequiredSubMessage, new FieldOffset(proto2_f, r)))); } } @@ -373,11 +395,12 @@ class P2R_Handlers { std::unique_ptr<SubMessageHandlerData> data( new SubMessageHandlerData(m, proto2_f, r)); if (f->IsSequence()) { - SetStartSequenceHandler(proto2_f, r, f, h); - h->SetStartSubMessageHandler( - f, UpbBind(StartRepeatedSubMessage, data.release())); + SetStartRepeatedSubmessageField(proto2_f, r, f, h); + CHKRET(h->SetStartSubMessageHandler( + f, UpbBind(StartRepeatedSubMessage, data.release()))); } else { - h->SetStartSubMessageHandler(f, UpbBind(StartSubMessage, data.release())); + CHKRET(h->SetStartSubMessageHandler( + f, UpbBind(StartSubMessage, data.release()))); } } @@ -388,23 +411,25 @@ class P2R_Handlers { std::unique_ptr<SubMessageHandlerData> data( new SubMessageHandlerData(m, proto2_f, r)); if (f->IsSequence()) { - SetStartSequenceHandler(proto2_f, r, f, h); - h->SetStartSubMessageHandler( - f, UpbBind(StartRepeatedSubMessage, data.release())); + SetStartRepeatedSubmessageField(proto2_f, r, f, h); + CHKRET(h->SetStartSubMessageHandler( + f, UpbBind(StartRepeatedSubMessage, data.release()))); } else { - h->SetStartSubMessageHandler( - f, UpbBind(StartWeakSubMessage, data.release())); + CHKRET(h->SetStartSubMessageHandler( + f, UpbBind(StartWeakSubMessage, data.release()))); } } - static void* StartSubMessage(void *m, const SubMessageHandlerData* info) { + static void* StartSubMessage(proto2::Message* m, + const SubMessageHandlerData* info) { info->SetHasbit(m); proto2::Message** subm = info->GetFieldPointer<proto2::Message*>(m); if (*subm == info->prototype()) *subm = (*subm)->New(); return *subm; } - static void* StartWeakSubMessage(void* m, const SubMessageHandlerData* info) { + static void* StartWeakSubMessage(proto2::Message* m, + const SubMessageHandlerData* info) { info->SetHasbit(m); proto2::Message** subm = info->GetFieldPointer<proto2::Message*>(m); if (*subm == NULL) { diff --git a/upb/google/proto1.h b/upb/bindings/googlepb/proto1.h index eb550ac..eb550ac 100644 --- a/upb/google/proto1.h +++ b/upb/bindings/googlepb/proto1.h diff --git a/upb/google/proto2.cc b/upb/bindings/googlepb/proto2.cc index d138123..c0b4907 100644 --- a/upb/google/proto2.cc +++ b/upb/bindings/googlepb/proto2.cc @@ -13,14 +13,26 @@ // and protobuf opensource both in a single binary without the two conflicting. // However we must be careful not to violate the ODR. -#include "upb/google/proto2.h" +#include "upb/bindings/googlepb/proto2.h" #include "upb/def.h" -#include "upb/google/proto1.h" +#include "upb/bindings/googlepb/proto1.h" #include "upb/handlers.h" #include "upb/shim/shim.h" #include "upb/sink.h" +namespace { + +template<typename To, typename From> To CheckDownCast(From* f) { + assert(f == NULL || dynamic_cast<To>(f) != NULL); + return static_cast<To>(f); +} + +} + +// Unconditionally evaluate, but also assert in debug mode. +#define CHKRET(x) do { bool ok = (x); UPB_UNUSED(ok); assert(ok); } while (0) + namespace upb { namespace google_google3 { class GMR_Handlers; } namespace google_opensource { class GMR_Handlers; } @@ -230,7 +242,7 @@ case goog::FieldDescriptor::cpptype: \ } } - template <class T> T* GetFieldPointer(void* message) const { + template <class T> T* GetFieldPointer(goog::Message* message) const { return GetPointer<T>(message, offset_); } @@ -262,7 +274,7 @@ case goog::FieldDescriptor::cpptype: \ int number() const { return number_; } goog::internal::FieldType type() const { return type_; } - goog::internal::ExtensionSet* GetExtensionSet(goog::MessageLite* m) const { + goog::internal::ExtensionSet* GetExtensionSet(goog::Message* m) const { return GetPointer<goog::internal::ExtensionSet>(m, offset_); } @@ -274,18 +286,38 @@ case goog::FieldDescriptor::cpptype: \ // StartSequence ///////////////////////////////////////////////////////////// - static void SetStartSequenceHandler( + template <class T> + 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<goog::RepeatedField<T> >, + new FieldOffset(proto2_f, r)))); + } + + template <class T> + static void SetStartRepeatedPtrField( const goog::FieldDescriptor* proto2_f, const goog::internal::GeneratedMessageReflection* r, const upb::FieldDef* f, upb::Handlers* h) { - assert(f->IsSequence()); - h->SetStartSequenceHandler( - f, UpbBind(PushOffset, new FieldOffset(proto2_f, r))); + CHKRET(h->SetStartSequenceHandler( + f, UpbBindT(&PushOffset<goog::RepeatedPtrField<T> >, + new FieldOffset(proto2_f, r)))); } - // TODO(haberman): make more type-safe? - static void* PushOffset(void* message, const FieldOffset* offset) { - return offset->GetFieldPointer<void>(message); + 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<goog::internal::RepeatedPtrFieldBase>, + new FieldOffset(proto2_f, r)))); + } + + template <class T> + static T* PushOffset(goog::Message* message, const FieldOffset* offset) { + return offset->GetFieldPointer<T>(message); } // Primitive Value (numeric, bool) /////////////////////////////////////////// @@ -297,18 +329,19 @@ case goog::FieldDescriptor::cpptype: \ if (proto2_f->is_extension()) { scoped_ptr<ExtensionFieldData> data(new ExtensionFieldData(proto2_f, r)); if (f->IsSequence()) { - h->SetValueHandler<T>( - f, UpbBindT(AppendPrimitiveExtension<T>, data.release())); + CHKRET(h->SetValueHandler<T>( + f, UpbBindT(AppendPrimitiveExtension<T>, data.release()))); } else { - h->SetValueHandler<T>( - f, UpbBindT(SetPrimitiveExtension<T>, data.release())); + CHKRET(h->SetValueHandler<T>( + f, UpbBindT(SetPrimitiveExtension<T>, data.release()))); } } else { if (f->IsSequence()) { - SetStartSequenceHandler(proto2_f, r, f, h); - h->SetValueHandler<T>(f, UpbMakeHandlerT(AppendPrimitive<T>)); + SetStartRepeatedField<T>(proto2_f, r, f, h); + CHKRET(h->SetValueHandler<T>(f, UpbMakeHandlerT(AppendPrimitive<T>))); } else { - upb::Shim::Set(h, f, GetOffset(proto2_f, r), GetHasbit(proto2_f, r)); + CHKRET(upb::Shim::Set(h, f, GetOffset(proto2_f, r), + GetHasbit(proto2_f, r))); } } } @@ -368,9 +401,9 @@ case goog::FieldDescriptor::cpptype: \ assert(!proto2_f->is_extension()); scoped_ptr<EnumHandlerData> data(new EnumHandlerData(proto2_f, r, f)); if (f->IsSequence()) { - h->SetInt32Handler(f, UpbBind(AppendEnum, data.release())); + CHKRET(h->SetInt32Handler(f, UpbBind(AppendEnum, data.release()))); } else { - h->SetInt32Handler(f, UpbBind(SetEnum, data.release())); + CHKRET(h->SetInt32Handler(f, UpbBind(SetEnum, data.release()))); } } @@ -408,9 +441,10 @@ case goog::FieldDescriptor::cpptype: \ assert(proto2_f->is_extension()); scoped_ptr<ExtensionFieldData> data(new ExtensionFieldData(proto2_f, r)); if (f->IsSequence()) { - h->SetInt32Handler(f, UpbBind(AppendEnumExtension, data.release())); + CHKRET( + h->SetInt32Handler(f, UpbBind(AppendEnumExtension, data.release()))); } else { - h->SetInt32Handler(f, UpbBind(SetEnumExtension, data.release())); + CHKRET(h->SetInt32Handler(f, UpbBind(SetEnumExtension, data.release()))); } } @@ -440,7 +474,7 @@ case goog::FieldDescriptor::cpptype: \ const T* prototype() const { return prototype_; } - T** GetStringPointer(void* message) const { + T** GetStringPointer(goog::Message* message) const { return GetFieldPointer<T*>(message); } @@ -454,13 +488,14 @@ case goog::FieldDescriptor::cpptype: \ const upb::FieldDef* f, upb::Handlers* h) { assert(!proto2_f->is_extension()); - h->SetStringHandler(f, UpbMakeHandlerT(&OnStringBuf<T>)); + CHKRET(h->SetStringHandler(f, UpbMakeHandlerT(&OnStringBuf<T>))); if (f->IsSequence()) { - SetStartSequenceHandler(proto2_f, r, f, h); - h->SetStartStringHandler(f, UpbMakeHandlerT(StartRepeatedString<T>)); + SetStartRepeatedPtrField<T>(proto2_f, r, f, h); + CHKRET( + h->SetStartStringHandler(f, UpbMakeHandlerT(StartRepeatedString<T>))); } else { - h->SetStartStringHandler( - f, UpbBindT(StartString<T>, new StringHandlerData<T>(proto2_f, r))); + CHKRET(h->SetStartStringHandler( + f, UpbBindT(StartString<T>, new StringHandlerData<T>(proto2_f, r)))); } } @@ -479,14 +514,13 @@ case goog::FieldDescriptor::cpptype: \ } template <typename T> - static size_t OnStringBuf(T* str, const char* buf, size_t n) { + static void OnStringBuf(T* str, const char* buf, size_t n) { str->append(buf, n); - return n; } template <typename T> static T* StartRepeatedString(goog::RepeatedPtrField<T>* r, - size_t size_hint) { + size_t size_hint) { UPB_UNUSED(size_hint); T* str = r->Add(); str->clear(); @@ -502,14 +536,14 @@ case goog::FieldDescriptor::cpptype: \ const goog::internal::GeneratedMessageReflection* r, const upb::FieldDef* f, upb::Handlers* h) { assert(proto2_f->is_extension()); - h->SetStringHandler(f, UpbMakeHandlerT(OnStringBuf<T>)); + CHKRET(h->SetStringHandler(f, UpbMakeHandlerT(OnStringBuf<T>))); scoped_ptr<ExtensionFieldData> data(new ExtensionFieldData(proto2_f, r)); if (f->IsSequence()) { - h->SetStartStringHandler( - f, UpbBindT(StartRepeatedStringExtension<T>, data.release())); + CHKRET(h->SetStartStringHandler( + f, UpbBindT(StartRepeatedStringExtension<T>, data.release()))); } else { - h->SetStartStringHandler( - f, UpbBindT(StartStringExtension<T>, data.release())); + CHKRET(h->SetStartStringHandler( + f, UpbBindT(StartStringExtension<T>, data.release()))); } } @@ -555,11 +589,12 @@ case goog::FieldDescriptor::cpptype: \ scoped_ptr<SubMessageHandlerData> data( new SubMessageHandlerData(proto2_f, r, field_prototype)); if (f->IsSequence()) { - SetStartSequenceHandler(proto2_f, r, f, h); - h->SetStartSubMessageHandler( - f, UpbBind(StartRepeatedSubMessage, data.release())); + SetStartRepeatedSubmessageField(proto2_f, r, f, h); + CHKRET(h->SetStartSubMessageHandler( + f, UpbBind(StartRepeatedSubMessage, data.release()))); } else { - h->SetStartSubMessageHandler(f, UpbBind(StartSubMessage, data.release())); + CHKRET(h->SetStartSubMessageHandler( + f, UpbBind(StartSubMessage, data.release()))); } } @@ -625,26 +660,32 @@ case goog::FieldDescriptor::cpptype: \ scoped_ptr<SubMessageExtensionHandlerData> data( new SubMessageExtensionHandlerData(proto2_f, r, field_prototype)); if (f->IsSequence()) { - h->SetStartSubMessageHandler( - f, UpbBind(StartRepeatedSubMessageExtension, data.release())); + CHKRET(h->SetStartSubMessageHandler( + f, UpbBind(StartRepeatedSubMessageExtension, data.release()))); } else { - h->SetStartSubMessageHandler( - f, UpbBind(StartSubMessageExtension, data.release())); + CHKRET(h->SetStartSubMessageHandler( + f, UpbBind(StartSubMessageExtension, data.release()))); } } - static goog::MessageLite* StartRepeatedSubMessageExtension( - goog::MessageLite* m, const SubMessageExtensionHandlerData* data) { + static goog::Message* StartRepeatedSubMessageExtension( + goog::Message* m, const SubMessageExtensionHandlerData* data) { goog::internal::ExtensionSet* set = data->GetExtensionSet(m); - return set->AddMessage(data->number(), data->type(), *data->prototype(), - NULL); + // 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<goog::Message*>(set->AddMessage( + data->number(), data->type(), *data->prototype(), NULL)); } - static goog::MessageLite* StartSubMessageExtension( - goog::MessageLite* m, const SubMessageExtensionHandlerData* data) { + static goog::Message* StartSubMessageExtension( + goog::Message* m, const SubMessageExtensionHandlerData* data) { goog::internal::ExtensionSet* set = data->GetExtensionSet(m); - return set->MutableMessage(data->number(), data->type(), *data->prototype(), - NULL); + // See comment above re: this down cast. + return CheckDownCast<goog::Message*>(set->MutableMessage( + data->number(), data->type(), *data->prototype(), NULL)); } // TODO(haberman): handle Unknown Fields. @@ -661,13 +702,13 @@ case goog::FieldDescriptor::cpptype: \ const proto2::internal::GeneratedMessageReflection* r, const upb::FieldDef* f, upb::Handlers* h) { assert(!proto2_f->is_extension()); - h->SetStringHandler(f, UpbMakeHandler(&OnCordBuf)); + CHKRET(h->SetStringHandler(f, UpbMakeHandler(&OnCordBuf))); if (f->IsSequence()) { - SetStartSequenceHandler(proto2_f, r, f, h); - h->SetStartStringHandler(f, UpbMakeHandler(StartRepeatedCord)); + SetStartRepeatedField<Cord>(proto2_f, r, f, h); + CHKRET(h->SetStartStringHandler(f, UpbMakeHandler(StartRepeatedCord))); } else { - h->SetStartStringHandler( - f, UpbBind(StartCord, new FieldOffset(proto2_f, r))); + CHKRET(h->SetStartStringHandler( + f, UpbBind(StartCord, new FieldOffset(proto2_f, r)))); } } @@ -680,9 +721,21 @@ case goog::FieldDescriptor::cpptype: \ return field; } - static size_t OnCordBuf(Cord* c, const char* buf, size_t n) { - c->Append(StringPiece(buf, n)); - return n; + static void OnCordBuf(Cord* c, const char* buf, size_t n, + const upb::BufferHandle* handle) { + const Cord* source_cord = handle->GetAttachedObject<Cord>(); + 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())); + assert(piece.size() >= n); + piece.RemoveSuffix(piece.size() - n); + + c->Append(piece); + } else { + c->Append(StringPiece(buf, n)); + } } static Cord* StartRepeatedCord(proto2::RepeatedField<Cord>* r, @@ -698,18 +751,20 @@ case goog::FieldDescriptor::cpptype: \ const proto2::internal::GeneratedMessageReflection* r, const upb::FieldDef* f, upb::Handlers* h) { assert(!proto2_f->is_extension()); - h->SetStringHandler(f, UpbMakeHandler(OnStringPieceBuf)); + CHKRET(h->SetStringHandler(f, UpbMakeHandler(OnStringPieceBuf))); if (f->IsSequence()) { - SetStartSequenceHandler(proto2_f, r, f, h); - h->SetStartStringHandler(f, UpbMakeHandler(StartRepeatedStringPiece)); + SetStartRepeatedPtrField<proto2::internal::StringPieceField>(proto2_f, r, + f, h); + CHKRET(h->SetStartStringHandler( + f, UpbMakeHandler(StartRepeatedStringPiece))); } else { - h->SetStartStringHandler( - f, UpbBind(StartStringPiece, new FieldOffset(proto2_f, r))); + CHKRET(h->SetStartStringHandler( + f, UpbBind(StartStringPiece, new FieldOffset(proto2_f, r)))); } } - static size_t OnStringPieceBuf(proto2::internal::StringPieceField* field, - const char* buf, size_t len) { + 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. @@ -719,7 +774,6 @@ case goog::FieldDescriptor::cpptype: \ memcpy(data + field->size(), buf, len); field->CopyFrom(StringPiece(data, new_len)); delete[] data; - return len; } static proto2::internal::StringPieceField* StartStringPiece( diff --git a/upb/google/proto2.h b/upb/bindings/googlepb/proto2.h index 516b7fd..516b7fd 100644 --- a/upb/google/proto2.h +++ b/upb/bindings/googlepb/proto2.h diff --git a/upb/bindings/linux/Makefile b/upb/bindings/linux/Makefile new file mode 100644 index 0000000..1736b61 --- /dev/null +++ b/upb/bindings/linux/Makefile @@ -0,0 +1,20 @@ +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 new file mode 100644 index 0000000..26d8ab6 --- /dev/null +++ b/upb/bindings/linux/assert.h @@ -0,0 +1,20 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2012 Google Inc. See LICENSE for details. + * Author: Josh Haberman <jhaberman@gmail.com> + */ + +#include <linux/kernel.h> + +#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 new file mode 100644 index 0000000..f45d939 --- /dev/null +++ b/upb/bindings/linux/errno.h @@ -0,0 +1,8 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2012 Google Inc. See LICENSE for details. + * Author: Josh Haberman <jhaberman@gmail.com> + */ + +#include <linux/errno.h> diff --git a/upb/bindings/linux/stdint.h b/upb/bindings/linux/stdint.h new file mode 100644 index 0000000..2524b23 --- /dev/null +++ b/upb/bindings/linux/stdint.h @@ -0,0 +1,8 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2012 Google Inc. See LICENSE for details. + * Author: Josh Haberman <jhaberman@gmail.com> + */ + +#include <linux/types.h> diff --git a/upb/bindings/linux/stdio.h b/upb/bindings/linux/stdio.h new file mode 100644 index 0000000..72c1b0d --- /dev/null +++ b/upb/bindings/linux/stdio.h @@ -0,0 +1,10 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2012 Google Inc. See LICENSE for details. + * Author: Josh Haberman <jhaberman@gmail.com> + * + * Linux-kernel implementations of some stdlib.h functions. + */ + +#include <linux/kernel.h> // For sprintf and friends. diff --git a/upb/bindings/linux/stdlib.h b/upb/bindings/linux/stdlib.h new file mode 100644 index 0000000..8381b13 --- /dev/null +++ b/upb/bindings/linux/stdlib.h @@ -0,0 +1,22 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2012 Google Inc. See LICENSE for details. + * Author: Josh Haberman <jhaberman@gmail.com> + * + * Linux-kernel implementations of some stdlib.h functions. + */ + +#include <linux/slab.h> + +#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 new file mode 100644 index 0000000..30ebf8a --- /dev/null +++ b/upb/bindings/linux/string.h @@ -0,0 +1,13 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2012 Google Inc. See LICENSE for details. + * Author: Josh Haberman <jhaberman@gmail.com> + */ + +#ifndef UPB_LINUX_STRING_H_ +#define UPB_LINUX_STRING_H_ + +#include <linux/string.h> + +#endif /* UPB_DEF_H_ */ diff --git a/upb/bindings/lua/table.c b/upb/bindings/lua/table.c new file mode 100644 index 0000000..51ba324 --- /dev/null +++ b/upb/bindings/lua/table.c @@ -0,0 +1,169 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2012 Google Inc. See LICENSE for details. + * Author: Josh Haberman <jhaberman@gmail.com> + * + * Lua extension that provides access to upb_table. This is an internal-only + * interface and exists for the sole purpose of writing a C code generator in + * Lua that can dump a upb_table as static C initializers. This lets us use + * Lua for convenient string manipulation while saving us from re-implementing + * the upb_table hash function and hash table layout / collision strategy in + * Lua. + * + * Since this is used only as part of the toolchain (and not part of the + * runtime) we do not hold this module to the same stringent requirements as + * the main Lua modules (for example that misbehaving Lua programs cannot + * crash the interpreter). + */ + +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <string.h> + +#include "lauxlib.h" +#include "upb/bindings/lua/upb.h" +#include "upb/def.h" + +static void lupbtable_setnum(lua_State *L, int tab, const char *key, + lua_Number val) { + lua_pushnumber(L, val); + lua_setfield(L, tab - 1, key); +} + +static void lupbtable_pushval(lua_State *L, _upb_value val, upb_ctype_t ctype) { + switch (ctype) { + case UPB_CTYPE_INT32: + lua_pushnumber(L, val.int32); + break; + case UPB_CTYPE_PTR: + lupb_def_pushwrapper(L, val.ptr, NULL); + break; + case UPB_CTYPE_CSTR: + lua_pushstring(L, val.cstr); + break; + default: + luaL_error(L, "Unexpected type: %d", ctype); + } +} + +// Sets a few fields common to both hash table entries and arrays. +static void lupbtable_setmetafields(lua_State *L, int ctype, const void *ptr) { + // We tack this onto every entry so we know it even if the entries + // don't stay with the table. + lua_pushnumber(L, ctype); + lua_setfield(L, -2, "valtype"); + + // Set this to facilitate linking. + lua_pushlightuserdata(L, (void*)ptr); + lua_setfield(L, -2, "ptr"); +} + +static void lupbtable_pushent(lua_State *L, const upb_tabent *e, + bool inttab, int ctype) { + lua_newtable(L); + if (!upb_tabent_isempty(e)) { + if (inttab) { + lua_pushnumber(L, e->key.num); + } else { + lua_pushstring(L, e->key.str); + } + lua_setfield(L, -2, "key"); + lupbtable_pushval(L, e->val, ctype); + lua_setfield(L, -2, "value"); + } + lua_pushlightuserdata(L, (void*)e->next); + lua_setfield(L, -2, "next"); + lupbtable_setmetafields(L, ctype, e); +} + +// Dumps the shared part of upb_table into a Lua table. +static void lupbtable_pushtable(lua_State *L, const upb_table *t, bool inttab) { + lua_newtable(L); + lupbtable_setnum(L, -1, "count", t->count); + lupbtable_setnum(L, -1, "mask", t->mask); + lupbtable_setnum(L, -1, "ctype", t->ctype); + lupbtable_setnum(L, -1, "size_lg2", t->size_lg2); + + lua_newtable(L); + for (int i = 0; i < upb_table_size(t); i++) { + lupbtable_pushent(L, &t->entries[i], inttab, t->ctype); + lua_rawseti(L, -2, i + 1); + } + lua_setfield(L, -2, "entries"); +} + +// Dumps a upb_inttable to a Lua table. +static void lupbtable_pushinttable(lua_State *L, const upb_inttable *t) { + lupbtable_pushtable(L, &t->t, true); + lupbtable_setnum(L, -1, "array_size", t->array_size); + lupbtable_setnum(L, -1, "array_count", t->array_count); + + lua_newtable(L); + for (int i = 0; i < t->array_size; i++) { + lua_newtable(L); + if (upb_arrhas(t->array[i])) { + lupbtable_pushval(L, t->array[i], t->t.ctype); + lua_setfield(L, -2, "val"); + } + lupbtable_setmetafields(L, t->t.ctype, &t->array[i]); + lua_rawseti(L, -2, i + 1); + } + lua_setfield(L, -2, "array"); +} + +static void lupbtable_pushstrtable(lua_State *L, const upb_strtable *t) { + lupbtable_pushtable(L, &t->t, false); +} + +static int lupbtable_msgdef_itof(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + lupbtable_pushinttable(L, &m->itof); + return 1; +} + +static int lupbtable_msgdef_ntof(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + lupbtable_pushstrtable(L, &m->ntof); + return 1; +} + +static int lupbtable_enumdef_iton(lua_State *L) { + const upb_enumdef *e = lupb_enumdef_check(L, 1); + lupbtable_pushinttable(L, &e->iton); + return 1; +} + +static int lupbtable_enumdef_ntoi(lua_State *L) { + const upb_enumdef *e = lupb_enumdef_check(L, 1); + lupbtable_pushstrtable(L, &e->ntoi); + return 1; +} + +static void lupbtable_setfieldi(lua_State *L, const char *field, int i) { + lua_pushnumber(L, i); + lua_setfield(L, -2, field); +} + +static const struct luaL_Reg lupbtable_toplevel_m[] = { + {"msgdef_itof", lupbtable_msgdef_itof}, + {"msgdef_ntof", lupbtable_msgdef_ntof}, + {"enumdef_iton", lupbtable_enumdef_iton}, + {"enumdef_ntoi", lupbtable_enumdef_ntoi}, + {NULL, NULL} +}; + +int luaopen_upbtable(lua_State *L) { + lupb_newlib(L, "upb.table", lupbtable_toplevel_m); + + // We define these here because they are not public. + lupbtable_setfieldi(L, "CTYPE_PTR", UPB_CTYPE_PTR); + lupbtable_setfieldi(L, "CTYPE_CSTR", UPB_CTYPE_CSTR); + lupbtable_setfieldi(L, "CTYPE_INT32", UPB_CTYPE_INT32); + + lua_pushlightuserdata(L, NULL); + lua_setfield(L, -2, "NULL"); + + return 1; // Return a single Lua value, the package table created above. +} diff --git a/upb/bindings/lua/upb.c b/upb/bindings/lua/upb.c new file mode 100644 index 0000000..1e7540a --- /dev/null +++ b/upb/bindings/lua/upb.c @@ -0,0 +1,1208 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2009 Google Inc. See LICENSE for details. + * Author: Josh Haberman <jhaberman@gmail.com> + * + * A Lua extension for upb. Exposes only the core library + * (sub-libraries are exposed in other extensions). + */ + +#include <float.h> +#include <math.h> +#include <stdlib.h> +#include <string.h> +#include "lauxlib.h" +#include "upb/bindings/lua/upb.h" +#include "upb/handlers.h" +#include "upb/pb/glue.h" + +// Lua metatable types. +#define LUPB_MSGDEF "lupb.msgdef" +#define LUPB_ENUMDEF "lupb.enumdef" +#define LUPB_FIELDDEF "lupb.fielddef" +#define LUPB_SYMTAB "lupb.symtab" + +// Other table constants. +#define LUPB_OBJCACHE "lupb.objcache" + +#if LUA_VERSION_NUM == 501 + +// Taken from Lua 5.2's source. +void *luaL_testudata(lua_State *L, int ud, const char *tname) { + void *p = lua_touserdata(L, ud); + if (p != NULL) { /* value is a userdata? */ + if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ + luaL_getmetatable(L, tname); /* get correct metatable */ + if (!lua_rawequal(L, -1, -2)) /* not the same? */ + p = NULL; /* value is a userdata with wrong metatable */ + lua_pop(L, 2); /* remove both metatables */ + return p; + } + } + return NULL; /* value is not a userdata with a metatable */ +} + +#elif LUA_VERSION_NUM == 502 + +int luaL_typerror(lua_State *L, int narg, const char *tname) { + const char *msg = lua_pushfstring(L, "%s expected, got %s", + tname, luaL_typename(L, narg)); + return luaL_argerror(L, narg, msg); +} + +#else +#error Only Lua 5.1 and 5.2 are supported +#endif + +static const char *chkname(lua_State *L, int narg) { + size_t len; + const char *name = luaL_checklstring(L, narg, &len); + if (strlen(name) != len) + luaL_error(L, "names cannot have embedded NULLs"); + return name; +} + +static bool chkbool(lua_State *L, int narg, const char *type) { + if (!lua_isboolean(L, narg)) { + luaL_error(L, "%s must be true or false", type); + } + return lua_toboolean(L, narg); +} + +static bool streql(const char *a, const char *b) { return strcmp(a, b) == 0; } + +static uint32_t chkint32(lua_State *L, int narg, const char *name) { + lua_Number n = lua_tonumber(L, narg); + if (n > INT32_MAX || n < INT32_MIN || rint(n) != n) + luaL_error(L, "Invalid %s", name); + return n; +} + +// Sets a fielddef default from the given Lua value. +static void lupb_setdefault(lua_State *L, int narg, upb_fielddef *f) { + if (upb_fielddef_type(f) == UPB_TYPE_BOOL) { + upb_fielddef_setdefaultbool(f, chkbool(L, narg, "bool default")); + } else { + // Numeric type. + lua_Number num = luaL_checknumber(L, narg); + switch (upb_fielddef_type(f)) { + case UPB_TYPE_INT32: + case UPB_TYPE_ENUM: + if (num > INT32_MAX || num < INT32_MIN || num != rint(num)) + luaL_error(L, "Cannot convert %f to 32-bit integer", num); + upb_fielddef_setdefaultint32(f, num); + break; + case UPB_TYPE_INT64: + if (num > INT64_MAX || num < INT64_MIN || num != rint(num)) + luaL_error(L, "Cannot convert %f to 64-bit integer", num); + upb_fielddef_setdefaultint64(f, num); + break; + case UPB_TYPE_UINT32: + if (num > UINT32_MAX || num < 0 || num != rint(num)) + luaL_error(L, "Cannot convert %f to unsigned 32-bit integer", num); + upb_fielddef_setdefaultuint32(f, num); + break; + case UPB_TYPE_UINT64: + if (num > UINT64_MAX || num < 0 || num != rint(num)) + luaL_error(L, "Cannot convert %f to unsigned 64-bit integer", num); + upb_fielddef_setdefaultuint64(f, num); + break; + case UPB_TYPE_DOUBLE: + if (num > DBL_MAX || num < -DBL_MAX) { + // This could happen if lua_Number was long double. + luaL_error(L, "Cannot convert %f to double", num); + } + upb_fielddef_setdefaultdouble(f, num); + break; + case UPB_TYPE_FLOAT: + if (num > FLT_MAX || num < -FLT_MAX) + luaL_error(L, "Cannot convert %f to float", num); + upb_fielddef_setdefaultfloat(f, num); + break; + default: luaL_error(L, "invalid type"); + } + } +} + +void lupb_checkstatus(lua_State *L, upb_status *s) { + if (!upb_ok(s)) { + lua_pushstring(L, upb_status_errmsg(s)); + lua_error(L); + } +} + +#define CHK(pred) do { \ + upb_status status = UPB_STATUS_INIT; \ + pred; \ + lupb_checkstatus(L, &status); \ + } while (0) + + +/* refcounted *****************************************************************/ + +// All upb objects that use upb_refcounted share a common Lua userdata +// representation and a common scheme for caching Lua wrapper object. They do +// however have different metatables. Objects are cached in a weak table +// indexed by the C pointer of the object they are caching. + +typedef union { + const upb_refcounted *refcounted; + const upb_def *def; + upb_symtab *symtab; +} lupb_refcounted; + +static bool lupb_refcounted_pushwrapper(lua_State *L, const upb_refcounted *obj, + const char *type, const void *owner) { + if (obj == NULL) { + lua_pushnil(L); + return false; + } + + // Lookup our cache in the registry (we don't put our objects in the registry + // directly because we need our cache to be a weak table). + lupb_refcounted *ud = NULL; + lua_getfield(L, LUA_REGISTRYINDEX, LUPB_OBJCACHE); + assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb. + lua_pushlightuserdata(L, (void*)obj); + lua_rawget(L, -2); + // Stack: objcache, cached value. + bool create = lua_isnil(L, -1) || + // A corner case: it is possible for the value to be GC'd + // already, in which case we should evict this entry and create + // a new one. + ((lupb_refcounted*)lua_touserdata(L, -1))->refcounted == NULL; + if (create) { + // Remove bad cached value and push new value. + lua_pop(L, 1); + + // We take advantage of the fact that all of our objects are currently a + // single pointer, and thus have the same layout. + // TODO: this probably violates aliasing. + ud = lua_newuserdata(L, sizeof(lupb_refcounted)); + ud->refcounted = obj; + upb_refcounted_donateref(obj, owner, ud); + + luaL_getmetatable(L, type); + assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb. + lua_setmetatable(L, -2); + + // Set it in the cache. + lua_pushlightuserdata(L, (void*)obj); + lua_pushvalue(L, -2); + lua_rawset(L, -4); + } else { + // Existing wrapper obj already has a ref. + ud = lua_touserdata(L, -1); + upb_refcounted_checkref(obj, ud); + if (owner) + upb_refcounted_unref(obj, owner); + } + lua_insert(L, -2); + lua_pop(L, 1); + return create; +} + +static void lupb_refcounted_pushnewrapper(lua_State *L, upb_refcounted *obj, + const char *type, const void *owner) { + bool created = lupb_refcounted_pushwrapper(L, obj, type, owner); + UPB_ASSERT_VAR(created, created == true); +} + + +/* lupb_def *******************************************************************/ + +static const upb_def *lupb_def_check(lua_State *L, int narg) { + lupb_refcounted *r = luaL_testudata(L, narg, LUPB_MSGDEF); + if (!r) r = luaL_testudata(L, narg, LUPB_ENUMDEF); + if (!r) r = luaL_testudata(L, narg, LUPB_FIELDDEF); + if (!r) luaL_typerror(L, narg, "upb def"); + if (!r->refcounted) luaL_error(L, "called into dead def"); + return r->def; +} + +static upb_def *lupb_def_checkmutable(lua_State *L, int narg) { + const upb_def *def = lupb_def_check(L, narg); + if (upb_def_isfrozen(def)) + luaL_typerror(L, narg, "not allowed on frozen value"); + return (upb_def*)def; +} + +bool lupb_def_pushwrapper(lua_State *L, const upb_def *def, const void *owner) { + if (def == NULL) { + lua_pushnil(L); + return false; + } + + const char *type = NULL; + switch (def->type) { + case UPB_DEF_MSG: type = LUPB_MSGDEF; break; + case UPB_DEF_ENUM: type = LUPB_ENUMDEF; break; + case UPB_DEF_FIELD: type = LUPB_FIELDDEF; break; + default: luaL_error(L, "unknown deftype %d", def->type); + } + return lupb_refcounted_pushwrapper(L, UPB_UPCAST(def), type, owner); +} + +void lupb_def_pushnewrapper(lua_State *L, const upb_def *def, + const void *owner) { + bool created = lupb_def_pushwrapper(L, def, owner); + UPB_ASSERT_VAR(created, created == true); +} + +static int lupb_def_type(lua_State *L) { + const upb_def *def = lupb_def_check(L, 1); + lua_pushnumber(L, upb_def_type(def)); + return 1; +} + +static int lupb_def_isfrozen(lua_State *L) { + const upb_def *def = lupb_def_check(L, 1); + lua_pushboolean(L, upb_def_isfrozen(def)); + return 1; +} + +static int lupb_def_fullname(lua_State *L) { + const upb_def *def = lupb_def_check(L, 1); + lua_pushstring(L, upb_def_fullname(def)); + return 1; +} + +static int lupb_def_setfullname(lua_State *L) { + CHK(upb_def_setfullname(lupb_def_checkmutable(L, 1), chkname(L, 2), &status)); + return 0; +} + +#define LUPB_COMMON_DEF_METHODS \ + {"def_type", lupb_def_type}, \ + {"full_name", lupb_def_fullname}, \ + {"is_frozen", lupb_def_isfrozen}, \ + {"set_full_name", lupb_def_setfullname}, \ + + +/* lupb_fielddef **************************************************************/ + +static const upb_fielddef *lupb_fielddef_check(lua_State *L, int narg) { + lupb_refcounted *r = luaL_checkudata(L, narg, LUPB_FIELDDEF); + if (!r) luaL_typerror(L, narg, "upb fielddef"); + if (!r->refcounted) luaL_error(L, "called into dead fielddef"); + return upb_downcast_fielddef(r->def); +} + +static upb_fielddef *lupb_fielddef_checkmutable(lua_State *L, int narg) { + const upb_fielddef *f = lupb_fielddef_check(L, narg); + if (upb_fielddef_isfrozen(f)) + luaL_typerror(L, narg, "not allowed on frozen value"); + return (upb_fielddef*)f; +} + +// Setter functions; these are called by both the constructor and the individual +// setter API calls like field:set_type(). + +static void lupb_fielddef_dosetdefault(lua_State *L, upb_fielddef *f, + int narg) { + int type = lua_type(L, narg); + upb_fieldtype_t upbtype = upb_fielddef_type(f); + if (type == LUA_TSTRING) { + if (!upb_fielddef_isstring(f) && upbtype != UPB_TYPE_ENUM) + luaL_argerror(L, narg, "field does not expect a string default"); + size_t len; + const char *str = lua_tolstring(L, narg, &len); + CHK(upb_fielddef_setdefaultstr(f, str, len, &status)); + } else { + lupb_setdefault(L, narg, f); + } +} + +static void lupb_fielddef_dosetisextension(lua_State *L, upb_fielddef *f, + int narg) { + CHK(upb_fielddef_setisextension(f, chkbool(L, narg, "is_extension"))); +} + +static void lupb_fielddef_dosetlabel(lua_State *L, upb_fielddef *f, int narg) { + int label = luaL_checkint(L, narg); + if (!upb_fielddef_checklabel(label)) + luaL_argerror(L, narg, "invalid field label"); + upb_fielddef_setlabel(f, label); +} + +static void lupb_fielddef_dosetname(lua_State *L, upb_fielddef *f, int narg) { + CHK(upb_fielddef_setname(f, chkname(L, narg), &status)); +} + +static void lupb_fielddef_dosetnumber(lua_State *L, upb_fielddef *f, int narg) { + CHK(upb_fielddef_setnumber(f, luaL_checkint(L, narg), &status)); +} + +static void lupb_fielddef_dosetsubdef(lua_State *L, upb_fielddef *f, int narg) { + const upb_def *def = NULL; + if (!lua_isnil(L, narg)) + def = lupb_def_check(L, narg); + CHK(upb_fielddef_setsubdef(f, def, &status)); +} + +static void lupb_fielddef_dosetsubdefname(lua_State *L, upb_fielddef *f, + int narg) { + const char *name = NULL; + if (!lua_isnil(L, narg)) + name = chkname(L, narg); + CHK(upb_fielddef_setsubdefname(f, name, &status)); +} + +static void lupb_fielddef_dosetcontainingtypename(lua_State *L, upb_fielddef *f, + int narg) { + const char *name = NULL; + if (!lua_isnil(L, narg)) + name = chkname(L, narg); + CHK(upb_fielddef_setcontainingtypename(f, name, &status)); +} + +static void lupb_fielddef_dosettype(lua_State *L, upb_fielddef *f, int narg) { + int type = luaL_checkint(L, narg); + if (!upb_fielddef_checktype(type)) + luaL_argerror(L, narg, "invalid field type"); + upb_fielddef_settype(f, type); +} + +static void lupb_fielddef_dosetintfmt(lua_State *L, upb_fielddef *f, int narg) { + int32_t intfmt = luaL_checknumber(L, narg); + if (!upb_fielddef_checkintfmt(intfmt)) + luaL_argerror(L, narg, "invalid intfmt"); + upb_fielddef_setintfmt(f, intfmt); +} + +static void lupb_fielddef_dosettagdelim(lua_State *L, upb_fielddef *f, + int narg) { + CHK(upb_fielddef_settagdelim(f, chkbool(L, narg, "tagdelim"))); +} + +// Setter API calls. These use the setter functions above. + +static int lupb_fielddef_setcontainingtypename(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetcontainingtypename(L, f, 2); + return 0; +} + +static int lupb_fielddef_setdefault(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetdefault(L, f, 2); + return 0; +} + +static int lupb_fielddef_setisextension(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetisextension(L, f, 2); + return 0; +} + +static int lupb_fielddef_setlabel(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetlabel(L, f, 2); + return 0; +} + +static int lupb_fielddef_setname(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetname(L, f, 2); + return 0; +} + +static int lupb_fielddef_setnumber(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetnumber(L, f, 2); + return 0; +} + +static int lupb_fielddef_setsubdef(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetsubdef(L, f, 2); + return 0; +} + +static int lupb_fielddef_setsubdefname(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetsubdefname(L, f, 2); + return 0; +} + +static int lupb_fielddef_settype(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosettype(L, f, 2); + return 0; +} + +static int lupb_fielddef_setintfmt(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetintfmt(L, f, 2); + return 0; +} + +static int lupb_fielddef_settagdelim(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosettagdelim(L, f, 2); + return 0; +} + +// Constructor and other methods. + +static int lupb_fielddef_new(lua_State *L) { + upb_fielddef *f = upb_fielddef_new(&f); + int narg = lua_gettop(L); + + lupb_def_pushnewrapper(L, UPB_UPCAST(f), &f); + + if (narg == 0) return 1; + + // User can specify initialization values like so: + // upb.FieldDef{label=upb.LABEL_REQUIRED, name="my_field", number=5, + // type=upb.TYPE_INT32, default_value=12, type_name="Foo"} + luaL_checktype(L, 1, LUA_TTABLE); + for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) { + luaL_checktype(L, -2, LUA_TSTRING); + const char *key = lua_tostring(L, -2); + int v = -1; + if (streql(key, "name")) lupb_fielddef_dosetname(L, f, v); + else if (streql(key, "number")) lupb_fielddef_dosetnumber(L, f, v); + else if (streql(key, "type")) lupb_fielddef_dosettype(L, f, v); + else if (streql(key, "label")) lupb_fielddef_dosetlabel(L, f, v); + else if (streql(key, "is_extension")) + lupb_fielddef_dosetisextension(L, f, v); + else if (streql(key, "containing_type_name")) + lupb_fielddef_dosetcontainingtypename(L, f, v); + else if (streql(key, "default_value")) ; // Defer to second pass. + else if (streql(key, "subdef")) ; // Defer to second pass. + else if (streql(key, "subdef_name")) ; // Defer to second pass. + else luaL_error(L, "Cannot set fielddef member '%s'", key); + } + + // Have to do these in a second pass because these depend on the type, so we + // have to make sure the type is set if the user specified one. + for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) { + const char *key = lua_tostring(L, -2); + int v = -1; + if (streql(key, "default_value")) lupb_fielddef_dosetdefault(L, f, v); + else if (streql(key, "subdef")) lupb_fielddef_dosetsubdef(L, f, v); + else if (streql(key, "subdef_name")) lupb_fielddef_dosetsubdefname(L, f, v); + } + + return 1; +} + +static int lupb_fielddef_default(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + switch (upb_fielddef_type(f)) { + case UPB_TYPE_INT32: + int32: + lua_pushnumber(L, upb_fielddef_defaultint32(f)); break; + case UPB_TYPE_INT64: + lua_pushnumber(L, upb_fielddef_defaultint64(f)); break; + case UPB_TYPE_UINT32: + lua_pushnumber(L, upb_fielddef_defaultuint32(f)); break; + case UPB_TYPE_UINT64: + lua_pushnumber(L, upb_fielddef_defaultuint64(f)); break; + case UPB_TYPE_DOUBLE: + lua_pushnumber(L, upb_fielddef_defaultdouble(f)); break; + case UPB_TYPE_FLOAT: + lua_pushnumber(L, upb_fielddef_defaultfloat(f)); break; + case UPB_TYPE_BOOL: + lua_pushboolean(L, upb_fielddef_defaultbool(f)); break; + case UPB_TYPE_ENUM: + if (!upb_fielddef_default_is_symbolic(f)) + goto int32; + // Fallthrough. + case UPB_TYPE_STRING: + case UPB_TYPE_BYTES: { + size_t len; + const char *data = upb_fielddef_defaultstr(f, &len); + lua_pushlstring(L, data, len); + break; + } + case UPB_TYPE_MESSAGE: + return luaL_error(L, "Message fields do not have explicit defaults."); + } + return 1; +} + +static int lupb_fielddef_getsel(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + upb_selector_t sel; + if (upb_handlers_getselector(f, luaL_checknumber(L, 2), &sel)) { + lua_pushnumber(L, sel); + return 1; + } else { + return 0; + } +} + +static int lupb_fielddef_label(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + lua_pushnumber(L, upb_fielddef_label(f)); + return 1; +} + +static int lupb_fielddef_name(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + lua_pushstring(L, upb_fielddef_name(f)); + return 1; +} + +static int lupb_fielddef_number(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + int32_t num = upb_fielddef_number(f); + if (num) + lua_pushnumber(L, num); + else + lua_pushnil(L); + return 1; +} + +static int lupb_fielddef_selectorbase(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + if (!upb_fielddef_isfrozen(f)) + luaL_error(L, "_selectorbase is only defined for frozen fielddefs"); + lua_pushnumber(L, f->selector_base); + return 1; +} + +static int lupb_fielddef_hassubdef(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + lua_pushboolean(L, upb_fielddef_hassubdef(f)); + return 1; +} + +static int lupb_fielddef_containingtype(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + lupb_def_pushwrapper(L, UPB_UPCAST(upb_fielddef_containingtype(f)), NULL); + return 1; +} + +static int lupb_fielddef_containingtypename(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lua_pushstring(L, upb_fielddef_containingtypename(f)); + return 1; +} + +static int lupb_fielddef_subdef(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + if (!upb_fielddef_hassubdef(f)) + luaL_error(L, "Tried to get subdef of non-message field"); + const upb_def *def = upb_fielddef_subdef(f); + lupb_def_pushwrapper(L, def, NULL); + return 1; +} + +static int lupb_fielddef_subdefname(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + if (!upb_fielddef_hassubdef(f)) + luaL_error(L, "Tried to get subdef name of non-message field"); + lua_pushstring(L, upb_fielddef_subdefname(f)); + return 1; +} + +static int lupb_fielddef_type(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + if (upb_fielddef_typeisset(f)) + lua_pushnumber(L, upb_fielddef_type(f)); + else + lua_pushnil(L); + return 1; +} + +static int lupb_fielddef_index(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + lua_pushnumber(L, upb_fielddef_index(f)); + return 1; +} + +static int lupb_fielddef_intfmt(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + lua_pushnumber(L, upb_fielddef_intfmt(f)); + return 1; +} + +static int lupb_fielddef_isextension(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + lua_pushboolean(L, upb_fielddef_isextension(f)); + return 1; +} + +static int lupb_fielddef_istagdelim(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + lua_pushboolean(L, upb_fielddef_istagdelim(f)); + return 1; +} + +static int lupb_fielddef_gc(lua_State *L) { + lupb_refcounted *r = luaL_checkudata(L, 1, LUPB_FIELDDEF); + upb_def_unref(r->def, r); + r->refcounted = NULL; + return 0; +} + +static const struct luaL_Reg lupb_fielddef_m[] = { + LUPB_COMMON_DEF_METHODS + + {"containing_type", lupb_fielddef_containingtype}, + {"containing_type_name", lupb_fielddef_containingtypename}, + {"default", lupb_fielddef_default}, + {"getsel", lupb_fielddef_getsel}, + {"has_subdef", lupb_fielddef_hassubdef}, + {"index", lupb_fielddef_index}, + {"intfmt", lupb_fielddef_intfmt}, + {"is_extension", lupb_fielddef_isextension}, + {"istagdelim", lupb_fielddef_istagdelim}, + {"label", lupb_fielddef_label}, + {"name", lupb_fielddef_name}, + {"number", lupb_fielddef_number}, + {"subdef", lupb_fielddef_subdef}, + {"subdef_name", lupb_fielddef_subdefname}, + {"type", lupb_fielddef_type}, + + {"set_containing_type_name", lupb_fielddef_setcontainingtypename}, + {"set_default", lupb_fielddef_setdefault}, + {"set_is_extension", lupb_fielddef_setisextension}, + {"set_label", lupb_fielddef_setlabel}, + {"set_name", lupb_fielddef_setname}, + {"set_number", lupb_fielddef_setnumber}, + {"set_subdef", lupb_fielddef_setsubdef}, + {"set_subdef_name", lupb_fielddef_setsubdefname}, + {"set_type", lupb_fielddef_settype}, + {"set_intfmt", lupb_fielddef_setintfmt}, + {"set_tagdelim", lupb_fielddef_settagdelim}, + + // Internal-only. + {"_selector_base", lupb_fielddef_selectorbase}, + + {NULL, NULL} +}; + +static const struct luaL_Reg lupb_fielddef_mm[] = { + {"__gc", lupb_fielddef_gc}, + {NULL, NULL} +}; + + +/* lupb_msgdef ****************************************************************/ + +const upb_msgdef *lupb_msgdef_check(lua_State *L, int narg) { + lupb_refcounted *r = luaL_checkudata(L, narg, LUPB_MSGDEF); + if (!r) luaL_typerror(L, narg, LUPB_MSGDEF); + if (!r->refcounted) luaL_error(L, "called into dead msgdef"); + return upb_downcast_msgdef(r->def); +} + +static upb_msgdef *lupb_msgdef_checkmutable(lua_State *L, int narg) { + const upb_msgdef *m = lupb_msgdef_check(L, narg); + if (upb_msgdef_isfrozen(m)) + luaL_typerror(L, narg, "not allowed on frozen value"); + return (upb_msgdef*)m; +} + +static int lupb_msgdef_gc(lua_State *L) { + lupb_refcounted *r = luaL_checkudata(L, 1, LUPB_MSGDEF); + upb_def_unref(r->def, r); + r->refcounted = NULL; + return 0; +} + +static int lupb_msgdef_new(lua_State *L) { + int narg = lua_gettop(L); + upb_msgdef *md = upb_msgdef_new(&md); + lupb_def_pushnewrapper(L, UPB_UPCAST(md), &md); + + if (narg == 0) return 1; + + // User can specify initialization values like so: + // upb.MessageDef{full_name="MyMessage", extstart=8000, fields={...}} + luaL_checktype(L, 1, LUA_TTABLE); + for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) { + luaL_checktype(L, -2, LUA_TSTRING); + const char *key = lua_tostring(L, -2); + + if (streql(key, "full_name")) { // full_name="MyMessage" + CHK(upb_def_setfullname(UPB_UPCAST(md), chkname(L, -1), &status)); + } else if (streql(key, "fields")) { // fields={...} + // Iterate over the list of fields. + luaL_checktype(L, -1, LUA_TTABLE); + for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, -1); + CHK(upb_msgdef_addfield(md, f, NULL, &status)); + } + } else { + // TODO: extrange= + luaL_error(L, "Unknown initializer key '%s'", key); + } + } + return 1; +} + +static int lupb_msgdef_add(lua_State *L) { + upb_msgdef *m = lupb_msgdef_checkmutable(L, 1); + luaL_checktype(L, 2, LUA_TTABLE); + int n = lua_rawlen(L, 2); + // TODO: add upb interface that lets us avoid this malloc/free. + upb_fielddef **fields = malloc(n * sizeof(upb_fielddef*)); + for (int i = 0; i < n; i++) { + lua_rawgeti(L, -1, i + 1); + fields[i] = lupb_fielddef_checkmutable(L, -1); + lua_pop(L, 1); + } + + upb_status status = UPB_STATUS_INIT; + upb_msgdef_addfields(m, fields, n, NULL, &status); + free(fields); + lupb_checkstatus(L, &status); + return 0; +} + +static int lupb_msgdef_len(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + lua_pushinteger(L, upb_msgdef_numfields(m)); + return 1; +} + +static int lupb_msgdef_selectorcount(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + lua_pushinteger(L, m->selector_count); + return 1; +} + +static int lupb_msgdef_submsgfieldcount(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + lua_pushinteger(L, m->submsg_field_count); + return 1; +} + +static int lupb_msgdef_field(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + int type = lua_type(L, 2); + const upb_fielddef *f; + if (type == LUA_TNUMBER) { + f = upb_msgdef_itof(m, lua_tointeger(L, 2)); + } else if (type == LUA_TSTRING) { + f = upb_msgdef_ntof(m, lua_tostring(L, 2)); + } else { + const char *msg = lua_pushfstring(L, "number or string expected, got %s", + luaL_typename(L, 2)); + return luaL_argerror(L, 2, msg); + } + + lupb_def_pushwrapper(L, UPB_UPCAST(f), NULL); + return 1; +} + +static int lupb_msgiter_next(lua_State *L) { + upb_msg_iter *i = lua_touserdata(L, lua_upvalueindex(1)); + if (upb_msg_done(i)) return 0; + lupb_def_pushwrapper(L, UPB_UPCAST(upb_msg_iter_field(i)), NULL); + upb_msg_next(i); + return 1; +} + +static int lupb_msgdef_fields(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + upb_msg_iter *i = lua_newuserdata(L, sizeof(upb_msg_iter)); + upb_msg_begin(i, m); + lua_pushcclosure(L, &lupb_msgiter_next, 1); + return 1; +} + +static const struct luaL_Reg lupb_msgdef_mm[] = { + {"__gc", lupb_msgdef_gc}, + {"__len", lupb_msgdef_len}, + {NULL, NULL} +}; + +static const struct luaL_Reg lupb_msgdef_m[] = { + LUPB_COMMON_DEF_METHODS + {"add", lupb_msgdef_add}, + {"field", lupb_msgdef_field}, + {"fields", lupb_msgdef_fields}, + + // Internal-only. + {"_selector_count", lupb_msgdef_selectorcount}, + {"_submsg_field_count", lupb_msgdef_submsgfieldcount}, + + {NULL, NULL} +}; + + +/* lupb_enumdef ***************************************************************/ + +const upb_enumdef *lupb_enumdef_check(lua_State *L, int narg) { + lupb_refcounted *r = luaL_checkudata(L, narg, LUPB_ENUMDEF); + if (!r) luaL_typerror(L, narg, LUPB_ENUMDEF); + if (!r->refcounted) luaL_error(L, "called into dead enumdef"); + return upb_downcast_enumdef(r->def); +} + +static upb_enumdef *lupb_enumdef_checkmutable(lua_State *L, int narg) { + const upb_enumdef *f = lupb_enumdef_check(L, narg); + if (upb_enumdef_isfrozen(f)) + luaL_typerror(L, narg, "not allowed on frozen value"); + return (upb_enumdef*)f; +} + +static int lupb_enumdef_gc(lua_State *L) { + lupb_refcounted *r = luaL_checkudata(L, 1, LUPB_ENUMDEF); + upb_def_unref(r->def, r); + r->refcounted = NULL; + return 0; +} + +static int lupb_enumdef_new(lua_State *L) { + int narg = lua_gettop(L); + upb_enumdef *e = upb_enumdef_new(&e); + lupb_def_pushnewrapper(L, UPB_UPCAST(e), &e); + + if (narg == 0) return 1; + + // User can specify initialization values like so: + // upb.EnumDef{full_name="MyEnum", + // values={ + // {"FOO_VALUE_1", 1}, + // {"FOO_VALUE_2", 2} + // } + // } + luaL_checktype(L, 1, LUA_TTABLE); + for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) { + luaL_checktype(L, -2, LUA_TSTRING); + const char *key = lua_tostring(L, -2); + if (streql(key, "values")) { + for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { + lua_rawgeti(L, -1, 1); + luaL_checktype(L, -1, LUA_TSTRING); + const char *name = lua_tostring(L, -1); + lua_rawgeti(L, -2, 2); + CHK(upb_enumdef_addval(e, name, chkint32(L, -1, "value"), &status)); + lua_pop(L, 2); // The key/val we got from lua_rawgeti() + } + } else if (streql(key, "full_name")) { + CHK(upb_def_setfullname(UPB_UPCAST(e), chkname(L, -1), &status)); + } else { + luaL_error(L, "Unknown initializer key '%s'", key); + } + } + return 1; +} + +static int lupb_enumdef_add(lua_State *L) { + upb_enumdef *e = lupb_enumdef_checkmutable(L, 1); + CHK(upb_enumdef_addval(e, chkname(L, 2), chkint32(L, 3, "value"), &status)); + return 0; +} + +static int lupb_enumdef_len(lua_State *L) { + const upb_enumdef *e = lupb_enumdef_check(L, 1); + lua_pushinteger(L, upb_enumdef_numvals(e)); + return 1; +} + +static int lupb_enumdef_value(lua_State *L) { + const upb_enumdef *e = lupb_enumdef_check(L, 1); + int type = lua_type(L, 2); + if (type == LUA_TNUMBER) { + // Pushes "nil" for a NULL pointer. + lua_pushstring(L, upb_enumdef_iton(e, chkint32(L, 2, "value"))); + } else if (type == LUA_TSTRING) { + int32_t num; + if (upb_enumdef_ntoi(e, lua_tostring(L, 2), &num)) { + lua_pushnumber(L, num); + } else { + lua_pushnil(L); + } + } else { + const char *msg = lua_pushfstring(L, "number or string expected, got %s", + luaL_typename(L, 2)); + return luaL_argerror(L, 2, msg); + } + return 1; +} + +static int lupb_enumiter_next(lua_State *L) { + upb_enum_iter *i = lua_touserdata(L, lua_upvalueindex(1)); + if (upb_enum_done(i)) return 0; + lua_pushstring(L, upb_enum_iter_name(i)); + lua_pushnumber(L, upb_enum_iter_number(i)); + upb_enum_next(i); + return 2; +} + +static int lupb_enumdef_values(lua_State *L) { + const upb_enumdef *e = lupb_enumdef_check(L, 1); + upb_enum_iter *i = lua_newuserdata(L, sizeof(upb_enum_iter)); + upb_enum_begin(i, e); + lua_pushcclosure(L, &lupb_enumiter_next, 1); + return 1; +} + +static const struct luaL_Reg lupb_enumdef_mm[] = { + {"__gc", lupb_enumdef_gc}, + {"__len", lupb_enumdef_len}, + {NULL, NULL} +}; + +static const struct luaL_Reg lupb_enumdef_m[] = { + LUPB_COMMON_DEF_METHODS + {"add", lupb_enumdef_add}, + {"value", lupb_enumdef_value}, + {"values", lupb_enumdef_values}, + {NULL, NULL} +}; + + +/* lupb_symtab ****************************************************************/ + +// Inherits a ref on the symtab. +// Checks that narg is a proper lupb_symtab object. If it is, leaves its +// metatable on the stack for cache lookups/updates. +upb_symtab *lupb_symtab_check(lua_State *L, int narg) { + lupb_refcounted *r = luaL_checkudata(L, narg, LUPB_SYMTAB); + if (!r) luaL_typerror(L, narg, LUPB_SYMTAB); + if (!r->refcounted) luaL_error(L, "called into dead symtab"); + return r->symtab; +} + +// narg is a lua table containing a list of defs to add. +void lupb_symtab_doadd(lua_State *L, upb_symtab *s, int narg) { + luaL_checktype(L, narg, LUA_TTABLE); + // Iterate over table twice. First iteration to count entries and + // check constraints. + int n = 0; + for (lua_pushnil(L); lua_next(L, narg); lua_pop(L, 1)) { + lupb_def_check(L, -1); + ++n; + } + + // Second iteration to build deflist and layout. + upb_def **defs = malloc(n * sizeof(*defs)); + n = 0; + for (lua_pushnil(L); lua_next(L, narg); lua_pop(L, 1)) { + upb_def *def = lupb_def_checkmutable(L, -1); + defs[n++] = def; + } + + upb_status status = UPB_STATUS_INIT; + upb_symtab_add(s, defs, n, NULL, &status); + free(defs); + lupb_checkstatus(L, &status); +} + +static int lupb_symtab_new(lua_State *L) { + int narg = lua_gettop(L); + upb_symtab *s = upb_symtab_new(&s); + lupb_refcounted_pushnewrapper(L, UPB_UPCAST(s), LUPB_SYMTAB, &s); + if (narg > 0) lupb_symtab_doadd(L, s, 1); + return 1; +} + +static int lupb_symtab_add(lua_State *L) { + lupb_symtab_doadd(L, lupb_symtab_check(L, 1), 2); + return 0; +} + +static int lupb_symtab_gc(lua_State *L) { + lupb_refcounted *r = luaL_checkudata(L, 1, LUPB_SYMTAB); + upb_symtab_unref(r->symtab, r); + r->refcounted = NULL; + return 0; +} + +static int lupb_symtab_lookup(lua_State *L) { + upb_symtab *s = lupb_symtab_check(L, 1); + for (int i = 2; i <= lua_gettop(L); i++) { + const upb_def *def = + upb_symtab_lookup(s, luaL_checkstring(L, i), &def); + lupb_def_pushwrapper(L, def, &def); + lua_replace(L, i); + } + return lua_gettop(L) - 1; +} + +static int lupb_symtab_getdefs(lua_State *L) { + upb_symtab *s = lupb_symtab_check(L, 1); + upb_deftype_t type = luaL_checkint(L, 2); + int count; + const upb_def **defs = upb_symtab_getdefs(s, type, &defs, &count); + + // Create the table in which we will return the defs. + lua_createtable(L, count, 0); + for (int i = 0; i < count; i++) { + const upb_def *def = defs[i]; + lupb_def_pushwrapper(L, def, &defs); + lua_rawseti(L, -2, i + 1); + } + free(defs); + return 1; +} + +// This is a *temporary* API that will be removed once pending refactorings are +// complete (it does not belong here in core because it depends on both +// the descriptor.proto schema and the protobuf binary format. +static int lupb_symtab_load_descriptor(lua_State *L) { + size_t len; + upb_symtab *s = lupb_symtab_check(L, 1); + const char *str = luaL_checklstring(L, 2, &len); + CHK(upb_load_descriptor_into_symtab(s, str, len, &status)); + return 0; +} + +static const struct luaL_Reg lupb_symtab_m[] = { + {"add", lupb_symtab_add}, + {"getdefs", lupb_symtab_getdefs}, + {"lookup", lupb_symtab_lookup}, + {"load_descriptor", lupb_symtab_load_descriptor}, + {NULL, NULL} +}; + +static const struct luaL_Reg lupb_symtab_mm[] = { + {"__gc", lupb_symtab_gc}, + {NULL, NULL} +}; + + +/* lupb toplevel **************************************************************/ + +static int lupb_def_freeze(lua_State *L) { + int n = lua_gettop(L); + upb_def **defs = malloc(n * sizeof(upb_def*)); + for (int i = 0; i < n; i++) { + // Could allow an array of defs here also. + defs[i] = lupb_def_checkmutable(L, i + 1); + } + upb_status s = UPB_STATUS_INIT; + upb_def_freeze(defs, n, &s); + free(defs); + lupb_checkstatus(L, &s); + return 0; +} + +static const struct luaL_Reg lupb_toplevel_m[] = { + {"EnumDef", lupb_enumdef_new}, + {"FieldDef", lupb_fielddef_new}, + {"MessageDef", lupb_msgdef_new}, + {"SymbolTable", lupb_symtab_new}, + {"freeze", lupb_def_freeze}, + + {NULL, NULL} +}; + +// Register the given type with the given methods and metamethods. +static void lupb_register_type(lua_State *L, const char *name, + const luaL_Reg *m, const luaL_Reg *mm) { + luaL_newmetatable(L, name); + lupb_setfuncs(L, mm); // Register all mm in the metatable. + lua_createtable(L, 0, 0); + // Methods go in the mt's __index method. This implies that you can't + // implement __index. + lupb_setfuncs(L, m); + lua_setfield(L, -2, "__index"); + lua_pop(L, 1); // The mt. +} + +static void lupb_setfieldi(lua_State *L, const char *field, int i) { + lua_pushnumber(L, i); + lua_setfield(L, -2, field); +} + +int luaopen_upb(lua_State *L) { + lupb_register_type(L, LUPB_MSGDEF, lupb_msgdef_m, lupb_msgdef_mm); + lupb_register_type(L, LUPB_ENUMDEF, lupb_enumdef_m, lupb_enumdef_mm); + lupb_register_type(L, LUPB_FIELDDEF, lupb_fielddef_m, lupb_fielddef_mm); + lupb_register_type(L, LUPB_SYMTAB, lupb_symtab_m, lupb_symtab_mm); + + // Create our object cache. + lua_newtable(L); + lua_createtable(L, 0, 1); // Cache metatable. + lua_pushstring(L, "v"); // Values are weak. + lua_setfield(L, -2, "__mode"); + lua_setmetatable(L, -2); + lua_setfield(L, LUA_REGISTRYINDEX, LUPB_OBJCACHE); + + lupb_newlib(L, "upb", lupb_toplevel_m); + + // Define a couple functions as Lua source (kept here instead of a separate + // Lua file so that upb.so is self-contained) + const char *lua_source = + "return function(upb)\n" + " upb.build_defs = function(defs)\n" + " local symtab = upb.SymbolTable(defs)\n" + " return symtab:getdefs(upb.DEF_ANY)\n" + " end\n" + "end"; + + if (luaL_dostring(L, lua_source) != 0) + lua_error(L); + + // Call the chunk that will define the extra functions on upb, passing our + // package dictionary as the argument. + lua_pushvalue(L, -2); + lua_call(L, 1, 0); + + // Register constants. + lupb_setfieldi(L, "LABEL_OPTIONAL", UPB_LABEL_OPTIONAL); + lupb_setfieldi(L, "LABEL_REQUIRED", UPB_LABEL_REQUIRED); + lupb_setfieldi(L, "LABEL_REPEATED", UPB_LABEL_REPEATED); + + lupb_setfieldi(L, "TYPE_DOUBLE", UPB_TYPE_DOUBLE); + lupb_setfieldi(L, "TYPE_FLOAT", UPB_TYPE_FLOAT); + lupb_setfieldi(L, "TYPE_INT64", UPB_TYPE_INT64); + lupb_setfieldi(L, "TYPE_UINT64", UPB_TYPE_UINT64); + lupb_setfieldi(L, "TYPE_INT32", UPB_TYPE_INT32); + lupb_setfieldi(L, "TYPE_BOOL", UPB_TYPE_BOOL); + lupb_setfieldi(L, "TYPE_STRING", UPB_TYPE_STRING); + lupb_setfieldi(L, "TYPE_MESSAGE", UPB_TYPE_MESSAGE); + lupb_setfieldi(L, "TYPE_BYTES", UPB_TYPE_BYTES); + lupb_setfieldi(L, "TYPE_UINT32", UPB_TYPE_UINT32); + lupb_setfieldi(L, "TYPE_ENUM", UPB_TYPE_ENUM); + + lupb_setfieldi(L, "INTFMT_VARIABLE", UPB_INTFMT_VARIABLE); + lupb_setfieldi(L, "INTFMT_FIXED", UPB_INTFMT_FIXED); + lupb_setfieldi(L, "INTFMT_ZIGZAG", UPB_INTFMT_ZIGZAG); + + lupb_setfieldi(L, "DESCRIPTOR_TYPE_DOUBLE", UPB_DESCRIPTOR_TYPE_DOUBLE); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_FLOAT", UPB_DESCRIPTOR_TYPE_FLOAT); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_INT64", UPB_DESCRIPTOR_TYPE_INT64); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_UINT64", UPB_DESCRIPTOR_TYPE_UINT64); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_INT32", UPB_DESCRIPTOR_TYPE_INT32); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_FIXED64", UPB_DESCRIPTOR_TYPE_FIXED64); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_FIXED32", UPB_DESCRIPTOR_TYPE_FIXED32); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_BOOL", UPB_DESCRIPTOR_TYPE_BOOL); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_STRING", UPB_DESCRIPTOR_TYPE_STRING); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_GROUP", UPB_DESCRIPTOR_TYPE_GROUP); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_MESSAGE", UPB_DESCRIPTOR_TYPE_MESSAGE); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_BYTES", UPB_DESCRIPTOR_TYPE_BYTES); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_UINT32", UPB_DESCRIPTOR_TYPE_UINT32); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_ENUM", UPB_DESCRIPTOR_TYPE_ENUM); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_SFIXED32", UPB_DESCRIPTOR_TYPE_SFIXED32); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_SFIXED64", UPB_DESCRIPTOR_TYPE_SFIXED64); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_SINT32", UPB_DESCRIPTOR_TYPE_SINT32); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_SINT64", UPB_DESCRIPTOR_TYPE_SINT64); + + lupb_setfieldi(L, "DEF_MSG", UPB_DEF_MSG); + lupb_setfieldi(L, "DEF_FIELD", UPB_DEF_FIELD); + lupb_setfieldi(L, "DEF_ENUM", UPB_DEF_ENUM); + lupb_setfieldi(L, "DEF_SERVICE", UPB_DEF_SERVICE); + lupb_setfieldi(L, "DEF_ANY", UPB_DEF_ANY); + + lupb_setfieldi(L, "HANDLER_INT32", UPB_HANDLER_INT32); + lupb_setfieldi(L, "HANDLER_INT64", UPB_HANDLER_INT64); + lupb_setfieldi(L, "HANDLER_UINT32", UPB_HANDLER_UINT32); + lupb_setfieldi(L, "HANDLER_UINT64", UPB_HANDLER_UINT64); + lupb_setfieldi(L, "HANDLER_FLOAT", UPB_HANDLER_FLOAT); + lupb_setfieldi(L, "HANDLER_DOUBLE", UPB_HANDLER_DOUBLE); + lupb_setfieldi(L, "HANDLER_BOOL", UPB_HANDLER_BOOL); + lupb_setfieldi(L, "HANDLER_STARTSTR", UPB_HANDLER_STARTSTR); + lupb_setfieldi(L, "HANDLER_STRING", UPB_HANDLER_STRING); + lupb_setfieldi(L, "HANDLER_ENDSTR", UPB_HANDLER_ENDSTR); + lupb_setfieldi(L, "HANDLER_STARTSUBMSG", UPB_HANDLER_STARTSUBMSG); + lupb_setfieldi(L, "HANDLER_ENDSUBMSG", UPB_HANDLER_ENDSUBMSG); + lupb_setfieldi(L, "HANDLER_STARTSEQ", UPB_HANDLER_STARTSEQ); + lupb_setfieldi(L, "HANDLER_ENDSEQ", UPB_HANDLER_ENDSEQ); + + return 1; // Return package table. +} + +// Alternate names so that the library can be loaded as upb5_1 etc. +int LUPB_OPENFUNC(upb)(lua_State *L) { return luaopen_upb(L); } diff --git a/upb/bindings/lua/upb.h b/upb/bindings/lua/upb.h new file mode 100644 index 0000000..e6b4f2f --- /dev/null +++ b/upb/bindings/lua/upb.h @@ -0,0 +1,45 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2012 Google Inc. See LICENSE for details. + * Author: Josh Haberman <jhaberman@gmail.com> + * + * Shared definitions for upb Lua modules. + */ + +#ifndef UPB_LUA_UPB_H_ +#define UPB_LUA_UPB_H_ + +#include "upb/def.h" + +// Lua 5.1/5.2 compatibility code. +#if LUA_VERSION_NUM == 501 + +#define lua_rawlen lua_objlen +#define lupb_newlib(L, name, l) luaL_register(L, name, l) +#define lupb_setfuncs(L, l) luaL_register(L, NULL, l) +#define LUPB_OPENFUNC(mod) luaopen_ ## mod ## upb5_1 + +void *luaL_testudata(lua_State *L, int ud, const char *tname); + +#elif LUA_VERSION_NUM == 502 + +// Lua 5.2 modules are not expected to set a global variable, so "name" is +// unused. +#define lupb_newlib(L, name, l) luaL_newlib(L, l) +#define lupb_setfuncs(L, l) luaL_setfuncs(L, l, 0) +int luaL_typerror(lua_State *L, int narg, const char *tname); +#define LUPB_OPENFUNC(mod) luaopen_ ## mod ## upb5_2 + +#else +#error Only Lua 5.1 and 5.2 are supported +#endif + +const upb_msgdef *lupb_msgdef_check(lua_State *L, int narg); +const upb_enumdef *lupb_enumdef_check(lua_State *L, int narg); +const char *lupb_checkname(lua_State *L, int narg); +bool lupb_def_pushwrapper(lua_State *L, const upb_def *def, const void *owner); +void lupb_def_pushnewrapper(lua_State *L, const upb_def *def, + const void *owner); + +#endif // UPB_LUA_UPB_H_ diff --git a/upb/bindings/python/setup.py b/upb/bindings/python/setup.py new file mode 100644 index 0000000..8abaff8 --- /dev/null +++ b/upb/bindings/python/setup.py @@ -0,0 +1,14 @@ +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 new file mode 100644 index 0000000..29a6c45 --- /dev/null +++ b/upb/bindings/python/test.py @@ -0,0 +1,72 @@ + +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 new file mode 100644 index 0000000..497074b --- /dev/null +++ b/upb/bindings/python/upb.c @@ -0,0 +1,724 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2009 Google Inc. See LICENSE for details. + * Author: Josh Haberman <jhaberman@gmail.com> + * + * Python extension exposing the core of upb: definitions, handlers, + * and a message type. + */ + +#include <stddef.h> +#include <Python.h> +#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*)); + 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); + assert(ptr_str); + int err = PyDict_DelItem(obj_cache, ptr_str); + assert(!err); + err = PyDict_DelItem(reverse_cache, ref); + 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); + 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); + assert(PyWeakref_GetObject(ref) == ret); + assert(ref); + PyDict_SetItem(obj_cache, kv, ref); + PyDict_SetItem(reverse_cache, ref, kv); + } + 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_iter i; + for(i = upb_msg_begin(m); !upb_msg_done(i); i = upb_msg_next(m, i)) { + 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_iter j; + for(j = upb_msg_begin(md); !upb_msg_done(j); j = upb_msg_next(md, 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 new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/upb/bindings/python/upb/__init__.py diff --git a/upb/bindings/stdc++/string.h b/upb/bindings/stdc++/string.h new file mode 100644 index 0000000..668f3e3 --- /dev/null +++ b/upb/bindings/stdc++/string.h @@ -0,0 +1,60 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// Author: haberman@google.com (Josh Haberman) +// +// upb - a minimalist implementation of protocol buffers. + +#ifndef UPB_STDCPP_H_ +#define UPB_STDCPP_H_ + +namespace upb { + +template <class T> +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) { + T* str = static_cast<T*>(c); + str->clear(); + return c; + } + + static size_t StringBuf(void* c, const void* hd, const char* buf, size_t n, + const BufferHandle* h) { + T* str = static_cast<T*>(c); + try { + str->append(buf, n); + return n; + } catch (const std::exception&) { + return 0; + } + } +}; + +class StringSink { + public: + template <class T> + 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<T>::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/stdc/error.c b/upb/bindings/stdc/error.c index 85c9ca6..85c9ca6 100644 --- a/upb/stdc/error.c +++ b/upb/bindings/stdc/error.c diff --git a/upb/stdc/error.h b/upb/bindings/stdc/error.h index 9802097..9802097 100644 --- a/upb/stdc/error.h +++ b/upb/bindings/stdc/error.h diff --git a/upb/stdc/io.c b/upb/bindings/stdc/io.c index 5d36aa5..5d36aa5 100644 --- a/upb/stdc/io.c +++ b/upb/bindings/stdc/io.c diff --git a/upb/stdc/io.h b/upb/bindings/stdc/io.h index fd19bef..fd19bef 100644 --- a/upb/stdc/io.h +++ b/upb/bindings/stdc/io.h @@ -156,17 +156,17 @@ static bool upb_validate_field(upb_fielddef *f, upb_status *s) { if (subdef == NULL) { upb_status_seterrf(s, "field %s.%s is missing required subdef", - msgdef_name(f->msgdef), upb_fielddef_name(f)); + msgdef_name(f->msg.def), upb_fielddef_name(f)); return false; } else if (!upb_def_isfrozen(subdef) && !subdef->came_from_user) { upb_status_seterrf(s, "subdef of field %s.%s is not frozen or being frozen", - msgdef_name(f->msgdef), upb_fielddef_name(f)); + msgdef_name(f->msg.def), upb_fielddef_name(f)); return false; } else if (upb_fielddef_default_is_symbolic(f)) { upb_status_seterrf(s, "enum field %s.%s has not been resolved", - msgdef_name(f->msgdef), upb_fielddef_name(f)); + msgdef_name(f->msg.def), upb_fielddef_name(f)); return false; } } @@ -202,7 +202,7 @@ static bool assign_msg_indices(upb_msgdef *m, upb_status *s) { m->submsg_field_count = 0; for(i = 0, upb_msg_begin(&j, m); !upb_msg_done(&j); upb_msg_next(&j), i++) { upb_fielddef *f = upb_msg_iter_field(&j); - assert(f->msgdef == m); + assert(f->msg.def == m); if (!upb_validate_field(f, s)) { free(fields); return false; @@ -428,11 +428,11 @@ static void upb_fielddef_uninit_default(upb_fielddef *f) { static void visitfield(const upb_refcounted *r, upb_refcounted_visit *visit, void *closure) { const upb_fielddef *f = (const upb_fielddef*)r; - if (f->msgdef) { - visit(r, UPB_UPCAST2(f->msgdef), closure); + if (upb_fielddef_containingtype(f)) { + visit(r, UPB_UPCAST2(upb_fielddef_containingtype(f)), closure); } - if (!f->subdef_is_symbolic && f->sub.def) { - visit(r, UPB_UPCAST(f->sub.def), closure); + if (upb_fielddef_subdef(f)) { + visit(r, UPB_UPCAST(upb_fielddef_subdef(f)), closure); } } @@ -453,14 +453,16 @@ upb_fielddef *upb_fielddef_new(const void *owner) { free(f); return NULL; } - f->msgdef = NULL; + f->msg.def = NULL; f->sub.def = NULL; f->subdef_is_symbolic = false; + f->msg_is_symbolic = false; f->label_ = UPB_LABEL_OPTIONAL; f->type_ = UPB_TYPE_INT32; f->number_ = 0; f->type_is_set_ = false; f->tagdelim = false; + f->is_extension_ = false; // For the moment we default this to UPB_INTFMT_VARIABLE, since it will work // with all integer types and is in some since more "default" since the most @@ -559,16 +561,43 @@ uint32_t upb_fielddef_number(const upb_fielddef *f) { return f->number_; } +bool upb_fielddef_isextension(const upb_fielddef *f) { + return f->is_extension_; +} + const char *upb_fielddef_name(const upb_fielddef *f) { return upb_def_fullname(UPB_UPCAST(f)); } const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f) { - return f->msgdef; + return f->msg_is_symbolic ? NULL : f->msg.def; } upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f) { - return (upb_msgdef*)f->msgdef; + return (upb_msgdef*)upb_fielddef_containingtype(f); +} + +const char *upb_fielddef_containingtypename(upb_fielddef *f) { + return f->msg_is_symbolic ? f->msg.name : NULL; +} + +static void release_containingtype(upb_fielddef *f) { + if (f->msg_is_symbolic) free(f->msg.name); +} + +bool upb_fielddef_setcontainingtypename(upb_fielddef *f, const char *name, + upb_status *s) { + assert(!upb_fielddef_isfrozen(f)); + if (upb_fielddef_containingtype(f)) { + upb_status_seterrmsg(s, "field has already been added to a message."); + return false; + } + // TODO: validate name (upb_isident() doesn't quite work atm because this name + // may have a leading "."). + release_containingtype(f); + f->msg.name = upb_strdup(name); + f->msg_is_symbolic = true; + return true; } bool upb_fielddef_setname(upb_fielddef *f, const char *name, upb_status *s) { @@ -650,12 +679,7 @@ static void upb_fielddef_init_default(upb_fielddef *f) { } const upb_def *upb_fielddef_subdef(const upb_fielddef *f) { - if (upb_fielddef_hassubdef(f) && upb_fielddef_isfrozen(f)) { - assert(f->sub.def); - return f->sub.def; - } else { - return f->subdef_is_symbolic ? NULL : f->sub.def; - } + return f->subdef_is_symbolic ? NULL : f->sub.def; } const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f) { @@ -678,7 +702,7 @@ const char *upb_fielddef_subdefname(const upb_fielddef *f) { } bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number, upb_status *s) { - if (f->msgdef) { + if (upb_fielddef_containingtype(f)) { upb_status_seterrmsg( s, "cannot change field number after adding to a message"); return false; @@ -800,6 +824,12 @@ upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f) { return 0; } +bool upb_fielddef_setisextension(upb_fielddef *f, bool is_extension) { + assert(!upb_fielddef_isfrozen(f)); + f->is_extension_ = is_extension; + return true; +} + void upb_fielddef_setlabel(upb_fielddef *f, upb_label_t label) { assert(!upb_fielddef_isfrozen(f)); assert(upb_fielddef_checklabel(label)); @@ -980,6 +1010,8 @@ bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name, upb_status_seterrmsg(s, "field type does not accept a subdef"); return false; } + // TODO: validate name (upb_isident() doesn't quite work atm because this name + // may have a leading "."). release_subdef(f); f->sub.name = upb_strdup(name); f->subdef_is_symbolic = true; @@ -1104,12 +1136,23 @@ bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname, bool upb_msgdef_addfields(upb_msgdef *m, upb_fielddef *const *fields, int n, const void *ref_donor, upb_status *s) { + // TODO: extensions need to have a separate namespace, because proto2 allows a + // top-level extension (ie. one not in any package) to have the same name as a + // field from the message. + // + // This also implies that there needs to be a separate lookup-by-name method + // for extensions. It seems desirable for iteration to return both extensions + // and non-extensions though. + // + // We also need to validate that the field number is in an extension range iff + // it is an extension. + // Check constraints for all fields before performing any action. for (int i = 0; i < n; i++) { upb_fielddef *f = fields[i]; // TODO(haberman): handle the case where two fields of the input duplicate // name or number. - if (f->msgdef != NULL) { + if (upb_fielddef_containingtype(f) != NULL) { upb_status_seterrmsg(s, "fielddef already belongs to a message"); return false; } else if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) { @@ -1125,7 +1168,9 @@ bool upb_msgdef_addfields(upb_msgdef *m, upb_fielddef *const *fields, int n, // Constraint checks ok, perform the action. for (int i = 0; i < n; i++) { upb_fielddef *f = fields[i]; - f->msgdef = m; + release_containingtype(f); + f->msg.def = m; + f->msg_is_symbolic = false; upb_inttable_insert(&m->itof, upb_fielddef_number(f), upb_value_ptr(f)); upb_strtable_insert(&m->ntof, upb_fielddef_name(f), upb_value_ptr(f)); upb_ref2(f, m); @@ -272,6 +272,7 @@ class upb::FieldDef /* : public upb::Def */ { Label label() const; // Defaults to UPB_LABEL_OPTIONAL. const char* name() const; // NULL if uninitialized. uint32_t number() const; // Returns 0 if uninitialized. + bool is_extension() const; // An integer that can be used as an index into an array of fields for // whatever message this field belongs to. Guaranteed to be less than @@ -279,8 +280,21 @@ class upb::FieldDef /* : public upb::Def */ { // been finalized. int index() const; - // The MessageDef to which this field belongs, or NULL if none. + // The MessageDef to which this field belongs. + // + // If this field has been added to a MessageDef, that message can be retrieved + // directly (this is always the case for frozen FieldDefs). + // + // If the field has not yet been added to a MessageDef, you can set the name + // of the containing type symbolically instead. This is mostly useful for + // extensions, where the extension is declared separately from the message. const MessageDef* containing_type() const; + const char* containing_type_name(); + + // This may only be called if containing_type() == NULL (ie. the field has not + // been added to a message yet). + bool set_containing_type_name(const char *name, Status* status); + bool set_containing_type_name(const std::string& name, Status* status); // The field's type according to the enum in descriptor.proto. This is not // the same as UPB_TYPE_*, because it distinguishes between (for example) @@ -297,6 +311,7 @@ class upb::FieldDef /* : public upb::Def */ { void set_type(Type type); void set_label(Label label); void set_descriptor_type(DescriptorType type); + void set_is_extension(bool is_extension); // "number" and "name" must be set before the FieldDef is added to a // MessageDef, and may not be set after that. @@ -395,9 +410,8 @@ class upb::FieldDef /* : public upb::Def */ { // Before a fielddef is frozen, its subdef may be set either directly (with a // upb::Def*) or symbolically. Symbolic refs must be resolved before the - // containing msgdef can be frozen (see upb_resolve() above). The client is - // responsible for making sure that "subdef" lives until this fielddef is - // frozen or deleted. + // containing msgdef can be frozen (see upb_resolve() above). upb always + // guarantees that any def reachable from a live def will also be kept alive. // // Both methods require that upb_hassubdef(f) (so the type must be set prior // to calling these methods). Returns false if this is not the case, or if @@ -423,14 +437,19 @@ struct upb_fielddef { float flt; void *bytes; } defaultval; - const upb_msgdef *msgdef; + union { + const upb_msgdef *def; // If !msg_is_symbolic. + char *name; // If msg_is_symbolic. + } msg; union { const upb_def *def; // If !subdef_is_symbolic. char *name; // If subdef_is_symbolic. } sub; // The msgdef or enumdef for this field, if upb_hassubdef(f). bool subdef_is_symbolic; + bool msg_is_symbolic; bool default_is_string; bool type_is_set_; // False until type is explicitly set. + bool is_extension_; upb_intfmt_t intfmt; bool tagdelim; upb_fieldtype_t type_; @@ -440,13 +459,14 @@ struct upb_fielddef { uint32_t index_; }; -#define UPB_FIELDDEF_INIT(label, type, intfmt, tagdelim, name, num, msgdef, \ - subdef, selector_base, index, defaultval, refs, \ - ref2s) \ - { \ - UPB_DEF_INIT(name, UPB_DEF_FIELD, refs, ref2s), defaultval, msgdef, \ - {subdef}, false, type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES, \ - true, intfmt, tagdelim, type, label, num, selector_base, index \ +#define UPB_FIELDDEF_INIT(label, type, intfmt, tagdelim, is_extension, name, \ + num, msgdef, subdef, selector_base, index, \ + defaultval, refs, ref2s) \ + { \ + UPB_DEF_INIT(name, UPB_DEF_FIELD, refs, ref2s), defaultval, {msgdef}, \ + {subdef}, false, false, \ + type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES, true, is_extension, \ + intfmt, tagdelim, type, label, num, selector_base, index \ } // Native C API. @@ -475,8 +495,10 @@ upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f); upb_label_t upb_fielddef_label(const upb_fielddef *f); uint32_t upb_fielddef_number(const upb_fielddef *f); const char *upb_fielddef_name(const upb_fielddef *f); +bool upb_fielddef_isextension(const upb_fielddef *f); const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f); upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f); +const char *upb_fielddef_containingtypename(upb_fielddef *f); upb_intfmt_t upb_fielddef_intfmt(const upb_fielddef *f); uint32_t upb_fielddef_index(const upb_fielddef *f); bool upb_fielddef_istagdelim(const upb_fielddef *f); @@ -504,6 +526,9 @@ void upb_fielddef_setdescriptortype(upb_fielddef *f, int type); void upb_fielddef_setlabel(upb_fielddef *f, upb_label_t label); bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number, upb_status *s); bool upb_fielddef_setname(upb_fielddef *f, const char *name, upb_status *s); +bool upb_fielddef_setcontainingtypename(upb_fielddef *f, const char *name, + upb_status *s); +bool upb_fielddef_setisextension(upb_fielddef *f, bool is_extension); bool upb_fielddef_setintfmt(upb_fielddef *f, upb_intfmt_t fmt); bool upb_fielddef_settagdelim(upb_fielddef *f, bool tag_delim); void upb_fielddef_setdefaultint64(upb_fielddef *f, int64_t val); @@ -1043,9 +1068,15 @@ inline FieldDef::Label FieldDef::label() const { } inline uint32_t FieldDef::number() const { return upb_fielddef_number(this); } inline const char* FieldDef::name() const { return upb_fielddef_name(this); } +inline bool FieldDef::is_extension() const { + return upb_fielddef_isextension(this); +} inline const MessageDef* FieldDef::containing_type() const { return upb_fielddef_containingtype(this); } +inline const char* FieldDef::containing_type_name() { + return upb_fielddef_containingtypename(this); +} inline bool FieldDef::set_number(uint32_t number, Status* s) { return upb_fielddef_setnumber(this, number, s); } @@ -1055,9 +1086,19 @@ inline bool FieldDef::set_name(const char *name, Status* s) { inline bool FieldDef::set_name(const std::string& name, Status* s) { return upb_fielddef_setname(this, upb_safecstr(name), s); } +inline bool FieldDef::set_containing_type_name(const char *name, Status* s) { + return upb_fielddef_setcontainingtypename(this, name, s); +} +inline bool FieldDef::set_containing_type_name(const std::string &name, + Status *s) { + return upb_fielddef_setcontainingtypename(this, upb_safecstr(name), s); +} inline void FieldDef::set_type(upb_fieldtype_t type) { upb_fielddef_settype(this, type); } +inline void FieldDef::set_is_extension(bool is_extension) { + upb_fielddef_setisextension(this, is_extension); +} inline void FieldDef::set_descriptor_type(FieldDef::DescriptorType type) { upb_fielddef_setdescriptortype(this, type); } diff --git a/upb/descriptor/descriptor.upb.c b/upb/descriptor/descriptor.upb.c index f183285..8046bcd 100755 --- a/upb/descriptor/descriptor.upb.c +++ b/upb/descriptor/descriptor.upb.c @@ -39,79 +39,79 @@ const upb_msgdef google_protobuf_msgs[20] = { }; const upb_fielddef google_protobuf_fields[73] = { - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "aggregate_value", 8, &google_protobuf_msgs[18], NULL, 15, 6, {0},&reftables[40], &reftables[41]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "cc_generic_services", 16, &google_protobuf_msgs[10], NULL, 14, 5, {0},&reftables[42], &reftables[43]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "ctype", 1, &google_protobuf_msgs[7], UPB_UPCAST(&google_protobuf_enums[2]), 6, 1, {0},&reftables[44], &reftables[45]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "default_value", 7, &google_protobuf_msgs[6], NULL, 16, 7, {0},&reftables[46], &reftables[47]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, "dependency", 3, &google_protobuf_msgs[8], NULL, 30, 8, {0},&reftables[48], &reftables[49]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "deprecated", 3, &google_protobuf_msgs[7], NULL, 8, 3, {0},&reftables[50], &reftables[51]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_DOUBLE, 0, false, "double_value", 6, &google_protobuf_msgs[18], NULL, 11, 4, {0},&reftables[52], &reftables[53]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "end", 2, &google_protobuf_msgs[1], NULL, 3, 1, {0},&reftables[54], &reftables[55]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "enum_type", 4, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[2]), 16, 2, {0},&reftables[56], &reftables[57]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "enum_type", 5, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[2]), 13, 1, {0},&reftables[58], &reftables[59]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "experimental_map_key", 9, &google_protobuf_msgs[7], NULL, 9, 4, {0},&reftables[60], &reftables[61]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "extendee", 2, &google_protobuf_msgs[6], NULL, 7, 2, {0},&reftables[62], &reftables[63]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension", 7, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[6]), 19, 3, {0},&reftables[64], &reftables[65]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension", 6, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[6]), 22, 4, {0},&reftables[66], &reftables[67]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension_range", 5, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[1]), 19, 3, {0},&reftables[68], &reftables[69]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "field", 2, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[6]), 10, 0, {0},&reftables[70], &reftables[71]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "file", 1, &google_protobuf_msgs[9], UPB_UPCAST(&google_protobuf_msgs[8]), 5, 0, {0},&reftables[72], &reftables[73]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "identifier_value", 3, &google_protobuf_msgs[18], NULL, 6, 1, {0},&reftables[74], &reftables[75]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "input_type", 2, &google_protobuf_msgs[12], NULL, 7, 2, {0},&reftables[76], &reftables[77]), - UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_BOOL, 0, false, "is_extension", 2, &google_protobuf_msgs[19], NULL, 5, 1, {0},&reftables[78], &reftables[79]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_generate_equals_and_hash", 20, &google_protobuf_msgs[10], NULL, 17, 8, {0},&reftables[80], &reftables[81]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_generic_services", 17, &google_protobuf_msgs[10], NULL, 15, 6, {0},&reftables[82], &reftables[83]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_multiple_files", 10, &google_protobuf_msgs[10], NULL, 13, 4, {0},&reftables[84], &reftables[85]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "java_outer_classname", 8, &google_protobuf_msgs[10], NULL, 9, 2, {0},&reftables[86], &reftables[87]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "java_package", 1, &google_protobuf_msgs[10], NULL, 6, 1, {0},&reftables[88], &reftables[89]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "label", 4, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_enums[0]), 11, 4, {0},&reftables[90], &reftables[91]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "location", 1, &google_protobuf_msgs[16], UPB_UPCAST(&google_protobuf_msgs[17]), 5, 0, {0},&reftables[92], &reftables[93]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "message_set_wire_format", 1, &google_protobuf_msgs[11], NULL, 6, 1, {0},&reftables[94], &reftables[95]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "message_type", 4, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[0]), 10, 0, {0},&reftables[96], &reftables[97]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "method", 2, &google_protobuf_msgs[14], UPB_UPCAST(&google_protobuf_msgs[12]), 6, 0, {0},&reftables[98], &reftables[99]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "name", 2, &google_protobuf_msgs[18], UPB_UPCAST(&google_protobuf_msgs[19]), 5, 0, {0},&reftables[100], &reftables[101]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[8], NULL, 22, 6, {0},&reftables[102], &reftables[103]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[14], NULL, 8, 2, {0},&reftables[104], &reftables[105]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[12], NULL, 4, 1, {0},&reftables[106], &reftables[107]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[6], NULL, 4, 1, {0},&reftables[108], &reftables[109]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[4], NULL, 4, 1, {0},&reftables[110], &reftables[111]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[2], NULL, 8, 2, {0},&reftables[112], &reftables[113]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[0], NULL, 24, 6, {0},&reftables[114], &reftables[115]), - UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_STRING, 0, false, "name_part", 1, &google_protobuf_msgs[19], NULL, 2, 0, {0},&reftables[116], &reftables[117]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT64, UPB_INTFMT_VARIABLE, false, "negative_int_value", 5, &google_protobuf_msgs[18], NULL, 10, 3, {0},&reftables[118], &reftables[119]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "nested_type", 3, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[0]), 13, 1, {0},&reftables[120], &reftables[121]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "no_standard_descriptor_accessor", 2, &google_protobuf_msgs[11], NULL, 7, 2, {0},&reftables[122], &reftables[123]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "number", 2, &google_protobuf_msgs[4], NULL, 7, 2, {0},&reftables[124], &reftables[125]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "number", 3, &google_protobuf_msgs[6], NULL, 10, 3, {0},&reftables[126], &reftables[127]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "optimize_for", 9, &google_protobuf_msgs[10], UPB_UPCAST(&google_protobuf_enums[3]), 12, 3, {0},&reftables[128], &reftables[129]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[2], UPB_UPCAST(&google_protobuf_msgs[3]), 7, 1, {0},&reftables[130], &reftables[131]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 8, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[10]), 20, 4, {0},&reftables[132], &reftables[133]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[14], UPB_UPCAST(&google_protobuf_msgs[15]), 7, 1, {0},&reftables[134], &reftables[135]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 7, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[11]), 23, 5, {0},&reftables[136], &reftables[137]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 4, &google_protobuf_msgs[12], UPB_UPCAST(&google_protobuf_msgs[13]), 3, 0, {0},&reftables[138], &reftables[139]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[4], UPB_UPCAST(&google_protobuf_msgs[5]), 3, 0, {0},&reftables[140], &reftables[141]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 8, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_msgs[7]), 3, 0, {0},&reftables[142], &reftables[143]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "output_type", 3, &google_protobuf_msgs[12], NULL, 10, 3, {0},&reftables[144], &reftables[145]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "package", 2, &google_protobuf_msgs[8], NULL, 25, 7, {0},&reftables[146], &reftables[147]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "packed", 2, &google_protobuf_msgs[7], NULL, 7, 2, {0},&reftables[148], &reftables[149]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "path", 1, &google_protobuf_msgs[17], NULL, 4, 0, {0},&reftables[150], &reftables[151]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_UINT64, UPB_INTFMT_VARIABLE, false, "positive_int_value", 4, &google_protobuf_msgs[18], NULL, 9, 2, {0},&reftables[152], &reftables[153]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "py_generic_services", 18, &google_protobuf_msgs[10], NULL, 16, 7, {0},&reftables[154], &reftables[155]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "service", 6, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[14]), 16, 2, {0},&reftables[156], &reftables[157]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "source_code_info", 9, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[16]), 21, 5, {0},&reftables[158], &reftables[159]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "span", 2, &google_protobuf_msgs[17], NULL, 7, 1, {0},&reftables[160], &reftables[161]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "start", 1, &google_protobuf_msgs[1], NULL, 2, 0, {0},&reftables[162], &reftables[163]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, "string_value", 7, &google_protobuf_msgs[18], NULL, 12, 5, {0},&reftables[164], &reftables[165]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "type", 5, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_enums[1]), 12, 5, {0},&reftables[166], &reftables[167]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "type_name", 6, &google_protobuf_msgs[6], NULL, 13, 6, {0},&reftables[168], &reftables[169]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[3], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[170], &reftables[171]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[15], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[172], &reftables[173]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[11], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[174], &reftables[175]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[10], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[176], &reftables[177]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[7], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[178], &reftables[179]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[13], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[180], &reftables[181]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[5], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[182], &reftables[183]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "value", 2, &google_protobuf_msgs[2], UPB_UPCAST(&google_protobuf_msgs[4]), 6, 0, {0},&reftables[184], &reftables[185]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "aggregate_value", 8, &google_protobuf_msgs[18], NULL, 15, 6, {0},&reftables[40], &reftables[41]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, "cc_generic_services", 16, &google_protobuf_msgs[10], NULL, 14, 5, {0},&reftables[42], &reftables[43]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, "ctype", 1, &google_protobuf_msgs[7], UPB_UPCAST(&google_protobuf_enums[2]), 6, 1, {0},&reftables[44], &reftables[45]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "default_value", 7, &google_protobuf_msgs[6], NULL, 16, 7, {0},&reftables[46], &reftables[47]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, false, "dependency", 3, &google_protobuf_msgs[8], NULL, 30, 8, {0},&reftables[48], &reftables[49]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, "deprecated", 3, &google_protobuf_msgs[7], NULL, 8, 3, {0},&reftables[50], &reftables[51]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_DOUBLE, 0, false, false, "double_value", 6, &google_protobuf_msgs[18], NULL, 11, 4, {0},&reftables[52], &reftables[53]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, "end", 2, &google_protobuf_msgs[1], NULL, 3, 1, {0},&reftables[54], &reftables[55]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "enum_type", 4, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[2]), 16, 2, {0},&reftables[56], &reftables[57]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "enum_type", 5, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[2]), 13, 1, {0},&reftables[58], &reftables[59]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "experimental_map_key", 9, &google_protobuf_msgs[7], NULL, 9, 4, {0},&reftables[60], &reftables[61]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "extendee", 2, &google_protobuf_msgs[6], NULL, 7, 2, {0},&reftables[62], &reftables[63]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "extension", 7, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[6]), 19, 3, {0},&reftables[64], &reftables[65]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "extension", 6, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[6]), 22, 4, {0},&reftables[66], &reftables[67]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "extension_range", 5, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[1]), 19, 3, {0},&reftables[68], &reftables[69]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "field", 2, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[6]), 10, 0, {0},&reftables[70], &reftables[71]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "file", 1, &google_protobuf_msgs[9], UPB_UPCAST(&google_protobuf_msgs[8]), 5, 0, {0},&reftables[72], &reftables[73]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "identifier_value", 3, &google_protobuf_msgs[18], NULL, 6, 1, {0},&reftables[74], &reftables[75]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "input_type", 2, &google_protobuf_msgs[12], NULL, 7, 2, {0},&reftables[76], &reftables[77]), + UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_BOOL, 0, false, false, "is_extension", 2, &google_protobuf_msgs[19], NULL, 5, 1, {0},&reftables[78], &reftables[79]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, "java_generate_equals_and_hash", 20, &google_protobuf_msgs[10], NULL, 17, 8, {0},&reftables[80], &reftables[81]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, "java_generic_services", 17, &google_protobuf_msgs[10], NULL, 15, 6, {0},&reftables[82], &reftables[83]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, "java_multiple_files", 10, &google_protobuf_msgs[10], NULL, 13, 4, {0},&reftables[84], &reftables[85]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "java_outer_classname", 8, &google_protobuf_msgs[10], NULL, 9, 2, {0},&reftables[86], &reftables[87]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "java_package", 1, &google_protobuf_msgs[10], NULL, 6, 1, {0},&reftables[88], &reftables[89]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, "label", 4, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_enums[0]), 11, 4, {0},&reftables[90], &reftables[91]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "location", 1, &google_protobuf_msgs[16], UPB_UPCAST(&google_protobuf_msgs[17]), 5, 0, {0},&reftables[92], &reftables[93]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, "message_set_wire_format", 1, &google_protobuf_msgs[11], NULL, 6, 1, {0},&reftables[94], &reftables[95]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "message_type", 4, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[0]), 10, 0, {0},&reftables[96], &reftables[97]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "method", 2, &google_protobuf_msgs[14], UPB_UPCAST(&google_protobuf_msgs[12]), 6, 0, {0},&reftables[98], &reftables[99]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "name", 2, &google_protobuf_msgs[18], UPB_UPCAST(&google_protobuf_msgs[19]), 5, 0, {0},&reftables[100], &reftables[101]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "name", 1, &google_protobuf_msgs[8], NULL, 22, 6, {0},&reftables[102], &reftables[103]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "name", 1, &google_protobuf_msgs[14], NULL, 8, 2, {0},&reftables[104], &reftables[105]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "name", 1, &google_protobuf_msgs[12], NULL, 4, 1, {0},&reftables[106], &reftables[107]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "name", 1, &google_protobuf_msgs[6], NULL, 4, 1, {0},&reftables[108], &reftables[109]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "name", 1, &google_protobuf_msgs[4], NULL, 4, 1, {0},&reftables[110], &reftables[111]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "name", 1, &google_protobuf_msgs[2], NULL, 8, 2, {0},&reftables[112], &reftables[113]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "name", 1, &google_protobuf_msgs[0], NULL, 24, 6, {0},&reftables[114], &reftables[115]), + UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_STRING, 0, false, false, "name_part", 1, &google_protobuf_msgs[19], NULL, 2, 0, {0},&reftables[116], &reftables[117]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT64, UPB_INTFMT_VARIABLE, false, false, "negative_int_value", 5, &google_protobuf_msgs[18], NULL, 10, 3, {0},&reftables[118], &reftables[119]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "nested_type", 3, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[0]), 13, 1, {0},&reftables[120], &reftables[121]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, "no_standard_descriptor_accessor", 2, &google_protobuf_msgs[11], NULL, 7, 2, {0},&reftables[122], &reftables[123]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, "number", 2, &google_protobuf_msgs[4], NULL, 7, 2, {0},&reftables[124], &reftables[125]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, "number", 3, &google_protobuf_msgs[6], NULL, 10, 3, {0},&reftables[126], &reftables[127]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, "optimize_for", 9, &google_protobuf_msgs[10], UPB_UPCAST(&google_protobuf_enums[3]), 12, 3, {0},&reftables[128], &reftables[129]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, "options", 3, &google_protobuf_msgs[2], UPB_UPCAST(&google_protobuf_msgs[3]), 7, 1, {0},&reftables[130], &reftables[131]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, "options", 8, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[10]), 20, 4, {0},&reftables[132], &reftables[133]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, "options", 3, &google_protobuf_msgs[14], UPB_UPCAST(&google_protobuf_msgs[15]), 7, 1, {0},&reftables[134], &reftables[135]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, "options", 7, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[11]), 23, 5, {0},&reftables[136], &reftables[137]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, "options", 4, &google_protobuf_msgs[12], UPB_UPCAST(&google_protobuf_msgs[13]), 3, 0, {0},&reftables[138], &reftables[139]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, "options", 3, &google_protobuf_msgs[4], UPB_UPCAST(&google_protobuf_msgs[5]), 3, 0, {0},&reftables[140], &reftables[141]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, "options", 8, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_msgs[7]), 3, 0, {0},&reftables[142], &reftables[143]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "output_type", 3, &google_protobuf_msgs[12], NULL, 10, 3, {0},&reftables[144], &reftables[145]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "package", 2, &google_protobuf_msgs[8], NULL, 25, 7, {0},&reftables[146], &reftables[147]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, "packed", 2, &google_protobuf_msgs[7], NULL, 7, 2, {0},&reftables[148], &reftables[149]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, "path", 1, &google_protobuf_msgs[17], NULL, 4, 0, {0},&reftables[150], &reftables[151]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_UINT64, UPB_INTFMT_VARIABLE, false, false, "positive_int_value", 4, &google_protobuf_msgs[18], NULL, 9, 2, {0},&reftables[152], &reftables[153]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, "py_generic_services", 18, &google_protobuf_msgs[10], NULL, 16, 7, {0},&reftables[154], &reftables[155]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "service", 6, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[14]), 16, 2, {0},&reftables[156], &reftables[157]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, "source_code_info", 9, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[16]), 21, 5, {0},&reftables[158], &reftables[159]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, "span", 2, &google_protobuf_msgs[17], NULL, 7, 1, {0},&reftables[160], &reftables[161]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, "start", 1, &google_protobuf_msgs[1], NULL, 2, 0, {0},&reftables[162], &reftables[163]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, false, "string_value", 7, &google_protobuf_msgs[18], NULL, 12, 5, {0},&reftables[164], &reftables[165]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, "type", 5, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_enums[1]), 12, 5, {0},&reftables[166], &reftables[167]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "type_name", 6, &google_protobuf_msgs[6], NULL, 13, 6, {0},&reftables[168], &reftables[169]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "uninterpreted_option", 999, &google_protobuf_msgs[3], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[170], &reftables[171]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "uninterpreted_option", 999, &google_protobuf_msgs[15], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[172], &reftables[173]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "uninterpreted_option", 999, &google_protobuf_msgs[11], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[174], &reftables[175]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "uninterpreted_option", 999, &google_protobuf_msgs[10], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[176], &reftables[177]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "uninterpreted_option", 999, &google_protobuf_msgs[7], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[178], &reftables[179]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "uninterpreted_option", 999, &google_protobuf_msgs[13], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[180], &reftables[181]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "uninterpreted_option", 999, &google_protobuf_msgs[5], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[182], &reftables[183]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "value", 2, &google_protobuf_msgs[2], UPB_UPCAST(&google_protobuf_msgs[4]), 6, 0, {0},&reftables[184], &reftables[185]), }; const upb_enumdef google_protobuf_enums[4] = { diff --git a/upb/descriptor/reader.c b/upb/descriptor/reader.c index 9dff6e9..eea6ce7 100644 --- a/upb/descriptor/reader.c +++ b/upb/descriptor/reader.c @@ -101,6 +101,7 @@ static void upb_deflist_qualify(upb_deflist *l, char *str, int32_t start) { void upb_descreader_init(upb_descreader *r, const upb_handlers *handlers, upb_status *status) { + UPB_UNUSED(status); upb_deflist_init(&r->defs); upb_sink_reset(upb_descreader_input(r), handlers, r); r->stack_len = 0; @@ -176,8 +177,9 @@ static bool file_endmsg(void *closure, const void *hd, upb_status *status) { } static size_t file_onpackage(void *closure, const void *hd, const char *buf, - size_t n) { + size_t n, const upb_bufhandle *handle) { UPB_UNUSED(hd); + UPB_UNUSED(handle); upb_descreader *r = closure; // XXX: see comment at the top of the file. upb_descreader_setscopename(r, upb_strndup(buf, n)); @@ -194,8 +196,9 @@ static bool enumval_startmsg(void *closure, const void *hd) { } static size_t enumval_onname(void *closure, const void *hd, const char *buf, - size_t n) { + size_t n, const upb_bufhandle *handle) { UPB_UNUSED(hd); + UPB_UNUSED(handle); upb_descreader *r = closure; // XXX: see comment at the top of the file. free(r->name); @@ -256,8 +259,9 @@ static bool enum_endmsg(void *closure, const void *hd, upb_status *status) { } static size_t enum_onname(void *closure, const void *hd, const char *buf, - size_t n) { + size_t n, const upb_bufhandle *handle) { UPB_UNUSED(hd); + UPB_UNUSED(handle); upb_descreader *r = closure; // XXX: see comment at the top of the file. char *fullname = upb_strndup(buf, n); @@ -349,7 +353,8 @@ static bool field_endmsg(void *closure, const void *hd, upb_status *status) { upb_descreader *r = closure; upb_fielddef *f = r->f; // TODO: verify that all required fields were present. - assert(upb_fielddef_number(f) != 0 && upb_fielddef_name(f) != NULL); + assert(upb_fielddef_number(f) != 0); + assert(upb_fielddef_name(f) != NULL); assert((upb_fielddef_subdefname(f) != NULL) == upb_fielddef_hassubdef(f)); if (r->default_string) { @@ -388,13 +393,15 @@ static bool field_onlabel(void *closure, const void *hd, int32_t val) { static bool field_onnumber(void *closure, const void *hd, int32_t val) { UPB_UNUSED(hd); upb_descreader *r = closure; - upb_fielddef_setnumber(r->f, val, NULL); + bool ok = upb_fielddef_setnumber(r->f, val, NULL); + UPB_ASSERT_VAR(ok, ok); return true; } static size_t field_onname(void *closure, const void *hd, const char *buf, - size_t n) { + size_t n, const upb_bufhandle *handle) { UPB_UNUSED(hd); + UPB_UNUSED(handle); upb_descreader *r = closure; // XXX: see comment at the top of the file. char *name = upb_strndup(buf, n); @@ -404,8 +411,9 @@ static size_t field_onname(void *closure, const void *hd, const char *buf, } static size_t field_ontypename(void *closure, const void *hd, const char *buf, - size_t n) { + size_t n, const upb_bufhandle *handle) { UPB_UNUSED(hd); + UPB_UNUSED(handle); upb_descreader *r = closure; // XXX: see comment at the top of the file. char *name = upb_strndup(buf, n); @@ -414,9 +422,22 @@ static size_t field_ontypename(void *closure, const void *hd, const char *buf, return n; } -static size_t field_ondefaultval(void *closure, const void *hd, - const char *buf, size_t n) { +static size_t field_onextendee(void *closure, const void *hd, const char *buf, + size_t n, const upb_bufhandle *handle) { + UPB_UNUSED(hd); + UPB_UNUSED(handle); + upb_descreader *r = closure; + // XXX: see comment at the top of the file. + char *name = upb_strndup(buf, n); + upb_fielddef_setcontainingtypename(r->f, name, NULL); + free(name); + return n; +} + +static size_t field_ondefaultval(void *closure, const void *hd, const char *buf, + size_t n, const upb_bufhandle *handle) { UPB_UNUSED(hd); + UPB_UNUSED(handle); upb_descreader *r = closure; // Have to convert from string to the correct type, but we might not know the // type yet, so we save it as a string until the end of the field. @@ -448,8 +469,9 @@ static bool msg_endmsg(void *closure, const void *hd, upb_status *status) { } static size_t msg_onname(void *closure, const void *hd, const char *buf, - size_t n) { + size_t n, const upb_bufhandle *handle) { UPB_UNUSED(hd); + UPB_UNUSED(handle); upb_descreader *r = closure; upb_msgdef *m = upb_descreader_top(r); // XXX: see comment at the top of the file. @@ -468,11 +490,12 @@ static bool msg_onendfield(void *closure, const void *hd) { return true; } -static bool discardfield(void *closure, const void *hd) { +static bool pushextension(void *closure, const void *hd) { UPB_UNUSED(hd); upb_descreader *r = closure; - // Discard extension field so we don't leak it. - upb_fielddef_unref(r->f, &r->defs); + assert(upb_fielddef_containingtypename(r->f)); + upb_fielddef_setisextension(r->f, true); + upb_deflist_push(&r->defs, UPB_UPCAST(r->f)); r->f = NULL; return true; } @@ -492,14 +515,12 @@ static void reghandlers(void *closure, upb_handlers *h) { upb_handlers_setendmsg(h, &msg_endmsg, NULL); upb_handlers_setstring(h, f(h, "name"), &msg_onname, NULL); upb_handlers_setendsubmsg(h, f(h, "field"), &msg_onendfield, NULL); - // TODO: support extensions - upb_handlers_setendsubmsg(h, f(h, "extension"), &discardfield, NULL); + upb_handlers_setendsubmsg(h, f(h, "extension"), &pushextension, NULL); } else if (m == GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO) { upb_handlers_setstartmsg(h, &file_startmsg, NULL); upb_handlers_setendmsg(h, &file_endmsg, NULL); upb_handlers_setstring(h, f(h, "package"), &file_onpackage, NULL); - // TODO: support extensions - upb_handlers_setendsubmsg(h, f(h, "extension"), &discardfield, NULL); + upb_handlers_setendsubmsg(h, f(h, "extension"), &pushextension, NULL); } else if (m == GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO) { upb_handlers_setstartmsg(h, &enumval_startmsg, NULL); upb_handlers_setendmsg(h, &enumval_endmsg, NULL); @@ -517,6 +538,7 @@ static void reghandlers(void *closure, upb_handlers *h) { upb_handlers_setint32(h, f(h, "number"), &field_onnumber, NULL); upb_handlers_setstring(h, f(h, "name"), &field_onname, NULL); upb_handlers_setstring(h, f(h, "type_name"), &field_ontypename, NULL); + upb_handlers_setstring(h, f(h, "extendee"), &field_onextendee, NULL); upb_handlers_setstring(h, f(h, "default_value"), &field_ondefaultval, NULL); } } diff --git a/upb/google/README b/upb/google/README deleted file mode 100644 index a237583..0000000 --- a/upb/google/README +++ /dev/null @@ -1,16 +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 "google" seems like the -least confusing option. - -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 of the same code. The two -live in different namespaces, and 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/handlers-inl.h b/upb/handlers-inl.h index a101da6..0bee5a2 100644 --- a/upb/handlers-inl.h +++ b/upb/handlers-inl.h @@ -91,6 +91,39 @@ #undef UPB_LONG_IS_64BITS #undef UPB_LLONG_IS_64BITS +// C inline methods. + +// upb_bufhandle +UPB_INLINE void upb_bufhandle_init(upb_bufhandle *h) { + h->obj_ = NULL; + h->objtype_ = NULL; + h->buf_ = NULL; + h->objofs_ = 0; +} +UPB_INLINE void upb_bufhandle_uninit(upb_bufhandle *h) { + UPB_UNUSED(h); +} +UPB_INLINE void upb_bufhandle_setobj(upb_bufhandle *h, const void *obj, + const void *type) { + h->obj_ = obj; + h->objtype_ = type; +} +UPB_INLINE void upb_bufhandle_setbuf(upb_bufhandle *h, const char *buf, + size_t ofs) { + h->buf_ = buf; + h->objofs_ = ofs; +} +UPB_INLINE const void *upb_bufhandle_obj(const upb_bufhandle *h) { + return h->obj_; +} +UPB_INLINE const void *upb_bufhandle_objtype(const upb_bufhandle *h) { + return h->objtype_; +} +UPB_INLINE const char *upb_bufhandle_buf(const upb_bufhandle *h) { + return h->buf_; +} + + #ifdef __cplusplus namespace upb { @@ -122,8 +155,8 @@ typedef void CleanupFunc(void *ptr); // We define a nonsense default because otherwise it will fail to instantiate as // a function parameter type even in cases where we don't expect any caller to // actually match the overload. -class NonsenseType {}; -template <class T> struct remove_constptr { typedef NonsenseType type; }; +class CouldntRemoveConst {}; +template <class T> struct remove_constptr { typedef CouldntRemoveConst type; }; template <class T> struct remove_constptr<const T *> { typedef T *type; }; // Template that we use below to remove a template specialization from @@ -133,6 +166,44 @@ template <class T> struct disable_if_same<T, T> {}; template <class T> void DeletePointer(void *p) { delete static_cast<T *>(p); } +template <class T1, class T2> +struct FirstUnlessVoid { + typedef T1 value; +}; + +template <class T2> +struct FirstUnlessVoid<void, T2> { + typedef T2 value; +}; + +template<class T, class U> +struct is_same { + static bool value; +}; + +template<class T> +struct is_same<T, T> { + static bool value; +}; + +template<class T, class U> +bool is_same<T, U>::value = false; + +template<class T> +bool is_same<T, T>::value = true; + +// FuncInfo //////////////////////////////////////////////////////////////////// + +// Info about the user's original, pre-wrapped function. +template <class C, class R = void> +struct FuncInfo { + // The type of the closure that the function takes (its first param). + typedef C Closure; + + // The return type. + typedef R Return; +}; + // Func //////////////////////////////////////////////////////////////////////// // Func1, Func2, Func3: Template classes representing a function and its @@ -147,30 +218,45 @@ struct UnboundFunc { void *GetData() { return NULL; } }; -template <class R, class P1, R F(P1)> +template <class R, class P1, R F(P1), class I> struct Func1 : public UnboundFunc { typedef R Return; + typedef I FuncInfo; static R Call(P1 p1) { return F(p1); } }; -template <class R, class P1, class P2, R F(P1, P2)> +template <class R, class P1, class P2, R F(P1, P2), class I> struct Func2 : public UnboundFunc { typedef R Return; + typedef I FuncInfo; static R Call(P1 p1, P2 p2) { return F(p1, p2); } }; -template <class R, class P1, class P2, class P3, R F(P1, P2, P3)> +template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I> struct Func3 : public UnboundFunc { typedef R Return; + typedef I FuncInfo; static R Call(P1 p1, P2 p2, P3 p3) { return F(p1, p2, p3); } }; -template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)> +template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4), + class I> struct Func4 : public UnboundFunc { typedef R Return; + typedef I FuncInfo; static R Call(P1 p1, P2 p2, P3 p3, P4 p4) { return F(p1, p2, p3, p4); } }; +template <class R, class P1, class P2, class P3, class P4, class P5, + R F(P1, P2, P3, P4, P5), class I> +struct Func5 : public UnboundFunc { + typedef R Return; + typedef I FuncInfo; + static R Call(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { + return F(p1, p2, p3, p4, p5); + } +}; + // BoundFunc /////////////////////////////////////////////////////////////////// // BoundFunc2, BoundFunc3: Like Func2/Func3 except also contains a value that @@ -187,24 +273,36 @@ struct BoundFunc { MutableP2 data; }; -template <class R, class P1, class P2, R F(P1, P2)> +template <class R, class P1, class P2, R F(P1, P2), class I> struct BoundFunc2 : public BoundFunc<P2> { typedef BoundFunc<P2> Base; + typedef I FuncInfo; explicit BoundFunc2(typename Base::MutableP2 arg) : Base(arg) {} }; -template <class R, class P1, class P2, class P3, R F(P1, P2, P3)> +template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I> struct BoundFunc3 : public BoundFunc<P2> { typedef BoundFunc<P2> Base; + typedef I FuncInfo; explicit BoundFunc3(typename Base::MutableP2 arg) : Base(arg) {} }; -template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)> +template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4), + class I> struct BoundFunc4 : public BoundFunc<P2> { typedef BoundFunc<P2> Base; + typedef I FuncInfo; explicit BoundFunc4(typename Base::MutableP2 arg) : Base(arg) {} }; +template <class R, class P1, class P2, class P3, class P4, class P5, + R F(P1, P2, P3, P4, P5), class I> +struct BoundFunc5 : public BoundFunc<P2> { + typedef BoundFunc<P2> Base; + typedef I FuncInfo; + explicit BoundFunc5(typename Base::MutableP2 arg) : Base(arg) {} +}; + // FuncSig ///////////////////////////////////////////////////////////////////// // FuncSig1, FuncSig2, FuncSig3: template classes reflecting a function @@ -215,49 +313,64 @@ struct BoundFunc4 : public BoundFunc<P2> { template <class R, class P1> struct FuncSig1 { template <R F(P1)> - Func1<R, P1, F> GetFunc() { - return Func1<R, P1, F>(); + Func1<R, P1, F, FuncInfo<P1, R> > GetFunc() { + return Func1<R, P1, F, FuncInfo<P1, R> >(); } }; template <class R, class P1, class P2> struct FuncSig2 { template <R F(P1, P2)> - Func2<R, P1, P2, F> GetFunc() { - return Func2<R, P1, P2, F>(); + Func2<R, P1, P2, F, FuncInfo<P1, R> > GetFunc() { + return Func2<R, P1, P2, F, FuncInfo<P1, R> >(); } template <R F(P1, P2)> - BoundFunc2<R, P1, P2, F> GetFunc(typename remove_constptr<P2>::type param2) { - return BoundFunc2<R, P1, P2, F>(param2); + BoundFunc2<R, P1, P2, F, FuncInfo<P1, R> > GetFunc( + typename remove_constptr<P2>::type param2) { + return BoundFunc2<R, P1, P2, F, FuncInfo<P1, R> >(param2); } }; template <class R, class P1, class P2, class P3> struct FuncSig3 { template <R F(P1, P2, P3)> - Func3<R, P1, P2, P3, F> GetFunc() { - return Func3<R, P1, P2, P3, F>(); + Func3<R, P1, P2, P3, F, FuncInfo<P1, R> > GetFunc() { + return Func3<R, P1, P2, P3, F, FuncInfo<P1, R> >(); } template <R F(P1, P2, P3)> - BoundFunc3<R, P1, P2, P3, F> GetFunc( + BoundFunc3<R, P1, P2, P3, F, FuncInfo<P1, R> > GetFunc( typename remove_constptr<P2>::type param2) { - return BoundFunc3<R, P1, P2, P3, F>(param2); + return BoundFunc3<R, P1, P2, P3, F, FuncInfo<P1, R> >(param2); } }; template <class R, class P1, class P2, class P3, class P4> struct FuncSig4 { template <R F(P1, P2, P3, P4)> - Func4<R, P1, P2, P3, P4, F> GetFunc() { - return Func4<R, P1, P2, P3, P4, F>(); + Func4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> > GetFunc() { + return Func4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> >(); } template <R F(P1, P2, P3, P4)> - BoundFunc4<R, P1, P2, P3, P4, F> GetFunc( + BoundFunc4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> > GetFunc( + typename remove_constptr<P2>::type param2) { + return BoundFunc4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> >(param2); + } +}; + +template <class R, class P1, class P2, class P3, class P4, class P5> +struct FuncSig5 { + template <R F(P1, P2, P3, P4, P5)> + Func5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> > GetFunc() { + return Func5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> >(); + } + + template <R F(P1, P2, P3, P4, P5)> + BoundFunc5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> > GetFunc( typename remove_constptr<P2>::type param2) { - return BoundFunc4<R, P1, P2, P3, P4, F>(param2); + return BoundFunc5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> >(param2); } }; @@ -287,6 +400,12 @@ inline FuncSig4<R, P1, P2, P3, P4> MatchFunc(R (*f)(P1, P2, P3, P4)) { return FuncSig4<R, P1, P2, P3, P4>(); } +template <class R, class P1, class P2, class P3, class P4, class P5> +inline FuncSig5<R, P1, P2, P3, P4, P5> MatchFunc(R (*f)(P1, P2, P3, P4, P5)) { + UPB_UNUSED(f); // Only used for template parameter deduction. + return FuncSig5<R, P1, P2, P3, P4, P5>(); +} + // MethodSig /////////////////////////////////////////////////////////////////// // CallMethod*: a function template that calls a given method. @@ -310,6 +429,12 @@ R CallMethod3(C *obj, P1 arg1, P2 arg2, P3 arg3) { return ((*obj).*F)(arg1, arg2, arg3); } +template <class R, class C, class P1, class P2, class P3, class P4, + R (C::*F)(P1, P2, P3, P4)> +R CallMethod4(C *obj, P1 arg1, P2 arg2, P3 arg3, P4 arg4) { + return ((*obj).*F)(arg1, arg2, arg3, arg4); +} + // MethodSig: like FuncSig, but for member functions. // // GetFunc() returns a normal FuncN object, so after calling GetFunc() no @@ -317,50 +442,77 @@ R CallMethod3(C *obj, P1 arg1, P2 arg2, P3 arg3) { template <class R, class C> struct MethodSig0 { template <R (C::*F)()> - Func1<R, C *, CallMethod0<R, C, F> > GetFunc() { - return Func1<R, C *, CallMethod0<R, C, F> >(); + Func1<R, C *, CallMethod0<R, C, F>, FuncInfo<C *, R> > GetFunc() { + return Func1<R, C *, CallMethod0<R, C, F>, FuncInfo<C *, R> >(); } }; template <class R, class C, class P1> struct MethodSig1 { template <R (C::*F)(P1)> - Func2<R, C *, P1, CallMethod1<R, C, P1, F> > GetFunc() { - return Func2<R, C *, P1, CallMethod1<R, C, P1, F> >(); + Func2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> > GetFunc() { + return Func2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> >(); } template <R (C::*F)(P1)> - BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F> > GetFunc( + BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> > GetFunc( typename remove_constptr<P1>::type param1) { - return BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F> >(param1); + return BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> >( + param1); } }; template <class R, class C, class P1, class P2> struct MethodSig2 { template <R (C::*F)(P1, P2)> - Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F> > GetFunc() { - return Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F> >(); + Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>, FuncInfo<C *, R> > + GetFunc() { + return Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>, + FuncInfo<C *, R> >(); } template <R (C::*F)(P1, P2)> - BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F> > GetFunc( - typename remove_constptr<P1>::type param1) { - return BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F> >(param1); + BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>, FuncInfo<C *, R> > + GetFunc(typename remove_constptr<P1>::type param1) { + return BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>, + FuncInfo<C *, R> >(param1); } }; template <class R, class C, class P1, class P2, class P3> struct MethodSig3 { template <R (C::*F)(P1, P2, P3)> - Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F> > GetFunc() { - return Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F> >(); + Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>, FuncInfo<C *, R> > + GetFunc() { + return Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>, + FuncInfo<C *, R> >(); } template <R (C::*F)(P1, P2, P3)> - BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F> > GetFunc( - typename remove_constptr<P1>::type param1) { - return BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F> >( + BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>, + FuncInfo<C *, R> > + GetFunc(typename remove_constptr<P1>::type param1) { + return BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>, + FuncInfo<C *, R> >(param1); + } +}; + +template <class R, class C, class P1, class P2, class P3, class P4> +struct MethodSig4 { + template <R (C::*F)(P1, P2, P3, P4)> + Func5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>, + FuncInfo<C *, R> > + GetFunc() { + return Func5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>, + FuncInfo<C *, R> >(); + } + + template <R (C::*F)(P1, P2, P3, P4)> + BoundFunc5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>, + FuncInfo<C *, R> > + GetFunc(typename remove_constptr<P1>::type param1) { + return BoundFunc5<R, C *, P1, P2, P3, P4, + CallMethod4<R, C, P1, P2, P3, P4, F>, FuncInfo<C *, R> >( param1); } }; @@ -389,6 +541,12 @@ inline MethodSig3<R, C, P1, P2, P3> MatchFunc(R (C::*f)(P1, P2, P3)) { return MethodSig3<R, C, P1, P2, P3>(); } +template <class R, class C, class P1, class P2, class P3, class P4> +inline MethodSig4<R, C, P1, P2, P3, P4> MatchFunc(R (C::*f)(P1, P2, P3, P4)) { + UPB_UNUSED(f); // Only used for template parameter deduction. + return MethodSig4<R, C, P1, P2, P3, P4>(); +} + // MaybeWrapReturn ///////////////////////////////////////////////////////////// // Template class that attempts to wrap the return value of the function so it @@ -448,58 +606,62 @@ void *CastReturnToVoidPtr3(P1 p1, P2 p2, P3 p3) { return F(p1, p2, p3); } -// For the string callback, which takes four params, returns the last param -// which is the size of the entire string. -template <class P1, class P2, class P3, void F(P1, P2, P3, size_t)> -size_t ReturnStringLen(P1 p1, P2 p2, P3 p3, size_t p4) { - F(p1, p2, p3, p4); +// For the string callback, which takes five params, returns the size param. +template <class P1, class P2, + void F(P1, P2, const char *, size_t, const BufferHandle *)> +size_t ReturnStringLen(P1 p1, P2 p2, const char *p3, size_t p4, + const BufferHandle *p5) { + F(p1, p2, p3, p4, p5); return p4; } // If we have a function returning void but want a function returning bool, wrap // it in a function that returns true. -template <class P1, class P2, void F(P1, P2)> -struct MaybeWrapReturn<Func2<void, P1, P2, F>, bool> { - typedef Func2<bool, P1, P2, ReturnTrue2<P1, P2, F> > Func; +template <class P1, class P2, void F(P1, P2), class I> +struct MaybeWrapReturn<Func2<void, P1, P2, F, I>, bool> { + typedef Func2<bool, P1, P2, ReturnTrue2<P1, P2, F>, I> Func; }; -template <class P1, class P2, class P3, void F(P1, P2, P3)> -struct MaybeWrapReturn<Func3<void, P1, P2, P3, F>, bool> { - typedef Func3<bool, P1, P2, P3, ReturnTrue3<P1, P2, P3, F> > Func; +template <class P1, class P2, class P3, void F(P1, P2, P3), class I> +struct MaybeWrapReturn<Func3<void, P1, P2, P3, F, I>, bool> { + typedef Func3<bool, P1, P2, P3, ReturnTrue3<P1, P2, P3, F>, I> Func; }; // If our function returns void but we want one returning void*, wrap it in a // function that returns the first argument. -template <class P1, class P2, void F(P1, P2)> -struct MaybeWrapReturn<Func2<void, P1, P2, F>, void *> { - typedef Func2<void *, P1, P2, ReturnClosure2<P1, P2, F> > Func; +template <class P1, class P2, void F(P1, P2), class I> +struct MaybeWrapReturn<Func2<void, P1, P2, F, I>, void *> { + typedef Func2<void *, P1, P2, ReturnClosure2<P1, P2, F>, I> Func; }; -template <class P1, class P2, class P3, void F(P1, P2, P3)> -struct MaybeWrapReturn<Func3<void, P1, P2, P3, F>, void *> { - typedef Func3<void *, P1, P2, P3, ReturnClosure3<P1, P2, P3, F> > Func; +template <class P1, class P2, class P3, void F(P1, P2, P3), class I> +struct MaybeWrapReturn<Func3<void, P1, P2, P3, F, I>, void *> { + typedef Func3<void *, P1, P2, P3, ReturnClosure3<P1, P2, P3, F>, I> Func; }; // If our function returns void but we want one returning size_t, wrap it in a -// function that returns the last argument. -template <class P1, class P2, class P3, void F(P1, P2, P3, size_t)> -struct MaybeWrapReturn<Func4<void, P1, P2, P3, size_t, F>, size_t> { - typedef Func4<size_t, P1, P2, P3, size_t, ReturnStringLen<P1, P2, P3, F> > - Func; +// function that returns the size argument. +template <class P1, class P2, + void F(P1, P2, const char *, size_t, const BufferHandle *), class I> +struct MaybeWrapReturn< + Func5<void, P1, P2, const char *, size_t, const BufferHandle *, F, I>, + size_t> { + typedef Func5<size_t, P1, P2, const char *, size_t, const BufferHandle *, + ReturnStringLen<P1, P2, F>, I> Func; }; // If our function returns R* but we want one returning void*, wrap it in a // function that casts to void*. -template <class R, class P1, class P2, R *F(P1, P2)> -struct MaybeWrapReturn<Func2<R *, P1, P2, F>, void *, +template <class R, class P1, class P2, R *F(P1, P2), class I> +struct MaybeWrapReturn<Func2<R *, P1, P2, F, I>, void *, typename disable_if_same<R *, void *>::Type> { - typedef Func2<void *, P1, P2, CastReturnToVoidPtr2<R *, P1, P2, F> > Func; + typedef Func2<void *, P1, P2, CastReturnToVoidPtr2<R *, P1, P2, F>, I> Func; }; -template <class R, class P1, class P2, class P3, R *F(P1, P2, P3)> -struct MaybeWrapReturn<Func3<R *, P1, P2, P3, F>, void *, +template <class R, class P1, class P2, class P3, R *F(P1, P2, P3), class I> +struct MaybeWrapReturn<Func3<R *, P1, P2, P3, F, I>, void *, typename disable_if_same<R *, void *>::Type> { - typedef Func3<void *, P1, P2, P3, CastReturnToVoidPtr3<R *, P1, P2, P3, F> > + typedef Func3<void *, P1, P2, P3, CastReturnToVoidPtr3<R *, P1, P2, P3, F>, I> Func; }; @@ -532,6 +694,20 @@ R IgnoreHandlerData4(void *p1, const void *hd, P2 p2, P3 p3) { return F(static_cast<P1>(p1), p2, p3); } +template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)> +R IgnoreHandlerData5(void *p1, const void *hd, P2 p2, P3 p3, P4 p4) { + UPB_UNUSED(hd); + return F(static_cast<P1>(p1), p2, p3, p4); +} + +template <class R, class P1, R F(P1, const char*, size_t)> +R IgnoreHandlerDataIgnoreHandle(void *p1, const void *hd, const char *p2, + size_t p3, const BufferHandle *handle) { + UPB_UNUSED(hd); + UPB_UNUSED(handle); + return F(static_cast<P1>(p1), p2, p3); +} + // Function that casts the handler data parameter. template <class R, class P1, class P2, R F(P1, P2)> R CastHandlerData2(void *c, const void *hd) { @@ -544,47 +720,75 @@ R CastHandlerData3(void *c, const void *hd, P3Wrapper p3) { return F(static_cast<P1>(c), static_cast<P2>(hd), p3); } -template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)> -R CastHandlerData4(void *c, const void *hd, P3 p3, P4 p4) { +template <class R, class P1, class P2, class P3, class P4, class P5, + R F(P1, P2, P3, P4, P5)> +R CastHandlerData5(void *c, const void *hd, P3 p3, P4 p4, P5 p5) { + return F(static_cast<P1>(c), static_cast<P2>(hd), p3, p4, p5); +} + +template <class R, class P1, class P2, R F(P1, P2, const char *, size_t)> +R CastHandlerDataIgnoreHandle(void *c, const void *hd, const char *p3, + size_t p4, const BufferHandle *handle) { + UPB_UNUSED(handle); return F(static_cast<P1>(c), static_cast<P2>(hd), p3, p4); } // For unbound functions, ignore the handler data. -template <class R, class P1, R F(P1)> -struct ConvertParams<Func1<R, P1, F> > { - typedef Func2<R, void *, const void *, IgnoreHandlerData2<R, P1, F> > Func; +template <class R, class P1, R F(P1), class I> +struct ConvertParams<Func1<R, P1, F, I> > { + typedef Func2<R, void *, const void *, IgnoreHandlerData2<R, P1, F>, I> Func; }; -template <class R, class P1, class P2, R F(P1, P2)> -struct ConvertParams<Func2<R, P1, P2, F> > { +template <class R, class P1, class P2, R F(P1, P2), class I> +struct ConvertParams<Func2<R, P1, P2, F, I> > { typedef typename CanonicalType<P2>::Type CanonicalP2; typedef Func3<R, void *, const void *, CanonicalP2, - IgnoreHandlerData3<R, P1, CanonicalP2, P2, F> > Func; + IgnoreHandlerData3<R, P1, CanonicalP2, P2, F>, I> Func; }; -template <class R, class P1, class P2, class P3, R F(P1, P2, P3)> -struct ConvertParams<Func3<R, P1, P2, P3, F> > { - typedef Func4<R, void *, const void *, P2, P3, - IgnoreHandlerData4<R, P1, P2, P3, F> > Func; +// For StringBuffer only; this ignores both the handler data and the +// BufferHandle. +template <class R, class P1, R F(P1, const char *, size_t), class I> +struct ConvertParams<Func3<R, P1, const char *, size_t, F, I> > { + typedef Func5<R, void *, const void *, const char *, size_t, + const BufferHandle *, IgnoreHandlerDataIgnoreHandle<R, P1, F>, + I> Func; +}; + +template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4), class I> +struct ConvertParams<Func4<R, P1, P2, P3, P4, F, I> > { + typedef Func5<R, void *, const void *, P2, P3, P4, + IgnoreHandlerData5<R, P1, P2, P3, P4, F>, I> Func; }; // For bound functions, cast the handler data. -template <class R, class P1, class P2, R F(P1, P2)> -struct ConvertParams<BoundFunc2<R, P1, P2, F> > { - typedef Func2<R, void *, const void *, CastHandlerData2<R, P1, P2, F> > Func; +template <class R, class P1, class P2, R F(P1, P2), class I> +struct ConvertParams<BoundFunc2<R, P1, P2, F, I> > { + typedef Func2<R, void *, const void *, CastHandlerData2<R, P1, P2, F>, I> + Func; }; -template <class R, class P1, class P2, class P3, R F(P1, P2, P3)> -struct ConvertParams<BoundFunc3<R, P1, P2, P3, F> > { +template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I> +struct ConvertParams<BoundFunc3<R, P1, P2, P3, F, I> > { typedef typename CanonicalType<P3>::Type CanonicalP3; typedef Func3<R, void *, const void *, CanonicalP3, - CastHandlerData3<R, P1, P2, CanonicalP3, P3, F> > Func; + CastHandlerData3<R, P1, P2, CanonicalP3, P3, F>, I> Func; }; -template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)> -struct ConvertParams<BoundFunc4<R, P1, P2, P3, P4, F> > { - typedef Func4<R, void *, const void *, P3, P4, - CastHandlerData4<R, P1, P2, P3, P4, F> > Func; +// For StringBuffer only; this ignores the BufferHandle. +template <class R, class P1, class P2, R F(P1, P2, const char *, size_t), + class I> +struct ConvertParams<BoundFunc4<R, P1, P2, const char *, size_t, F, I> > { + typedef Func5<R, void *, const void *, const char *, size_t, + const BufferHandle *, CastHandlerDataIgnoreHandle<R, P1, P2, F>, + I> Func; +}; + +template <class R, class P1, class P2, class P3, class P4, class P5, + R F(P1, P2, P3, P4, P5), class I> +struct ConvertParams<BoundFunc5<R, P1, P2, P3, P4, P5, F, I> > { + typedef Func5<R, void *, const void *, P3, P4, P5, + CastHandlerData5<R, P1, P2, P3, P4, P5, F>, I> Func; }; // utype/ltype are upper/lower-case, ctype is canonical C type, vtype is @@ -659,6 +863,16 @@ struct ReturnOf<R (*)(P1, P2, P3, P4)> { typedef R Return; }; +template <class R, class P1, class P2, class P3, class P4, class P5> +struct ReturnOf<R (*)(P1, P2, P3, P4, P5)> { + typedef R Return; +}; + +template<class T> const void *UniquePtrForType() { + static const char ch = 0; + return &ch; +} + template <class T> template <class F> inline Handler<T>::Handler(F func) @@ -669,6 +883,25 @@ inline Handler<T>::Handler(F func) typedef typename MaybeWrapReturn<ConvertedParamsFunc, Return>::Func ReturnWrappedFunc; handler_ = ReturnWrappedFunc().Call; + + // Set attributes based on what templates can statically tell us about the + // user's function. + + // If the original function returns void, then we know that we wrapped it to + // always return ok. + bool always_ok = is_same<typename F::FuncInfo::Return, void>::value; + attr_.SetAlwaysOk(always_ok); + + // Closure parameter and return type. + attr_.SetClosureType(UniquePtrForType<typename F::FuncInfo::Closure>()); + + // We use the closure type (from the first parameter) if the return type is + // void. This is all nonsense for non START* handlers, but it doesn't matter + // because in that case the value will be ignored. + typedef typename FirstUnlessVoid<typename F::FuncInfo::Return, + typename F::FuncInfo::Closure>::value + EffectiveReturn; + attr_.SetReturnClosureType(UniquePtrForType<EffectiveReturn>()); } template <class T> @@ -682,6 +915,49 @@ inline bool HandlerAttributes::SetHandlerData(void *hd, upb_handlerfree *cleanup) { return upb_handlerattr_sethandlerdata(this, hd, cleanup); } +inline const void* HandlerAttributes::handler_data() const { + return upb_handlerattr_handlerdata(this); +} +inline bool HandlerAttributes::SetClosureType(const void *type) { + return upb_handlerattr_setclosuretype(this, type); +} +inline const void* HandlerAttributes::closure_type() const { + return upb_handlerattr_closuretype(this); +} +inline bool HandlerAttributes::SetReturnClosureType(const void *type) { + return upb_handlerattr_setreturnclosuretype(this, type); +} +inline const void* HandlerAttributes::return_closure_type() const { + return upb_handlerattr_returnclosuretype(this); +} +inline bool HandlerAttributes::SetAlwaysOk(bool always_ok) { + return upb_handlerattr_setalwaysok(this, always_ok); +} +inline bool HandlerAttributes::always_ok() const { + return upb_handlerattr_alwaysok(this); +} + +inline BufferHandle::BufferHandle() { upb_bufhandle_init(this); } +inline BufferHandle::~BufferHandle() { upb_bufhandle_uninit(this); } +inline const char* BufferHandle::buffer() const { + return upb_bufhandle_buf(this); +} +inline size_t BufferHandle::object_offset() const { + return upb_bufhandle_objofs(this); +} +inline void BufferHandle::SetBuffer(const char* buf, size_t ofs) { + upb_bufhandle_setbuf(this, buf, ofs); +} +template <class T> +void BufferHandle::SetAttachedObject(const T* obj) { + upb_bufhandle_setobj(this, obj, UniquePtrForType<T>()); +} +template <class T> +const T* BufferHandle::GetAttachedObject() const { + return upb_bufhandle_objtype(this) == UniquePtrForType<T>() + ? static_cast<const T *>(upb_bufhandle_obj(this)) + : NULL; +} inline reffed_ptr<Handlers> Handlers::New(const MessageDef *m) { upb_handlers *h = upb_handlers_new(m, &h); @@ -803,10 +1079,19 @@ inline const void *Handlers::GetHandlerData(Handlers::Selector selector) { return upb_handlers_gethandlerdata(this, selector); } +inline BytesHandler::BytesHandler() { + upb_byteshandler_init(this); +} + +inline BytesHandler::~BytesHandler() { + upb_byteshandler_uninit(this); +} + } // namespace upb #endif // __cplusplus + #undef UPB_TWO_32BIT_TYPES #undef UPB_TWO_64BIT_TYPES #undef UPB_INT32_T diff --git a/upb/handlers.c b/upb/handlers.c index baa3e06..006ff83 100644 --- a/upb/handlers.c +++ b/upb/handlers.c @@ -92,8 +92,8 @@ oom: // The selector for a submessage field is the field index. #define SUBH_F(h, f) SUBH(h, f->index_) -static int32_t getsel(upb_handlers *h, const upb_fielddef *f, - upb_handlertype_t type) { +static int32_t trygetsel(upb_handlers *h, const upb_fielddef *f, + upb_handlertype_t type) { upb_selector_t sel; assert(!upb_handlers_isfrozen(h)); if (upb_handlers_msgdef(h) != upb_fielddef_containingtype(f)) { @@ -112,7 +112,20 @@ static int32_t getsel(upb_handlers *h, const upb_fielddef *f, return sel; } -static bool doset(upb_handlers *h, int32_t sel, upb_func *func, +static upb_selector_t getsel(upb_handlers *h, const upb_fielddef *f, + upb_handlertype_t type) { + int32_t sel = trygetsel(h, f, type); + assert(sel >= 0); + return sel; +} + +static const void **returntype(upb_handlers *h, const upb_fielddef *f, + upb_handlertype_t type) { + return &h->table[getsel(h, f, type)].attr.return_closure_type_; +} + +static bool doset(upb_handlers *h, int32_t sel, const upb_fielddef *f, + upb_handlertype_t type, upb_func *func, upb_handlerattr *attr) { assert(!upb_handlers_isfrozen(h)); @@ -133,11 +146,103 @@ static bool doset(upb_handlers *h, int32_t sel, upb_func *func, set_attr = *attr; } + // Check that the given closure type matches the closure type that has been + // established for this context (if any). + const void *closure_type = upb_handlerattr_closuretype(&set_attr); + const void **context_closure_type; + + if (type == UPB_HANDLER_STRING) { + context_closure_type = returntype(h, f, UPB_HANDLER_STARTSTR); + } else if (f && upb_fielddef_isseq(f) && + type != UPB_HANDLER_STARTSEQ && + type != UPB_HANDLER_ENDSEQ) { + context_closure_type = returntype(h, f, UPB_HANDLER_STARTSEQ); + } else { + context_closure_type = &h->top_closure_type; + } + + if (closure_type && *context_closure_type && + closure_type != *context_closure_type) { + // TODO(haberman): better message for debugging. + upb_status_seterrmsg(&h->status_, "closure type does not match"); + return false; + } + + if (closure_type) + *context_closure_type = closure_type; + + // If this is a STARTSEQ or STARTSTR handler, check that the returned pointer + // matches any pre-existing expectations about what type is expected. + if (type == UPB_HANDLER_STARTSEQ || type == UPB_HANDLER_STARTSTR) { + const void *return_type = upb_handlerattr_returnclosuretype(&set_attr); + const void *table_return_type = + upb_handlerattr_returnclosuretype(&h->table[sel].attr); + if (return_type && table_return_type && return_type != table_return_type) { + upb_status_seterrmsg(&h->status_, "closure return type does not match"); + return false; + } + + if (table_return_type && !return_type) + upb_handlerattr_setreturnclosuretype(&set_attr, table_return_type); + } + h->table[sel].func = (upb_func*)func; h->table[sel].attr = set_attr; return true; } +// Returns the effective closure type for this handler (which will propagate +// from outer frames if this frame has no START* handler). Not implemented for +// UPB_HANDLER_STRING at the moment since this is not needed. Returns NULL is +// the effective closure type is unspecified (either no handler was registered +// to specify it or the handler that was registered did not specify the closure +// type). +const void *effective_closure_type(upb_handlers *h, const upb_fielddef *f, + upb_handlertype_t type) { + assert(type != UPB_HANDLER_STRING); + const void *ret = h->top_closure_type; + upb_selector_t sel; + if (upb_fielddef_isseq(f) && + type != UPB_HANDLER_STARTSEQ && + type != UPB_HANDLER_ENDSEQ && + h->table[sel = getsel(h, f, UPB_HANDLER_STARTSEQ)].func) { + ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr); + } + + if (type == UPB_HANDLER_STRING && + h->table[sel = getsel(h, f, UPB_HANDLER_STARTSTR)].func) { + ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr); + } + + // The effective type of the submessage; not used yet. + // if (type == SUBMESSAGE && + // h->table[sel = getsel(h, f, UPB_HANDLER_STARTSUBMSG)].func) { + // ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr); + // } + + return ret; +} + +// Checks whether the START* handler specified by f & type is missing even +// though it is required to convert the established type of an outer frame +// ("closure_type") into the established type of an inner frame (represented in +// the return closure type of this handler's attr. +bool checkstart(upb_handlers *h, const upb_fielddef *f, upb_handlertype_t type, + upb_status *status) { + upb_selector_t sel = getsel(h, f, type); + if (h->table[sel].func) return true; + const void *closure_type = effective_closure_type(h, f, type); + const upb_handlerattr *attr = &h->table[sel].attr; + const void *return_closure_type = upb_handlerattr_returnclosuretype(attr); + if (closure_type && return_closure_type && + closure_type != return_closure_type) { + upb_status_seterrf(status, + "expected start handler to return sub type for field %f", + upb_fielddef_name(f)); + return false; + } + return true; +} /* Public interface ***********************************************************/ @@ -218,8 +323,8 @@ void upb_handlers_clearerr(upb_handlers *h) { #define SETTER(name, handlerctype, handlertype) \ bool upb_handlers_set ## name(upb_handlers *h, const upb_fielddef *f, \ handlerctype func, upb_handlerattr *attr) { \ - int32_t sel = getsel(h, f, handlertype); \ - return doset(h, sel, (upb_func*)func, attr); \ + int32_t sel = trygetsel(h, f, handlertype); \ + return doset(h, sel, f, handlertype, (upb_func*)func, attr); \ } SETTER(int32, upb_int32_handlerfunc*, UPB_HANDLER_INT32); @@ -241,13 +346,15 @@ SETTER(endseq, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSEQ); bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func, upb_handlerattr *attr) { - return doset(h, UPB_STARTMSG_SELECTOR, (upb_func*)func, attr); + return doset(h, UPB_STARTMSG_SELECTOR, NULL, UPB_HANDLER_INT32, + (upb_func *)func, attr); } bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func, upb_handlerattr *attr) { assert(!upb_handlers_isfrozen(h)); - return doset(h, UPB_ENDMSG_SELECTOR, (upb_func*)func, attr); + return doset(h, UPB_ENDMSG_SELECTOR, NULL, UPB_HANDLER_INT32, + (upb_func *)func, attr); } bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f, @@ -270,6 +377,14 @@ const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h, return SUBH_F(h, f); } +bool upb_handlers_getattr(const upb_handlers *h, upb_selector_t sel, + upb_handlerattr *attr) { + if (!upb_handlers_gethandler(h, sel)) + return false; + *attr = h->table[sel].attr; + return true; +} + const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h, upb_selector_t sel) { // STARTSUBMSG selector in sel is the field's selector base. @@ -284,12 +399,37 @@ const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h) { return h->msg; } bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) { // TODO: verify we have a transitive closure. for (int i = 0; i < n; i++) { - if (!upb_ok(&handlers[i]->status_)) { + upb_handlers *h = handlers[i]; + + if (!upb_ok(&h->status_)) { upb_status_seterrf(s, "handlers for message %s had error status: %s", - upb_msgdef_fullname(upb_handlers_msgdef(handlers[i])), - upb_status_errmsg(&handlers[i]->status_)); + upb_msgdef_fullname(upb_handlers_msgdef(h)), + upb_status_errmsg(&h->status_)); return false; } + + // Check that there are no closure mismatches due to missing Start* handlers + // or subhandlers with different type-level types. + upb_msg_iter j; + for(upb_msg_begin(&j, h->msg); !upb_msg_done(&j); upb_msg_next(&j)) { + + const upb_fielddef *f = upb_msg_iter_field(&j); + if (upb_fielddef_isseq(f)) { + if (!checkstart(h, f, UPB_HANDLER_STARTSEQ, s)) + return false; + } + + if (upb_fielddef_isstring(f)) { + if (!checkstart(h, f, UPB_HANDLER_STARTSTR, s)) + return false; + } + + if (upb_fielddef_issubmsg(f)) { + // TODO(haberman): check type of submessage. + // This is slightly tricky; also consider whether we should check that + // they match at setsubhandlers time. + } + } } if (!upb_refcounted_freeze((upb_refcounted*const*)handlers, n, s, @@ -394,13 +534,44 @@ void upb_handlerattr_uninit(upb_handlerattr *attr) { bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, void *hd, upb_handlerfree *cleanup) { - if (attr->handler_data_) - return false; attr->handler_data_ = hd; attr->cleanup = cleanup; return true; } +bool upb_handlerattr_setclosuretype(upb_handlerattr *attr, const void *type) { + attr->closure_type_ = type; + return true; +} + +const void *upb_handlerattr_closuretype(const upb_handlerattr *attr) { + return attr->closure_type_; +} + +bool upb_handlerattr_setreturnclosuretype(upb_handlerattr *attr, + const void *type) { + attr->return_closure_type_ = type; + return true; +} + +const void *upb_handlerattr_returnclosuretype(const upb_handlerattr *attr) { + return attr->return_closure_type_; +} + +bool upb_handlerattr_setalwaysok(upb_handlerattr *attr, bool alwaysok) { + attr->alwaysok_ = alwaysok; + return true; +} + +bool upb_handlerattr_alwaysok(const upb_handlerattr *attr) { + return attr->alwaysok_; +} + +/* upb_bufhandle **************************************************************/ + +size_t upb_bufhandle_objofs(const upb_bufhandle *h) { + return h->objofs_; +} /* upb_byteshandler ***********************************************************/ diff --git a/upb/handlers.h b/upb/handlers.h index ceb559f..a03c99e 100644 --- a/upb/handlers.h +++ b/upb/handlers.h @@ -27,18 +27,26 @@ #ifdef __cplusplus namespace upb { +class BufferHandle; +class BytesHandler; class HandlerAttributes; class Handlers; template <class T> class Handler; template <class T> struct CanonicalType; } // namespace upb +typedef upb::BufferHandle upb_bufhandle; +typedef upb::BytesHandler upb_byteshandler; typedef upb::HandlerAttributes upb_handlerattr; typedef upb::Handlers upb_handlers; #else +struct upb_bufhandle; +struct upb_byteshandler; struct upb_handlerattr; struct upb_handlers; struct upb_sinkframe; +typedef struct upb_bufhandle upb_bufhandle; +typedef struct upb_byteshandler upb_byteshandler; typedef struct upb_handlerattr upb_handlerattr; typedef struct upb_handlers upb_handlers; typedef struct upb_sinkframe upb_sinkframe; @@ -89,12 +97,23 @@ typedef void upb_func(); extern "C" { #endif +// Forward-declares for C inline accessors. We need to declare these here +// so we can "friend" them in the class declarations in C++. UPB_INLINE upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s); UPB_INLINE const void *upb_handlerattr_handlerdata(const upb_handlerattr *attr); UPB_INLINE const void *upb_handlers_gethandlerdata(const upb_handlers *h, upb_selector_t s); +UPB_INLINE void upb_bufhandle_init(upb_bufhandle *h); +UPB_INLINE void upb_bufhandle_setobj(upb_bufhandle *h, const void *obj, + const void *type); +UPB_INLINE void upb_bufhandle_setbuf(upb_bufhandle *h, const char *buf, + size_t ofs); +UPB_INLINE const void *upb_bufhandle_obj(const upb_bufhandle *h); +UPB_INLINE const void *upb_bufhandle_objtype(const upb_bufhandle *h); +UPB_INLINE const char *upb_bufhandle_buf(const upb_bufhandle *h); + #ifdef __cplusplus } #endif @@ -114,6 +133,7 @@ typedef void upb_handlerfree(void *d); #ifdef __cplusplus +// A set of attributes that accompanies a handler's function pointer. class upb::HandlerAttributes { public: HandlerAttributes(); @@ -126,7 +146,27 @@ class upb::HandlerAttributes { // cleanup handler will be called once for each handler it was successfully // set on. bool SetHandlerData(void *handler_data, upb_handlerfree *cleanup); - void *handler_data() const; + const void* handler_data() const; + + // Use this to specify the type of the closure. This will be checked against + // all other closure types for handler that use the same closure. + // Registration will fail if this does not match all other non-NULL closure + // types. + bool SetClosureType(const void *closure_type); + const void* closure_type() const; + + // Use this to specify the type of the returned closure. Only used for + // Start*{String,SubMessage,Sequence} handlers. This must match the closure + // type of any handlers that use it (for example, the StringBuf handler must + // match the closure returned from StartString). + bool SetReturnClosureType(const void *return_closure_type); + const void* return_closure_type() const; + + // Set to indicate that the handler always returns "ok" (either "true" or a + // non-NULL closure). This is a hint that can allow code generators to + // generate more efficient code. + bool SetAlwaysOk(bool always_ok); + bool always_ok() const; private: friend UPB_INLINE const void * ::upb_handlerattr_handlerdata( @@ -137,15 +177,81 @@ struct upb_handlerattr { #endif void *handler_data_; upb_handlerfree *cleanup; + const void *closure_type_; + const void *return_closure_type_; + bool alwaysok_; }; +#define UPB_HANDLERATTR_INITIALIZER {NULL, NULL, NULL, NULL, false} + typedef struct { upb_func *func; + // It is wasteful to include the entire attributes here: + // + // * Some of the information is redundant (like storing the closure type + // separately for each handler that must match). + // * Some of the info is only needed prior to freeze() (like closure types). + // * alignment padding wastes a lot of space for alwaysok_. + // + // If/when the size and locality of handlers is an issue, we can optimize this + // not to store the entire attr like this. We do not expose the table's + // layout to allow this optimization in the future. upb_handlerattr attr; } upb_handlers_tabent; #ifdef __cplusplus +// Extra information about a buffer that is passed to a StringBuf handler. +// TODO(haberman): allow the handle to be pinned so that it will outlive +// the handler invocation. +class upb::BufferHandle { + public: + BufferHandle(); + ~BufferHandle(); + + // The beginning of the buffer. This may be different than the pointer + // passed to a StringBuf handler because the handler may receive data + // that is from the middle or end of a larger buffer. + const char* buffer() const; + + // The offset within the attached object where this buffer begins. Only + // meaningful if there is an attached object. + size_t object_offset() const; + + // Note that object_offset is the offset of "buf" within the attached object. + void SetBuffer(const char* buf, size_t object_offset); + + // The BufferHandle can have an "attached object", which can be used to + // tunnel through a pointer to the buffer's underlying representation. + template <class T> + void SetAttachedObject(const T* obj); + + // Returns NULL if the attached object is not of this type. + template <class T> + const T* GetAttachedObject() const; + + private: + friend UPB_INLINE void ::upb_bufhandle_init(upb_bufhandle *h); + friend UPB_INLINE void ::upb_bufhandle_setobj(upb_bufhandle *h, + const void *obj, + const void *type); + friend UPB_INLINE void ::upb_bufhandle_setbuf(upb_bufhandle *h, + const char *buf, size_t ofs); + friend UPB_INLINE const void* ::upb_bufhandle_obj(const upb_bufhandle *h); + friend UPB_INLINE const void* ::upb_bufhandle_objtype( + const upb_bufhandle *h); + friend UPB_INLINE const char* ::upb_bufhandle_buf(const upb_bufhandle *h); +#else +struct upb_bufhandle { +#endif + const char *buf_; + const void *obj_; + const void *objtype_; + size_t objofs_; +}; + +#ifdef __cplusplus + // A upb::Handlers object represents the set of handlers associated with a // message in the graph of messages. You can think of it as a big virtual // table with functions corresponding to all the events that can fire while @@ -167,8 +273,8 @@ class upb::Handlers { typedef Handler<bool (*)(void *, const void *)> StartMessageHandler; typedef Handler<bool (*)(void *, const void *, Status*)> EndMessageHandler; typedef Handler<void *(*)(void *, const void *, size_t)> StartStringHandler; - typedef Handler<size_t(*)(void *, const void *, const char *, size_t)> - StringHandler; + typedef Handler<size_t (*)(void *, const void *, const char *, size_t, + const BufferHandle *)> StringHandler; template <class T> struct ValueHandler { typedef Handler<bool(*)(void *, const void *, T)> H; @@ -224,7 +330,7 @@ class upb::Handlers { // Freezes the given set of handlers. You may not freeze a handler without // also freezing any handlers they point to. static bool Freeze(Handlers*const* handlers, int n, Status* s); - static bool Freeze(const vector<Handlers*>& handlers, Status* s); + static bool Freeze(const std::vector<Handlers*>& handlers, Status* s); // Returns the msgdef associated with this handlers object. const MessageDef* message_def() const; @@ -401,6 +507,9 @@ class upb::Handlers { // responsibility to cast to the correct function type before calling it. GenericFunction* GetHandler(Selector selector); + // Sets the given attributes to the attributes for this selector. + bool GetAttributes(Selector selector, HandlerAttributes* attr); + // Returns the handler data that was registered with this handler. const void* GetHandlerData(Selector selector); @@ -424,6 +533,7 @@ struct upb_handlers { upb_refcounted base; const upb_msgdef *msg; const upb_handlers **sub; + const void *top_closure_type; upb_status status_; // Used only when mutable. upb_handlers_tabent table[1]; // Dynamically-sized field handler array. }; @@ -538,31 +648,38 @@ typedef bool upb_bool_handlerfunc(void *c, const void *hd, bool val); typedef void *upb_startstr_handlerfunc(void *c, const void *hd, size_t size_hint); typedef size_t upb_string_handlerfunc(void *c, const void *hd, const char *buf, - size_t n); -// upb_handlerattr -#define UPB_HANDLERATTR_INITIALIZER {NULL, NULL} + size_t n, const upb_bufhandle* handle); +// upb_bufhandle +size_t upb_bufhandle_objofs(const upb_bufhandle *h); + +// upb_handlerattr void upb_handlerattr_init(upb_handlerattr *attr); void upb_handlerattr_uninit(upb_handlerattr *attr); bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, void *hd, upb_handlerfree *cleanup); +bool upb_handlerattr_setclosuretype(upb_handlerattr *attr, const void *type); +const void *upb_handlerattr_closuretype(const upb_handlerattr *attr); +bool upb_handlerattr_setreturnclosuretype(upb_handlerattr *attr, + const void *type); +const void *upb_handlerattr_returnclosuretype(const upb_handlerattr *attr); +bool upb_handlerattr_setalwaysok(upb_handlerattr *attr, bool alwaysok); +bool upb_handlerattr_alwaysok(const upb_handlerattr *attr); + UPB_INLINE const void *upb_handlerattr_handlerdata( const upb_handlerattr *attr) { return attr->handler_data_; } -typedef void upb_handlers_callback(void *closure, upb_handlers *h); - // upb_handlers +typedef void upb_handlers_callback(void *closure, upb_handlers *h); upb_handlers *upb_handlers_new(const upb_msgdef *m, const void *owner); const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m, const void *owner, upb_handlers_callback *callback, void *closure); - -// From upb_refcounted. bool upb_handlers_isfrozen(const upb_handlers *h); void upb_handlers_ref(const upb_handlers *h, const void *owner); void upb_handlers_unref(const upb_handlers *h, const void *owner); @@ -630,17 +747,32 @@ UPB_INLINE upb_func *upb_handlers_gethandler(const upb_handlers *h, return (upb_func *)h->table[s].func; } +bool upb_handlers_getattr(const upb_handlers *h, upb_selector_t s, + upb_handlerattr *attr); + UPB_INLINE const void *upb_handlers_gethandlerdata(const upb_handlers *h, upb_selector_t s) { return upb_handlerattr_handlerdata(&h->table[s].attr); } +#ifdef __cplusplus + // Handler types for single fields. // Right now we only have one for TYPE_BYTES but ones for other types // should follow. // // These follow the same handlers protocol for fields of a message. -typedef struct { upb_handlers_tabent table[3]; } upb_byteshandler; +class upb::BytesHandler { + public: + BytesHandler(); + ~BytesHandler(); + + // TODO(haberman): make private and figure out what to friend. +#else +struct upb_byteshandler { +#endif + upb_handlers_tabent table[3]; +}; void upb_byteshandler_init(upb_byteshandler *h); void upb_byteshandler_uninit(upb_byteshandler *h); @@ -659,7 +791,7 @@ bool upb_byteshandler_setendstr(upb_byteshandler *h, #ifdef __cplusplus namespace upb { -typedef upb_byteshandler BytesHandler; +typedef upb_byteshandler BytesHandler; } #endif diff --git a/upb/pb/compile_decoder_x64.c b/upb/pb/compile_decoder_x64.c index 429f690..44331b8 100644 --- a/upb/pb/compile_decoder_x64.c +++ b/upb/pb/compile_decoder_x64.c @@ -56,8 +56,6 @@ typedef struct { // Used by DynASM to store globals. void **globals; - - bool chkret; } jitcompiler; // Functions called by codegen. @@ -72,7 +70,6 @@ static int pcofs(jitcompiler* jc); static jitcompiler *newjitcompiler(mgroup *group) { jitcompiler *jc = malloc(sizeof(jitcompiler)); - jc->chkret = false; jc->group = group; jc->pclabel_count = 0; jc->lastlabelofs = -1; diff --git a/upb/pb/compile_decoder_x64.dasc b/upb/pb/compile_decoder_x64.dasc index fec822a..571aa9b 100644 --- a/upb/pb/compile_decoder_x64.dasc +++ b/upb/pb/compile_decoder_x64.dasc @@ -23,6 +23,7 @@ |.define ARG3_32, edx |.define ARG3_64, rdx |.define ARG4_64, rcx +|.define ARG5_64, r8 |.define XMMARG1, xmm0 | |// Register allocation / type map. @@ -159,6 +160,16 @@ static upb_func *gethandler(const upb_handlers *h, upb_selector_t sel) { return h ? upb_handlers_gethandler(h, sel) : NULL; } +// Should only be called when the associated handler is known to exist. +static bool alwaysok(const upb_handlers *h, upb_selector_t sel) { + upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; + bool ok = upb_handlers_getattr(h, sel, &attr); + UPB_ASSERT_VAR(ok, ok); + bool ret = upb_handlerattr_alwaysok(&attr); + upb_handlerattr_uninit(&attr); + return ret; +} + // Emit static assembly routines; code that does not vary based on the message // schema. Since it's not input-dependent, we only need one single copy of it. // For the moment we generate a single copy per generated handlers. Eventually @@ -623,9 +634,9 @@ static void jitprimitive(jitcompiler *jc, opcode op, | mov ARG1_64, CLOSURE | load_handler_data h, sel | callp handler - if (jc->chkret) { + if (!alwaysok(h, sel)) { | test al, al - | jz >5 + | jnz >5 | call ->suspend | jmp <1 |5: @@ -887,10 +898,11 @@ static void jitbytecode(jitcompiler *jc) { | mov ARG1_64, CLOSURE | load_handler_data h, UPB_STARTMSG_SELECTOR | callp startmsg - if (jc->chkret) { + if (!alwaysok(h, UPB_STARTMSG_SELECTOR)) { | test al, al - | jnz <2 + | jnz >2 | call ->suspend + | jmp <1 |2: } } @@ -960,7 +972,7 @@ static void jitbytecode(jitcompiler *jc) { | sub ARG3_64, PTR } | callp start - if (jc->chkret) { + if (!alwaysok(h, arg)) { | test rax, rax | jnz >2 | call ->suspend @@ -986,7 +998,7 @@ static void jitbytecode(jitcompiler *jc) { | mov ARG1_64, CLOSURE | load_handler_data h, arg | callp end - if (jc->chkret) { + if (!alwaysok(h, arg)) { | test al, al | jnz >2 | call ->suspend @@ -1016,9 +1028,10 @@ static void jitbytecode(jitcompiler *jc) { | mov ARG3_64, PTR | mov ARG4_64, DATAEND | sub ARG4_64, PTR + | mov ARG5_64, qword DECODER->handle | callp str | add PTR, rax - if (jc->chkret) { + if (!alwaysok(h, arg)) { | cmp PTR, DATAEND | je >3 | call ->strret_fallback diff --git a/upb/pb/decoder.c b/upb/pb/decoder.c index 6fd6576..c5fae0e 100644 --- a/upb/pb/decoder.c +++ b/upb/pb/decoder.c @@ -148,10 +148,11 @@ static void checkpoint(upb_pbdecoder *d) { // Resumes the decoder from an initial state or from a previous suspend. void *upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf, - size_t size) { + size_t size, const upb_bufhandle *handle) { UPB_UNUSED(p); // Useless; just for the benefit of the JIT. d->buf_param = buf; d->size_param = size; + d->handle = handle; d->skip = 0; if (d->residual_end > d->residual) { // We have residual bytes from the last buffer. @@ -488,11 +489,11 @@ upb_pbdecoder_frame *outer_frame(upb_pbdecoder *d) { /* The main decoding loop *****************************************************/ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, - size_t size) { + size_t size, const upb_bufhandle *handle) { upb_pbdecoder *d = closure; const mgroup *group = hd; assert(buf); - upb_pbdecoder_resume(d, NULL, buf, size); + upb_pbdecoder_resume(d, NULL, buf, size, handle); UPB_UNUSED(group); #define VMCASE(op, code) \ @@ -578,7 +579,8 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, ) VMCASE(OP_STRING, uint32_t len = curbufleft(d); - CHECK_SUSPEND(upb_sink_putstring(&d->top->sink, arg, ptr(d), len)); + CHECK_SUSPEND( + upb_sink_putstring(&d->top->sink, arg, ptr(d), len, handle)); advance(d, len); if (d->delim_end == NULL) { // String extends beyond this buf? d->pc--; @@ -683,6 +685,7 @@ void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint) { void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint) { UPB_UNUSED(hd); + UPB_UNUSED(size_hint); upb_pbdecoder *d = closure; d->call_len = 0; return d; @@ -712,7 +715,7 @@ bool upb_pbdecoder_end(void *closure, const void *handler_data) { if (group->jit_code) { if (d->top != d->stack) d->stack->end_ofs = 0; - group->jit_code(closure, method->code_base.ptr, &dummy, 0); + group->jit_code(closure, method->code_base.ptr, &dummy, 0, NULL); } else { #endif d->stack->end_ofs = end; @@ -726,7 +729,7 @@ bool upb_pbdecoder_end(void *closure, const void *handler_data) { getop(*d->pc) == OP_TAGN); d->pc = p; } - upb_pbdecoder_decode(closure, handler_data, &dummy, 0); + upb_pbdecoder_decode(closure, handler_data, &dummy, 0, NULL); #ifdef UPB_USE_JIT_X64 } #endif @@ -762,7 +765,9 @@ void upb_pbdecoder_reset(upb_pbdecoder *d) { // Not currently required, but to support outgrowing the static stack we need // this. -void upb_pbdecoder_uninit(upb_pbdecoder *d) {} +void upb_pbdecoder_uninit(upb_pbdecoder *d) { + UPB_UNUSED(d); +} const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d) { return d->method_; diff --git a/upb/pb/decoder.h b/upb/pb/decoder.h index 4529324..4313bb3 100644 --- a/upb/pb/decoder.h +++ b/upb/pb/decoder.h @@ -234,6 +234,7 @@ struct upb_pbdecoder { // Stores the user buffer passed to our decode function. const char *buf_param; size_t size_param; + const upb_bufhandle *handle; #ifdef UPB_USE_JIT_X64 // Used momentarily by the generated code to store a value while a user diff --git a/upb/pb/decoder.int.h b/upb/pb/decoder.int.h index 1c10eb3..20afa68 100644 --- a/upb/pb/decoder.int.h +++ b/upb/pb/decoder.int.h @@ -108,12 +108,12 @@ typedef struct { void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint); void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint); size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, - size_t size); + size_t size, const upb_bufhandle *handle); bool upb_pbdecoder_end(void *closure, const void *handler_data); // Decoder-internal functions that the JIT calls to handle fallback paths. void *upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf, - size_t size); + size_t size, const upb_bufhandle *handle); size_t upb_pbdecoder_suspend(upb_pbdecoder *d); int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, uint32_t fieldnum, uint8_t wire_type); diff --git a/upb/pb/textprinter.c b/upb/pb/textprinter.c index 0c12571..8a49c73 100644 --- a/upb/pb/textprinter.c +++ b/upb/pb/textprinter.c @@ -3,6 +3,9 @@ * * Copyright (c) 2009 Google Inc. See LICENSE for details. * Author: Josh Haberman <jhaberman@gmail.com> + * + * OPT: This is not optimized at all. It uses printf() which parses the format + * string every time, and it allocates memory for every put. */ #include "upb/pb/textprinter.h" @@ -16,29 +19,29 @@ #include "upb/sink.h" -struct _upb_textprinter { - int indent_depth; - bool single_line; - upb_status status; -}; - #define CHECK(x) if ((x) < 0) goto err; +static const char *shortname(const char *longname) { + const char *last = strrchr(longname, '.'); + return last ? last + 1 : longname; +} + static int indent(upb_textprinter *p) { int i; - if (!p->single_line) - for (i = 0; i < p->indent_depth * 2; i++) - putchar(' '); + if (!p->single_line_) + for (i = 0; i < p->indent_depth_; i++) + upb_bytessink_putbuf(p->output_, p->subc, " ", 2, NULL); return 0; - return -1; } static int endfield(upb_textprinter *p) { - putchar(p->single_line ? ' ' : '\n'); + const char ch = (p->single_line_ ? ' ' : '\n'); + upb_bytessink_putbuf(p->output_, p->subc, &ch, 1, NULL); return 0; } -static int putescaped(const char* buf, size_t len, bool preserve_utf8) { +static int putescaped(upb_textprinter *p, const char *buf, size_t len, + bool preserve_utf8) { // Based on CEscapeInternal() from Google's protobuf release. char dstbuf[4096], *dst = dstbuf, *dstend = dstbuf + sizeof(dstbuf); const char *end = buf + len; @@ -50,7 +53,7 @@ static int putescaped(const char* buf, size_t len, bool preserve_utf8) { for (; buf < end; buf++) { if (dstend - dst < 4) { - fwrite(dstbuf, dst - dstbuf, 1, stdout); + upb_bytessink_putbuf(p->output_, p->subc, dstbuf, dst - dstbuf, NULL); dst = dstbuf; } @@ -78,18 +81,57 @@ static int putescaped(const char* buf, size_t len, bool preserve_utf8) { last_hex_escape = is_hex_escape; } // Flush remaining data. - fwrite(dst, dst - dstbuf, 1, stdout); + upb_bytessink_putbuf(p->output_, p->subc, dstbuf, dst - dstbuf, NULL); return 0; } +bool putf(upb_textprinter *p, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + + // Run once to get the length of the string. + va_list args_copy; + va_copy(args_copy, args); + int len = vsnprintf(NULL, 0, fmt, args_copy); + va_end(args_copy); + + // + 1 for NULL terminator (vsnprintf() requires it even if we don't). + char *str = malloc(len + 1); + if (!str) return false; + int written = vsnprintf(str, len + 1, fmt, args); + va_end(args); + UPB_ASSERT_VAR(written, written == len); + + bool ok = upb_bytessink_putbuf(p->output_, p->subc, str, len, NULL); + free(str); + return ok; +} + + +/* handlers *******************************************************************/ + +static bool startmsg(void *c, const void *hd) { + upb_textprinter *p = c; + if (p->indent_depth_ == 0) { + upb_bytessink_start(p->output_, 0, &p->subc); + } + return true; +} + +static bool endmsg(void *c, const void *hd, upb_status *s) { + upb_textprinter *p = c; + if (p->indent_depth_ == 0) { + upb_bytessink_end(p->output_); + } + return true; +} + #define TYPE(name, ctype, fmt) \ static bool put ## name(void *closure, const void *handler_data, ctype val) {\ upb_textprinter *p = closure; \ const upb_fielddef *f = handler_data; \ CHECK(indent(p)); \ - puts(upb_fielddef_name(f)); \ - puts(": "); \ - printf(fmt, val); \ + putf(p, "%s: " fmt, upb_fielddef_name(f), val); \ CHECK(endfield(p)); \ return true; \ err: \ @@ -100,9 +142,7 @@ static bool putbool(void *closure, const void *handler_data, bool val) { upb_textprinter *p = closure; const upb_fielddef *f = handler_data; CHECK(indent(p)); - puts(upb_fielddef_name(f)); - puts(": "); - puts(val ? "true" : "false"); + putf(p, "%s: %s", upb_fielddef_name(f), val ? "true" : "false"); CHECK(endfield(p)); return true; err: @@ -121,11 +161,14 @@ TYPE(double, double, "%." STRINGIFY_MACROVAL(DBL_DIG) "g") // Output a symbolic value from the enum if found, else just print as int32. static bool putenum(void *closure, const void *handler_data, int32_t val) { + upb_textprinter *p = closure; const upb_fielddef *f = handler_data; const upb_enumdef *enum_def = upb_downcast_enumdef(upb_fielddef_subdef(f)); const char *label = upb_enumdef_iton(enum_def, val); if (label) { - puts(label); + indent(p); + putf(p, "%s: %s", upb_fielddef_name(f), label); + endfield(p); } else { CHECK(putint32(closure, handler_data, val)); } @@ -136,25 +179,27 @@ err: static void *startstr(void *closure, const void *handler_data, size_t size_hint) { - UPB_UNUSED(handler_data); + const upb_fielddef *f = handler_data; UPB_UNUSED(size_hint); upb_textprinter *p = closure; - putchar('"'); + putf(p, "%s: \"", upb_fielddef_name(f)); return p; } static bool endstr(void *closure, const void *handler_data) { - UPB_UNUSED(closure); UPB_UNUSED(handler_data); - putchar('"'); + upb_textprinter *p = closure; + putf(p, "\""); + endfield(p); return true; } static size_t putstr(void *closure, const void *hd, const char *buf, - size_t len) { - UPB_UNUSED(closure); + size_t len, const upb_bufhandle *handle) { + UPB_UNUSED(handle); + upb_textprinter *p = closure; const upb_fielddef *f = hd; - CHECK(putescaped(buf, len, upb_fielddef_type(f) == UPB_TYPE_STRING)); + CHECK(putescaped(p, buf, len, upb_fielddef_type(f) == UPB_TYPE_STRING)); return len; err: return 0; @@ -162,12 +207,10 @@ err: static void *startsubmsg(void *closure, const void *handler_data) { upb_textprinter *p = closure; - const upb_fielddef *f = handler_data; + const char *name = handler_data; CHECK(indent(p)); - printf("%s {", upb_fielddef_name(f)); - if (!p->single_line) - putchar('\n'); - p->indent_depth++; + putf(p, "%s {%c", name, p->single_line_ ? ' ' : '\n'); + p->indent_depth_++; return p; err: return UPB_BREAK; @@ -176,30 +219,36 @@ err: static bool endsubmsg(void *closure, const void *handler_data) { UPB_UNUSED(handler_data); upb_textprinter *p = closure; - p->indent_depth--; + p->indent_depth_--; CHECK(indent(p)); - putchar('}'); + upb_bytessink_putbuf(p->output_, p->subc, "}", 1, NULL); CHECK(endfield(p)); return true; err: return false; } -upb_textprinter *upb_textprinter_new() { - upb_textprinter *p = malloc(sizeof(*p)); - return p; + +/* Public API *****************************************************************/ + +void upb_textprinter_init(upb_textprinter *p, const upb_handlers *h) { + p->single_line_ = false; + p->indent_depth_ = 0; + upb_sink_reset(&p->input_, h, p); } -void upb_textprinter_free(upb_textprinter *p) { free(p); } +void upb_textprinter_uninit(upb_textprinter *p) {} void upb_textprinter_reset(upb_textprinter *p, bool single_line) { - p->single_line = single_line; - p->indent_depth = 0; + p->single_line_ = single_line; + p->indent_depth_ = 0; } static void onmreg(void *c, upb_handlers *h) { (void)c; const upb_msgdef *m = upb_handlers_msgdef(h); + upb_handlers_setstartmsg(h, startmsg, NULL); + upb_handlers_setendmsg(h, endmsg, NULL); upb_msg_iter i; for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) { upb_fielddef *f = upb_msg_iter_field(&i); @@ -233,20 +282,37 @@ static void onmreg(void *c, upb_handlers *h) { upb_handlers_setstring(h, f, putstr, &attr); upb_handlers_setendstr(h, f, endstr, &attr); break; - case UPB_TYPE_MESSAGE: + case UPB_TYPE_MESSAGE: { + const char *name = + upb_fielddef_istagdelim(f) + ? shortname(upb_msgdef_fullname(upb_fielddef_msgsubdef(f))) + : upb_fielddef_name(f); + // TODO(haberman): add "setconsthandlerdata"? If we pass NULL for + // cleanup then we don't need a non-const pointer. + upb_handlerattr_sethandlerdata(&attr, (void*)name, NULL); upb_handlers_setstartsubmsg(h, f, startsubmsg, &attr); upb_handlers_setendsubmsg(h, f, endsubmsg, &attr); break; + } case UPB_TYPE_ENUM: upb_handlers_setint32(h, f, putenum, &attr); - default: - assert(false); break; } } } -const upb_handlers *upb_textprinter_newhandlers(const void *owner, - const upb_msgdef *m) { +const upb_handlers *upb_textprinter_newhandlers(const upb_msgdef *m, + const void *owner) { return upb_handlers_newfrozen(m, owner, &onmreg, NULL); } + +upb_sink *upb_textprinter_input(upb_textprinter *p) { return &p->input_; } + +bool upb_textprinter_resetoutput(upb_textprinter *p, upb_bytessink *output) { + p->output_ = output; + return true; +} + +void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line) { + p->single_line_ = single_line; +} diff --git a/upb/pb/textprinter.h b/upb/pb/textprinter.h index 7b653e7..eb3e132 100644 --- a/upb/pb/textprinter.h +++ b/upb/pb/textprinter.h @@ -8,23 +8,87 @@ #ifndef UPB_TEXT_H_ #define UPB_TEXT_H_ -#include "upb/handlers.h" +#include "upb/sink.h" + +#ifdef __cplusplus +namespace upb { +namespace pb { +class TextPrinter; +} // namespace pb +} // namespace upb + +typedef upb::pb::TextPrinter upb_textprinter; +#else +struct upb_textprinter; +typedef struct upb_textprinter upb_textprinter; +#endif + +#ifdef __cplusplus +class upb::pb::TextPrinter { + public: + // The given handlers must have come from NewHandlers(). It must outlive the + // TextPrinter. + explicit TextPrinter(const upb::Handlers* handlers); + + void SetSingleLineMode(bool single_line); + + bool ResetOutput(BytesSink* output); + Sink* input(); + + // If handler caching becomes a requirement we can add a code cache as in + // decoder.h + static reffed_ptr<const Handlers> NewHandlers(const MessageDef* md); + + private: +#else +struct upb_textprinter { +#endif + upb_sink input_; + upb_bytessink *output_; + int indent_depth_; + bool single_line_; + void *subc; +}; #ifdef __cplusplus extern "C" { #endif -struct _upb_textprinter; -typedef struct _upb_textprinter upb_textprinter; +// C API. +void upb_textprinter_init(upb_textprinter *p, const upb_handlers *h); +void upb_textprinter_uninit(upb_textprinter *p); +bool upb_textprinter_resetoutput(upb_textprinter *p, upb_bytessink *output); +void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line); +upb_sink *upb_textprinter_input(upb_textprinter *p); -upb_textprinter *upb_textprinter_new(); -void upb_textprinter_free(upb_textprinter *p); -void upb_textprinter_reset(upb_textprinter *p, bool single_line); -const upb_handlers *upb_textprinter_newhandlers(const void *owner, - const upb_msgdef *m); +const upb_handlers *upb_textprinter_newhandlers(const upb_msgdef *m, + const void *owner); #ifdef __cplusplus } /* extern "C" */ + +namespace upb { +namespace pb { +inline TextPrinter::TextPrinter(const upb::Handlers* handlers) { + upb_textprinter_init(this, handlers); +} +inline void TextPrinter::SetSingleLineMode(bool single_line) { + upb_textprinter_setsingleline(this, single_line); +} +inline bool TextPrinter::ResetOutput(BytesSink* output) { + return upb_textprinter_resetoutput(this, output); +} +inline Sink* TextPrinter::input() { + return upb_textprinter_input(this); +} +inline reffed_ptr<const Handlers> TextPrinter::NewHandlers( + const MessageDef *md) { + const Handlers* h = upb_textprinter_newhandlers(md, &h); + return reffed_ptr<const Handlers>(h, &h); +} +} // namespace pb +} // namespace upb + #endif #endif /* UPB_TEXT_H_ */ diff --git a/upb/shim/shim.c b/upb/shim/shim.c index 5c3e026..797a2d1 100644 --- a/upb/shim/shim.c +++ b/upb/shim/shim.c @@ -38,6 +38,7 @@ bool upb_shim_set(upb_handlers *h, const upb_fielddef *f, size_t offset, upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; upb_handlerattr_sethandlerdata(&attr, d, free); + upb_handlerattr_setalwaysok(&attr, true); #define TYPE(u, l) \ case UPB_TYPE_##u: \ @@ -120,7 +120,8 @@ class upb::Sink { // For StartString(), the function will write a sink for the string to "sub." // The sub-sink must be used for any/all PutStringBuffer() calls. bool StartString(Handlers::Selector s, size_t size_hint, Sink* sub); - size_t PutStringBuffer(Handlers::Selector s, const char *buf, size_t len); + size_t PutStringBuffer(Handlers::Selector s, const char *buf, size_t len, + const BufferHandle *handle); bool EndString(Handlers::Selector s); // For submessage fields. @@ -160,13 +161,14 @@ class upb::BytesSink { // // TODO(haberman): once the Handlers know the expected closure type, verify // that T matches it. - template <class T> BytesSink(const Handlers* handlers, T* closure); + template <class T> BytesSink(const BytesHandler* handler, T* closure); // Resets the value of the sink. - template <class T> void Reset(const Handlers* handlers, T* closure); + template <class T> void Reset(const BytesHandler* handler, T* closure); bool Start(size_t size_hint, void **subc); - size_t PutBuffer(void *subc, const char *buf, size_t len); + size_t PutBuffer(void *subc, const char *buf, size_t len, + const BufferHandle *handle); bool End(); #else @@ -219,6 +221,7 @@ UPB_INLINE void upb_bytessink_reset(upb_bytessink *s, const upb_byteshandler *h, UPB_INLINE bool upb_bytessink_start(upb_bytessink *s, size_t size_hint, void **subc) { + *subc = NULL; if (!s->handler) return true; upb_startstr_handlerfunc *start = (upb_startstr_handlerfunc *)s->handler->table[UPB_STARTSTR_SELECTOR].func; @@ -231,7 +234,8 @@ UPB_INLINE bool upb_bytessink_start(upb_bytessink *s, size_t size_hint, } UPB_INLINE size_t upb_bytessink_putbuf(upb_bytessink *s, void *subc, - const char *buf, size_t size) { + const char *buf, size_t size, + const upb_bufhandle* handle) { if (!s->handler) return true; upb_string_handlerfunc *putbuf = (upb_string_handlerfunc *)s->handler->table[UPB_STRING_SELECTOR].func; @@ -239,7 +243,7 @@ UPB_INLINE size_t upb_bytessink_putbuf(upb_bytessink *s, void *subc, if (!putbuf) return true; return putbuf(subc, upb_handlerattr_handlerdata( &s->handler->table[UPB_STRING_SELECTOR].attr), - buf, size); + buf, size, handle); } UPB_INLINE bool upb_bytessink_end(upb_bytessink *s) { @@ -256,10 +260,18 @@ UPB_INLINE bool upb_bytessink_end(upb_bytessink *s) { UPB_INLINE bool upb_bufsrc_putbuf(const char *buf, size_t len, upb_bytessink *sink) { void *subc; - return - upb_bytessink_start(sink, len, &subc) && - (len == 0 || upb_bytessink_putbuf(sink, subc, buf, len) == len) && - upb_bytessink_end(sink); + upb_bufhandle handle; + upb_bufhandle_init(&handle); + upb_bufhandle_setbuf(&handle, buf, 0); + bool ret = upb_bytessink_start(sink, len, &subc); + if (ret && len != 0) { + ret = (upb_bytessink_putbuf(sink, subc, buf, len, &handle) == len); + } + if (ret) { + ret = upb_bytessink_end(sink); + } + upb_bufhandle_uninit(&handle); + return ret; } #define PUTVAL(type, ctype) \ @@ -287,15 +299,16 @@ UPB_INLINE void upb_sink_reset(upb_sink *s, const upb_handlers *h, void *c) { s->closure = c; } -UPB_INLINE size_t -upb_sink_putstring(upb_sink *s, upb_selector_t sel, const char *buf, size_t n) { +UPB_INLINE size_t upb_sink_putstring(upb_sink *s, upb_selector_t sel, + const char *buf, size_t n, + const upb_bufhandle *handle) { if (!s->handlers) return n; upb_string_handlerfunc *handler = (upb_string_handlerfunc *)upb_handlers_gethandler(s->handlers, sel); if (!handler) return n; const void *hd = upb_handlers_gethandlerdata(s->handlers, sel); - return handler(s->closure, hd, buf, n); + return handler(s->closure, hd, buf, n, handle); } UPB_INLINE bool upb_sink_startmsg(upb_sink *s) { @@ -443,8 +456,8 @@ inline bool Sink::StartString(Handlers::Selector sel, size_t size_hint, return upb_sink_startstr(this, sel, size_hint, sub); } inline size_t Sink::PutStringBuffer(Handlers::Selector sel, const char *buf, - size_t len) { - return upb_sink_putstring(this, sel, buf, len); + size_t len, const BufferHandle* handle) { + return upb_sink_putstring(this, sel, buf, len, handle); } inline bool Sink::EndString(Handlers::Selector sel) { return upb_sink_endstr(this, sel); @@ -462,11 +475,16 @@ inline bool Sink::EndSequence(Handlers::Selector sel) { return upb_sink_endseq(this, sel); } +template <class T> +void BytesSink::Reset(const BytesHandler *handler, T *closure) { + upb_bytessink_reset(this, handler, closure); +} inline bool BytesSink::Start(size_t size_hint, void **subc) { return upb_bytessink_start(this, size_hint, subc); } -inline size_t BytesSink::PutBuffer(void *subc, const char *buf, size_t len) { - return upb_bytessink_putbuf(this, subc, buf, len); +inline size_t BytesSink::PutBuffer(void *subc, const char *buf, size_t len, + const BufferHandle *handle) { + return upb_bytessink_putbuf(this, subc, buf, len, handle); } inline bool BytesSink::End() { return upb_bytessink_end(this); diff --git a/upb/stdc/README b/upb/stdc/README deleted file mode 100644 index 1815af4..0000000 --- a/upb/stdc/README +++ /dev/null @@ -1,15 +0,0 @@ -This directory contains code that is ANSI C but uses parts of the -standard library that are not available to very limited environments -like Linux Kernel modules. The standard calls environments like this -"freestanding implementations." - -This does *not* imply that the upb core can be compiled directly on a -freestanding implementation. Even the core uses library functions -that are not directly available on freestanding implementations -(notably malloc()/free(), vsnprintf(), and assert()). So compiling on -freestanding implementations may require implementing compatibility -versions of functions like malloc(). - -Also, Linux is not technically a freestanding implementation either, -since it does not accept functions that return float or double on -x86-64 (these use SSE registers which are disabled in kernel mode). diff --git a/upb/symtab.c b/upb/symtab.c index a3acd16..099aa8d 100644 --- a/upb/symtab.c +++ b/upb/symtab.c @@ -146,10 +146,10 @@ static bool upb_resolve_dfs(const upb_def *def, upb_strtable *addtab, if (def->type == UPB_DEF_FIELD) continue; upb_value v; if (upb_strtable_lookup(addtab, upb_def_fullname(def), &v)) { - // Because we memoize we should not visit a node after we have dup'd it. - assert(((upb_def*)upb_value_getptr(v))->came_from_user); need_dup = true; } + + // For messages, continue the recursion by visiting all subdefs. const upb_msgdef *m = upb_dyncast_msgdef(def); if (m) { upb_msg_iter i; @@ -188,6 +188,8 @@ oom: return false; } +// TODO(haberman): we need a lot more testing of error conditions. +// The came_from_user stuff in particular is not tested. bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, upb_status *status) { upb_def **add_defs = NULL; @@ -197,7 +199,7 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, return false; } - // Add new defs to table. + // Add new defs to our "add" set. for (int i = 0; i < n; i++) { upb_def *def = defs[i]; if (upb_def_isfrozen(def)) { @@ -211,20 +213,79 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, status, "Anonymous defs cannot be added to a symtab"); goto err; } - if (upb_strtable_lookup(&addtab, fullname, NULL)) { - upb_status_seterrf(status, "Conflicting defs named '%s'", fullname); + + upb_fielddef *f = upb_dyncast_fielddef_mutable(def); + + if (f) { + if (!upb_fielddef_containingtypename(f)) { + upb_status_seterrmsg(status, + "Standalone fielddefs must have a containing type " + "(extendee) name set"); + goto err; + } + } else { + if (upb_strtable_lookup(&addtab, fullname, NULL)) { + upb_status_seterrf(status, "Conflicting defs named '%s'", fullname); + goto err; + } + // We need this to back out properly, because if there is a failure we + // need to donate the ref back to the caller. + def->came_from_user = true; + upb_def_donateref(def, ref_donor, s); + if (!upb_strtable_insert(&addtab, fullname, upb_value_ptr(def))) + goto oom_err; + } + } + + // Add standalone fielddefs (ie. extensions) to the appropriate messages. + // If the appropriate message only exists in the existing symtab, duplicate + // it so we have a mutable copy we can add the fields to. + for (int i = 0; i < n; i++) { + upb_def *def = defs[i]; + upb_fielddef *f = upb_dyncast_fielddef_mutable(def); + if (!f) continue; + const char *msgname = upb_fielddef_containingtypename(f); + // We validated this earlier in this function. + assert(msgname); + + // If the extendee name is absolutely qualified, move past the initial ".". + // TODO(haberman): it is not obvious what it would mean if this was not + // absolutely qualified. + if (msgname[0] == '.') { + msgname++; + } + + upb_value v; + upb_msgdef *m; + if (upb_strtable_lookup(&addtab, msgname, &v)) { + // Extendee is in the set of defs the user asked us to add. + m = upb_value_getptr(v); + } else { + // Need to find and dup the extendee from the existing symtab. + const upb_msgdef *frozen_m = upb_symtab_lookupmsg(s, msgname, &frozen_m); + if (!frozen_m) { + upb_status_seterrf(status, + "Tried to extend message %s that does not exist " + "in this SymbolTable.", + msgname); + goto err; + } + m = upb_msgdef_dup(frozen_m, s); + upb_msgdef_unref(frozen_m, &frozen_m); + if (!m) goto oom_err; + if (!upb_strtable_insert(&addtab, msgname, upb_value_ptr(m))) { + upb_msgdef_unref(m, s); + goto oom_err; + } + } + + if (!upb_msgdef_addfield(m, f, ref_donor, status)) { goto err; } - // We need this to back out properly, because if there is a failure we need - // to donate the ref back to the caller. - def->came_from_user = true; - upb_def_donateref(def, ref_donor, s); - if (!upb_strtable_insert(&addtab, fullname, upb_value_ptr(def))) - goto oom_err; } // Add dups of any existing def that can reach a def with the same name as - // one of "defs." + // anything in our "add" set. upb_inttable seen; if (!upb_inttable_init(&seen, UPB_CTYPE_BOOL)) goto oom_err; upb_strtable_iter i; @@ -236,7 +297,7 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, } upb_inttable_uninit(&seen); - // Now using the table, resolve symbolic references. + // Now using the table, resolve symbolic references for subdefs. upb_strtable_begin(&i, &addtab); for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { upb_def *def = upb_value_getptr(upb_strtable_iter_value(&i)); @@ -305,12 +366,13 @@ err: { upb_strtable_begin(&i, &addtab); for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { upb_def *def = upb_value_getptr(upb_strtable_iter_value(&i)); - if (def->came_from_user) { + bool came_from_user = def->came_from_user; + def->came_from_user = false; + if (came_from_user) { upb_def_donateref(def, s, ref_donor); } else { upb_def_unref(def, s); } - def->came_from_user = false; } } upb_strtable_uninit(&addtab); |