summaryrefslogtreecommitdiff
path: root/upb
diff options
context:
space:
mode:
Diffstat (limited to 'upb')
-rw-r--r--upb/bindings/README25
-rw-r--r--upb/bindings/googlepb/README20
-rw-r--r--upb/bindings/googlepb/bridge.cc (renamed from upb/google/bridge.cc)58
-rw-r--r--upb/bindings/googlepb/bridge.h (renamed from upb/google/bridge.h)55
-rw-r--r--upb/bindings/googlepb/proto1.cc (renamed from upb/google/proto1.cc)107
-rw-r--r--upb/bindings/googlepb/proto1.h (renamed from upb/google/proto1.h)0
-rw-r--r--upb/bindings/googlepb/proto2.cc (renamed from upb/google/proto2.cc)190
-rw-r--r--upb/bindings/googlepb/proto2.h (renamed from upb/google/proto2.h)0
-rw-r--r--upb/bindings/linux/Makefile20
-rw-r--r--upb/bindings/linux/assert.h20
-rw-r--r--upb/bindings/linux/errno.h8
-rw-r--r--upb/bindings/linux/stdint.h8
-rw-r--r--upb/bindings/linux/stdio.h10
-rw-r--r--upb/bindings/linux/stdlib.h22
-rw-r--r--upb/bindings/linux/string.h13
-rw-r--r--upb/bindings/lua/table.c169
-rw-r--r--upb/bindings/lua/upb.c1208
-rw-r--r--upb/bindings/lua/upb.h45
-rw-r--r--upb/bindings/python/setup.py14
-rw-r--r--upb/bindings/python/test.py72
-rw-r--r--upb/bindings/python/upb.c724
-rw-r--r--upb/bindings/python/upb/__init__.py0
-rw-r--r--upb/bindings/stdc++/string.h60
-rw-r--r--upb/bindings/stdc/error.c (renamed from upb/stdc/error.c)0
-rw-r--r--upb/bindings/stdc/error.h (renamed from upb/stdc/error.h)0
-rw-r--r--upb/bindings/stdc/io.c (renamed from upb/stdc/io.c)0
-rw-r--r--upb/bindings/stdc/io.h (renamed from upb/stdc/io.h)0
-rw-r--r--upb/def.c85
-rw-r--r--upb/def.h65
-rwxr-xr-xupb/descriptor/descriptor.upb.c146
-rw-r--r--upb/descriptor/reader.c56
-rw-r--r--upb/google/README16
-rw-r--r--upb/handlers-inl.h463
-rw-r--r--upb/handlers.c195
-rw-r--r--upb/handlers.h158
-rw-r--r--upb/pb/compile_decoder_x64.c3
-rw-r--r--upb/pb/compile_decoder_x64.dasc27
-rw-r--r--upb/pb/decoder.c19
-rw-r--r--upb/pb/decoder.h1
-rw-r--r--upb/pb/decoder.int.h4
-rw-r--r--upb/pb/textprinter.c158
-rw-r--r--upb/pb/textprinter.h80
-rw-r--r--upb/shim/shim.c1
-rw-r--r--upb/sink.h52
-rw-r--r--upb/stdc/README15
-rw-r--r--upb/symtab.c92
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
diff --git a/upb/def.c b/upb/def.c
index a674a98..805f143 100644
--- a/upb/def.c
+++ b/upb/def.c
@@ -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);
diff --git a/upb/def.h b/upb/def.h
index 2b7ebba..8951353 100644
--- a/upb/def.h
+++ b/upb/def.h
@@ -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: \
diff --git a/upb/sink.h b/upb/sink.h
index dd2b9f1..d8322e1 100644
--- a/upb/sink.h
+++ b/upb/sink.h
@@ -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);
generated by cgit on debian on lair
contact matthew@masot.net with questions or feedback