diff options
-rw-r--r-- | Makefile | 9 | ||||
-rw-r--r-- | README | 127 | ||||
-rw-r--r-- | benchmarks/parsetoproto2.upb.cc | 2 | ||||
-rw-r--r-- | tests/bindings/lua/LICENSE (renamed from bindings/lua/LICENSE) | 0 | ||||
-rw-r--r-- | tests/bindings/lua/lunit/console.lua (renamed from bindings/lua/lunit/console.lua) | 0 | ||||
-rw-r--r-- | tests/bindings/lua/lunit/lunit.lua (renamed from bindings/lua/lunit/lunit.lua) | 0 | ||||
-rw-r--r-- | tests/bindings/lua/test.lua (renamed from bindings/lua/test.lua) | 42 | ||||
-rw-r--r-- | tests/pb/test_decoder.cc (renamed from tests/test_decoder.cc) | 11 | ||||
-rw-r--r-- | tests/pb/test_decoder_schema.proto (renamed from tests/test_decoder_schema.proto) | 0 | ||||
-rw-r--r-- | tests/pb/test_varint.c (renamed from tests/test_varint.c) | 2 | ||||
-rw-r--r-- | tests/test_cpp.cc | 448 | ||||
-rw-r--r-- | tests/test_def.c | 4 | ||||
-rw-r--r-- | tests/test_vs_proto2.cc | 6 | ||||
-rw-r--r-- | tools/dump_cinit.lua | 11 | ||||
-rw-r--r-- | tools/test_cinit.lua | 2 | ||||
-rw-r--r-- | upb/bindings/README | 25 | ||||
-rw-r--r-- | upb/bindings/googlepb/README | 20 | ||||
-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/Makefile (renamed from bindings/linux/Makefile) | 0 | ||||
-rw-r--r-- | upb/bindings/linux/assert.h (renamed from bindings/linux/assert.h) | 0 | ||||
-rw-r--r-- | upb/bindings/linux/errno.h (renamed from bindings/linux/errno.h) | 0 | ||||
-rw-r--r-- | upb/bindings/linux/stdint.h (renamed from bindings/linux/stdint.h) | 0 | ||||
-rw-r--r-- | upb/bindings/linux/stdio.h (renamed from bindings/linux/stdio.h) | 0 | ||||
-rw-r--r-- | upb/bindings/linux/stdlib.h (renamed from bindings/linux/stdlib.h) | 0 | ||||
-rw-r--r-- | upb/bindings/linux/string.h (renamed from bindings/linux/string.h) | 0 | ||||
-rw-r--r-- | upb/bindings/lua/table.c (renamed from bindings/lua/table.c) | 3 | ||||
-rw-r--r-- | upb/bindings/lua/upb.c (renamed from bindings/lua/upb.c) | 70 | ||||
-rw-r--r-- | upb/bindings/lua/upb.h (renamed from bindings/lua/upb.h) | 0 | ||||
-rw-r--r-- | upb/bindings/python/setup.py (renamed from bindings/python/setup.py) | 0 | ||||
-rw-r--r-- | upb/bindings/python/test.py (renamed from bindings/python/test.py) | 0 | ||||
-rw-r--r-- | upb/bindings/python/upb.c (renamed from bindings/python/upb.c) | 0 | ||||
-rw-r--r-- | upb/bindings/python/upb/__init__.py (renamed from bindings/python/upb/__init__.py) | 0 | ||||
-rw-r--r-- | upb/bindings/stdc++/string.h | 60 | ||||
-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.c | 85 | ||||
-rw-r--r-- | upb/def.h | 65 | ||||
-rwxr-xr-x | upb/descriptor/descriptor.upb.c | 146 | ||||
-rw-r--r-- | upb/descriptor/reader.c | 56 | ||||
-rw-r--r-- | upb/google/README | 16 | ||||
-rw-r--r-- | upb/handlers-inl.h | 463 | ||||
-rw-r--r-- | upb/handlers.c | 195 | ||||
-rw-r--r-- | upb/handlers.h | 158 | ||||
-rw-r--r-- | upb/pb/compile_decoder_x64.c | 3 | ||||
-rw-r--r-- | upb/pb/compile_decoder_x64.dasc | 27 | ||||
-rw-r--r-- | upb/pb/decoder.c | 19 | ||||
-rw-r--r-- | upb/pb/decoder.h | 1 | ||||
-rw-r--r-- | upb/pb/decoder.int.h | 4 | ||||
-rw-r--r-- | upb/pb/textprinter.c | 158 | ||||
-rw-r--r-- | upb/pb/textprinter.h | 80 | ||||
-rw-r--r-- | upb/shim/shim.c | 1 | ||||
-rw-r--r-- | upb/sink.h | 52 | ||||
-rw-r--r-- | upb/stdc/README | 15 | ||||
-rw-r--r-- | upb/symtab.c | 92 |
61 files changed, 2167 insertions, 721 deletions
@@ -82,16 +82,14 @@ deps: Makefile $(ALLSRC) # The core library. CORE= \ - upb/bytestream.upb.c \ upb/def.c \ upb/descriptor/reader.c \ upb/descriptor/descriptor.upb.c \ - upb/google/bridge.cc \ - upb/google/proto2.cc \ + upb/bindings/googlepb/bridge.cc \ + upb/bindings/googlepb/proto2.cc \ upb/handlers.c \ upb/refcounted.c \ upb/shim/shim.c \ - upb/sink.c \ upb/symtab.c \ upb/table.c \ upb/upb.c \ @@ -217,8 +215,7 @@ tests/test.proto.pb: tests/test.proto SIMPLE_TESTS= \ tests/test_def \ - tests/test_varint \ - tests/test_pipeline \ + tests/pb/test_varint \ tests/test_handlers SIMPLE_CXX_TESTS= \ @@ -1,7 +1,8 @@ upb - a small, low-level protocol buffer library -For API documentation, see the header files. +BUILDING +======== To build (the core library is ANSI C99 and has no dependencies): $ make @@ -22,100 +23,44 @@ Issue tracking is on Google Code: A manual is forthcoming, for now see wiki docs at: https://github.com/haberman/upb/wiki +API +=== + +The public C/C++ API is defined by all of the .h files in upb/ except .int.h +files (which are internal-only). + +The .h files define both C and C++ APIs. Both languages have 100% complete and +first-class APIs. The C++ API is a wrapper around the C API, but all of the +wrapping is done in inline methods in .h files, so there is no overhead to this. + +For a more detailed description of the scheme we use to provide both C and C++ +APIs, see: https://github.com/haberman/upb/wiki/CAndCPlusPlusAPI + +All of the code that is under upb/ but *not* under upb/bindings/ forms the +namespace of upb's cross-language public API. For example, the code in +upb/descriptor would be exposed as follows: + + * in C/C++: + #include "upb/descriptor/X.h" + + * in Lua: + require "upb.descriptor" + + * in Python: + import upb.descriptor + + * etc. + +STABILITY / STATUS +================== + API and ABI are both subject to change! Please do not distribute as a shared library for this reason (for now at least). -TODO -==== - -The issue tracker contains small-to-medium tasks that need doing; but here are -the major things that are broken or not yet implemented yet: - -- serialization isn't written yet (only deserialization) - - -C/C++ API -========= - -upb's main interfaces are defined in .h files (like upb/def.h). These header -files are coded in such a way that they are not only compatible with C and C++ -but provide idiomatic interfaces to both (functions for C, classes for C++). - -Here is the general strategy/pattern for this. I'll explain it piece by piece. - -// This defines a type called upb::Foo in C++ or upb_foo in C. In both cases -// there is a typedef for upb_foo, which is important since this is how the -// C functions are defined (which are exposed to both C and C++). - -#ifdef __cplusplus -namespace upb { class Foo; } -typedef upb::Foo upb_foo; -extern "C" { -#else -struct upb_foo; -typedef struct upb_foo upb_foo; -#endif - -// Here is the actual definition of the class/struct. In C++ we get a class -// called upb::Foo and in C we get a struct called "struct upb_foo", but both -// have the same members and the C++ version is "standard-layout" according -// to C++11. This means that the two should be compatible. -// -// In addition to being completely accessible from C, it also provides C++ -// niceities like methods (instead of bare functions). We also get -// encapsulation in C++, even though this is impossible to provide in C. We -// provide all method documentation in the C++ class, since the class/method -// syntax is nicer to read than the bare functions of C. - -#ifdef __cplusplus - -class upb::Foo { - public: - // Method documentation for DoBar(). - void DoBar(int32_t x); - - // Method documentation for IsSpicy(). - bool IsSpicy(); - - private: - -#else -struct upb_foo { -#endif - int32_t private_member; -}; - -// Next follows the C API, which is how the functionality is actually -// implemented. We omit documentation here because everything was documented -// in the C++ class, and it's easy to match the functions 1:1 to the C++ -// methods. -void upb_foo_dobar(upb_foo *f, int32_t x); -bool upb_foo_isspicy(upb_foo *f); - -// Finally we include inline definitions of the C++ methods, which are nothing -// but this wrappers around the C functions. Since these are inline, the C++ -// API imposes no overhead. - -#ifdef __cplusplus -} // extern "C" - -namespace upb { -inline void Foo::DoBar(int32_t x) { upb_foo_dobar(this, x); } -inline bool Foo::IsSpicy() { return upb_foo_isspicy(this); } -} -#endif - -This scheme works pretty nicely. It adds a bit of noise to the header file, but -gives nice, zero-overhead APIs to both C and C++ without having to duplicate -the API documentation. - -The biggest bummer is that there isn't any good way to use C++ inheritance -even for types which are trying to express inheritance in C. C++ just doesn't -give any guarantees about how it will arrange data members in base classes, -so we can't use C++ inheritance while interoperating with C layouts. The -biggest effect of this is that we can't get C++'s nice implicit upcasts; all -upcasts have to be explicit, which is a pain. +Parsing is becoming stable, but serialization is in very early stages. +The Python bindings are completely broken and Lua only supports schemas for the +moment. CONTACT ======= diff --git a/benchmarks/parsetoproto2.upb.cc b/benchmarks/parsetoproto2.upb.cc index 699b521..20b6381 100644 --- a/benchmarks/parsetoproto2.upb.cc +++ b/benchmarks/parsetoproto2.upb.cc @@ -8,7 +8,7 @@ #include "upb/def.h" #include "upb/pb/decoder.h" #include "upb/pb/glue.h" -#include "upb/google/bridge.h" +#include "upb/bindings/google/bridge.h" #include MESSAGE_HFILE const char *str; diff --git a/bindings/lua/LICENSE b/tests/bindings/lua/LICENSE index fb720fe..fb720fe 100644 --- a/bindings/lua/LICENSE +++ b/tests/bindings/lua/LICENSE diff --git a/bindings/lua/lunit/console.lua b/tests/bindings/lua/lunit/console.lua index 0ff22a4..0ff22a4 100644 --- a/bindings/lua/lunit/console.lua +++ b/tests/bindings/lua/lunit/console.lua diff --git a/bindings/lua/lunit/lunit.lua b/tests/bindings/lua/lunit/lunit.lua index 80f43c1..80f43c1 100644 --- a/bindings/lua/lunit/lunit.lua +++ b/tests/bindings/lua/lunit/lunit.lua diff --git a/bindings/lua/test.lua b/tests/bindings/lua/test.lua index b19da53..99f58f2 100644 --- a/bindings/lua/test.lua +++ b/tests/bindings/lua/test.lua @@ -214,6 +214,42 @@ function test_symtab() assert_equal(msgdef3:field("field5"):subdef(), msgdef2) end +function test_symtab_add_extension() + -- Adding an extension at the same time as the extendee. + local symtab = upb.SymbolTable{ + upb.MessageDef{full_name = "M1"}, + upb.FieldDef{name = "extension1", is_extension = true, number = 1, + type = upb.TYPE_INT32, containing_type_name = "M1"} + } + + local m1 = symtab:lookup("M1") + assert_not_nil(m1) + assert_equal(1, #m1) + + local f1 = m1:field("extension1") + assert_not_nil(f1) + assert_true(f1:is_extension()) + assert_true(f1:is_frozen()) + assert_equal(1, f1:number()) + + -- Adding an extension to an existing extendee. + symtab:add{ + upb.FieldDef{name = "extension2", is_extension = true, number = 2, + type = upb.TYPE_INT32, containing_type_name = "M1"} + } + + local m1_2 = symtab:lookup("M1") + assert_not_nil(m1_2) + assert_true(m1 ~= m1_2) + assert_equal(2, #m1_2) + + local f2 = m1_2:field("extension2") + assert_not_nil(f2) + assert_true(f2:is_extension()) + assert_true(f2:is_frozen()) + assert_equal(2, f2:number()) +end + -- Lua 5.1 and 5.2 have slightly different semantics for how a finalizer -- can be defined in Lua. if _VERSION >= 'Lua 5.2' then @@ -260,4 +296,8 @@ function test_finalizer() collectgarbage() end -lunit.main() +local stats = lunit.main() + +if stats.failed > 0 or stats.errors > 0 then + error("One or more errors in test suite") +end diff --git a/tests/test_decoder.cc b/tests/pb/test_decoder.cc index f1ee510..eb95580 100644 --- a/tests/test_decoder.cc +++ b/tests/pb/test_decoder.cc @@ -35,12 +35,13 @@ #include <stdint.h> #include <stdlib.h> #include <string.h> + +#include "tests/upb_test.h" +#include "third_party/upb/tests/pb/test_decoder_schema.upb.h" #include "upb/handlers.h" #include "upb/pb/decoder.h" #include "upb/pb/varint.int.h" -#include "upb_test.h" #include "upb/upb.h" -#include "third_party/upb/tests/test_decoder_schema.upb.h" #undef PRINT_FAILURE #define PRINT_FAILURE(expr) \ @@ -59,6 +60,7 @@ double completed; double total; double *count; bool count_only; +upb::BufferHandle global_handle; // Copied from decoder.c, since this is not a public interface. typedef struct { @@ -235,9 +237,10 @@ int* startstr(int* depth, const uint32_t* num, size_t size_hint) { } size_t value_string(int* depth, const uint32_t* num, const char* buf, - size_t n) { + size_t n, const upb::BufferHandle* handle) { UPB_UNUSED(num); output.append(buf, n); + ASSERT(handle == &global_handle); return n; } @@ -407,7 +410,7 @@ bool parse(upb::BytesSink* s, void* subc, const char* buf, size_t start, start = UPB_MAX(start, *ofs); if (start <= end) { size_t len = end - start; - size_t parsed = s->PutBuffer(subc, buf + start, len); + size_t parsed = s->PutBuffer(subc, buf + start, len, &global_handle); if (status->ok() != (parsed >= len)) { fprintf(stderr, "Status: %s, parsed=%zu, len=%zu\n", status->error_message(), parsed, len); diff --git a/tests/test_decoder_schema.proto b/tests/pb/test_decoder_schema.proto index 50bfca9..50bfca9 100644 --- a/tests/test_decoder_schema.proto +++ b/tests/pb/test_decoder_schema.proto diff --git a/tests/test_varint.c b/tests/pb/test_varint.c index fc7eb40..84ff831 100644 --- a/tests/test_varint.c +++ b/tests/pb/test_varint.c @@ -6,7 +6,7 @@ #include <stdio.h> #include "upb/pb/varint.int.h" -#include "upb_test.h" +#include "tests/upb_test.h" // Test that we can round-trip from int->varint->int. static void test_varint_for_num(upb_decoderet (*decoder)(const char*), diff --git a/tests/test_cpp.cc b/tests/test_cpp.cc index 8d06135..c4313e1 100644 --- a/tests/test_cpp.cc +++ b/tests/test_cpp.cc @@ -12,7 +12,10 @@ #include <iostream> #include <set> + +#ifdef UPB_CXX11 #include <type_traits> +#endif #include "upb/def.h" #include "upb/descriptor/reader.h" @@ -231,9 +234,10 @@ class StringBufTesterBase { upb::Sink sub; sink->StartMessage(); sink->StartString(start, 0, &sub); - sub.PutStringBuffer(str, NULL, 5); + size_t ret = sub.PutStringBuffer(str, &buf_, 5, &handle_); ASSERT(seen_); ASSERT(len_ == 5); + ASSERT(ret == 5); ASSERT(handler_data_val_ == kExpectedHandlerData); } @@ -241,115 +245,139 @@ class StringBufTesterBase { bool seen_; int handler_data_val_; size_t len_; + char buf_; + upb::BufferHandle handle_; }; -// Test all 8 combinations of: -// (handler data?) x (function/method) x (returns {void, size_t}) +// Test 8 combinations of: +// (handler data?) x (buffer handle?) x (function/method) +// +// Then we add one test each for this variation: to prevent combinatorial +// explosion of these tests we don't test the full 16 combinations, but +// rely on our knowledge that the implementation processes the return wrapping +// in a second separate and independent stage: +// +// (function/method) -class StringBufTesterVoidFunctionNoHandlerData : public StringBufTesterBase { +class StringBufTesterVoidMethodNoHandlerDataNoHandle + : public StringBufTesterBase { public: - typedef StringBufTesterVoidFunctionNoHandlerData ME; + typedef StringBufTesterVoidMethodNoHandlerDataNoHandle ME; void Register(upb::Handlers* h, const upb::FieldDef* f) { UPB_UNUSED(f); - ASSERT(h->SetStringHandler(f, UpbMakeHandler(&Handler))); + ASSERT(h->SetStringHandler(f, UpbMakeHandler(&ME::Handler))); handler_data_val_ = kExpectedHandlerData; } private: - static void Handler(ME* t, const char *buf, size_t len) { - t->seen_ = true; - t->len_ = len; + void Handler(const char *buf, size_t len) { + ASSERT(buf == &buf_); + seen_ = true; + len_ = len; } }; -class StringBufTesterSizeTFunctionNoHandlerData : public StringBufTesterBase { +class StringBufTesterVoidMethodNoHandlerDataWithHandle + : public StringBufTesterBase { public: - typedef StringBufTesterSizeTFunctionNoHandlerData ME; + typedef StringBufTesterVoidMethodNoHandlerDataWithHandle ME; void Register(upb::Handlers* h, const upb::FieldDef* f) { UPB_UNUSED(f); - ASSERT(h->SetStringHandler(f, UpbMakeHandler(&Handler))); + ASSERT(h->SetStringHandler(f, UpbMakeHandler(&ME::Handler))); handler_data_val_ = kExpectedHandlerData; } private: - static size_t Handler(ME* t, const char *buf, size_t len) { - t->seen_ = true; - t->len_ = len; - return len; + void Handler(const char *buf, size_t len, const upb::BufferHandle* handle) { + ASSERT(buf == &buf_); + ASSERT(handle == &handle_); + seen_ = true; + len_ = len; } }; -class StringBufTesterVoidMethodNoHandlerData : public StringBufTesterBase { +class StringBufTesterVoidMethodWithHandlerDataNoHandle + : public StringBufTesterBase { public: - typedef StringBufTesterVoidMethodNoHandlerData ME; + typedef StringBufTesterVoidMethodWithHandlerDataNoHandle ME; void Register(upb::Handlers* h, const upb::FieldDef* f) { UPB_UNUSED(f); - ASSERT(h->SetStringHandler(f, UpbMakeHandler(&ME::Handler))); - handler_data_val_ = kExpectedHandlerData; + ASSERT(h->SetStringHandler( + f, UpbBind(&ME::Handler, new int(kExpectedHandlerData)))); } private: - void Handler(const char *buf, size_t len) { + void Handler(const int* hd, const char *buf, size_t len) { + ASSERT(buf == &buf_); + handler_data_val_ = *hd; seen_ = true; len_ = len; } }; -class StringBufTesterSizeTMethodNoHandlerData : public StringBufTesterBase { +class StringBufTesterVoidMethodWithHandlerDataWithHandle + : public StringBufTesterBase { public: - typedef StringBufTesterSizeTMethodNoHandlerData ME; + typedef StringBufTesterVoidMethodWithHandlerDataWithHandle ME; void Register(upb::Handlers* h, const upb::FieldDef* f) { UPB_UNUSED(f); - ASSERT(h->SetStringHandler(f, UpbMakeHandler(&ME::Handler))); - handler_data_val_ = kExpectedHandlerData; + ASSERT(h->SetStringHandler( + f, UpbBind(&ME::Handler, new int(kExpectedHandlerData)))); } private: - size_t Handler(const char *buf, size_t len) { + void Handler(const int* hd, const char* buf, size_t len, + const upb::BufferHandle* handle) { + ASSERT(buf == &buf_); + ASSERT(handle == &handle_); + handler_data_val_ = *hd; seen_ = true; len_ = len; - return len; } }; -class StringBufTesterVoidFunctionWithHandlerData : public StringBufTesterBase { +class StringBufTesterVoidFunctionNoHandlerDataNoHandle + : public StringBufTesterBase { public: - typedef StringBufTesterVoidFunctionWithHandlerData ME; + typedef StringBufTesterVoidFunctionNoHandlerDataNoHandle ME; void Register(upb::Handlers* h, const upb::FieldDef* f) { UPB_UNUSED(f); - ASSERT(h->SetStringHandler( - f, UpbBind(&Handler, new int(kExpectedHandlerData)))); + ASSERT(h->SetStringHandler(f, UpbMakeHandler(&ME::Handler))); + handler_data_val_ = kExpectedHandlerData; } private: - static void Handler(ME* t, const int* hd, const char *buf, size_t len) { - t->handler_data_val_ = *hd; + static void Handler(ME* t, const char *buf, size_t len) { + ASSERT(buf == &t->buf_); t->seen_ = true; t->len_ = len; } }; -class StringBufTesterSizeTFunctionWithHandlerData : public StringBufTesterBase { +class StringBufTesterVoidFunctionNoHandlerDataWithHandle + : public StringBufTesterBase { public: - typedef StringBufTesterSizeTFunctionWithHandlerData ME; + typedef StringBufTesterVoidFunctionNoHandlerDataWithHandle ME; void Register(upb::Handlers* h, const upb::FieldDef* f) { UPB_UNUSED(f); - ASSERT(h->SetStringHandler( - f, UpbBind(&Handler, new int(kExpectedHandlerData)))); + ASSERT(h->SetStringHandler(f, UpbMakeHandler(&ME::Handler))); + handler_data_val_ = kExpectedHandlerData; } private: - static size_t Handler(ME* t, const int* hd, const char *buf, size_t len) { - t->handler_data_val_ = *hd; + static void Handler(ME* t, const char* buf, size_t len, + const upb::BufferHandle* handle) { + ASSERT(buf == &t->buf_); + ASSERT(handle == &t->handle_); t->seen_ = true; t->len_ = len; - return len; } }; -class StringBufTesterVoidMethodWithHandlerData : public StringBufTesterBase { +class StringBufTesterVoidFunctionWithHandlerDataNoHandle + : public StringBufTesterBase { public: - typedef StringBufTesterVoidMethodWithHandlerData ME; + typedef StringBufTesterVoidFunctionWithHandlerDataNoHandle ME; void Register(upb::Handlers* h, const upb::FieldDef* f) { UPB_UNUSED(f); ASSERT(h->SetStringHandler( @@ -357,16 +385,18 @@ class StringBufTesterVoidMethodWithHandlerData : public StringBufTesterBase { } private: - void Handler(const int* hd, const char *buf, size_t len) { - handler_data_val_ = *hd; - seen_ = true; - len_ = len; + static void Handler(ME* t, const int* hd, const char *buf, size_t len) { + ASSERT(buf == &t->buf_); + t->handler_data_val_ = *hd; + t->seen_ = true; + t->len_ = len; } }; -class StringBufTesterSizeTMethodWithHandlerData : public StringBufTesterBase { +class StringBufTesterVoidFunctionWithHandlerDataWithHandle + : public StringBufTesterBase { public: - typedef StringBufTesterSizeTMethodWithHandlerData ME; + typedef StringBufTesterVoidFunctionWithHandlerDataWithHandle ME; void Register(upb::Handlers* h, const upb::FieldDef* f) { UPB_UNUSED(f); ASSERT(h->SetStringHandler( @@ -374,8 +404,29 @@ class StringBufTesterSizeTMethodWithHandlerData : public StringBufTesterBase { } private: - size_t Handler(const int* hd, const char *buf, size_t len) { - handler_data_val_ = *hd; + static void Handler(ME* t, const int* hd, const char* buf, size_t len, + const upb::BufferHandle* handle) { + ASSERT(buf == &t->buf_); + ASSERT(handle == &t->handle_); + t->handler_data_val_ = *hd; + t->seen_ = true; + t->len_ = len; + } +}; + +class StringBufTesterSizeTMethodNoHandlerDataNoHandle + : public StringBufTesterBase { + public: + typedef StringBufTesterSizeTMethodNoHandlerDataNoHandle ME; + void Register(upb::Handlers* h, const upb::FieldDef* f) { + UPB_UNUSED(f); + ASSERT(h->SetStringHandler(f, UpbMakeHandler(&ME::Handler))); + handler_data_val_ = kExpectedHandlerData; + } + + private: + size_t Handler(const char *buf, size_t len) { + ASSERT(buf == &buf_); seen_ = true; len_ = len; return len; @@ -712,6 +763,284 @@ void TestHandler() { tester.CallAndVerify(&sink, f.get()); } +class T1 {}; +class T2 {}; + +template <class C> +void DoNothingHandler(C* closure) { + UPB_UNUSED(closure); +} + +template <class C> +void DoNothingInt32Handler(C* closure, int32_t val) { + UPB_UNUSED(closure); + UPB_UNUSED(val); +} + +template <class R, class C> +R* DoNothingStartHandler(C* closure) { + UPB_UNUSED(closure); + return NULL; +} + +template <class R, class C> +R* DoNothingStartStringHandler(C* closure, size_t size_len) { + UPB_UNUSED(closure); + UPB_UNUSED(size_len); + return NULL; +} + +template <class C> +void DoNothingStringBufHandler(C* closure, const char *buf, size_t len) { + UPB_UNUSED(closure); + UPB_UNUSED(buf); + UPB_UNUSED(len); +} + +template <class C> +void DoNothingEndMessageHandler(C* closure, upb::Status *status) { + UPB_UNUSED(closure); + UPB_UNUSED(status); +} + +void TestMismatchedTypes() { + // First create a schema for our test. + upb::reffed_ptr<upb::MessageDef> md(upb::MessageDef::New()); + + upb::reffed_ptr<upb::FieldDef> f(upb::FieldDef::New()); + f->set_type(UPB_TYPE_INT32); + ASSERT(f->set_name("i32", NULL)); + ASSERT(f->set_number(1, NULL)); + ASSERT(md->AddField(f, NULL)); + const upb::FieldDef* i32 = f.get(); + + f = upb::FieldDef::New(); + f->set_type(UPB_TYPE_INT32); + ASSERT(f->set_name("r_i32", NULL)); + ASSERT(f->set_number(2, NULL)); + f->set_label(UPB_LABEL_REPEATED); + ASSERT(md->AddField(f, NULL)); + const upb::FieldDef* r_i32 = f.get(); + + f = upb::FieldDef::New(); + f->set_type(UPB_TYPE_STRING); + ASSERT(f->set_name("str", NULL)); + ASSERT(f->set_number(3, NULL)); + ASSERT(md->AddField(f, NULL)); + const upb::FieldDef* str = f.get(); + + f = upb::FieldDef::New(); + f->set_type(UPB_TYPE_STRING); + ASSERT(f->set_name("r_str", NULL)); + ASSERT(f->set_number(4, NULL)); + f->set_label(UPB_LABEL_REPEATED); + ASSERT(md->AddField(f, NULL)); + const upb::FieldDef* r_str = f.get(); + + f = upb::FieldDef::New(); + f->set_type(UPB_TYPE_MESSAGE); + ASSERT(f->set_name("msg", NULL)); + ASSERT(f->set_number(5, NULL)); + ASSERT(f->set_message_subdef(md.get(), NULL)); + ASSERT(md->AddField(f, NULL)); + const upb::FieldDef* msg = f.get(); + + f = upb::FieldDef::New(); + f->set_type(UPB_TYPE_MESSAGE); + ASSERT(f->set_name("r_msg", NULL)); + ASSERT(f->set_number(6, NULL)); + ASSERT(f->set_message_subdef(md.get(), NULL)); + f->set_label(UPB_LABEL_REPEATED); + ASSERT(md->AddField(f, NULL)); + const upb::FieldDef* r_msg = f.get(); + + ASSERT(md->Freeze(NULL)); + + // Now test the type-checking in handler registration. + upb::reffed_ptr<upb::Handlers> h(upb::Handlers::New(md.get())); + + // Establish T1 as the top-level closure type. + ASSERT(h->SetInt32Handler(i32, UpbMakeHandler(DoNothingInt32Handler<T1>))); + + // Now any other attempt to set another handler with T2 as the top-level + // closure should fail. But setting these same handlers with T1 as the + // top-level closure will succeed. + ASSERT(!h->SetStartMessageHandler(UpbMakeHandler(DoNothingHandler<T2>))); + ASSERT(h->SetStartMessageHandler(UpbMakeHandler(DoNothingHandler<T1>))); + + ASSERT( + !h->SetEndMessageHandler(UpbMakeHandler(DoNothingEndMessageHandler<T2>))); + ASSERT( + h->SetEndMessageHandler(UpbMakeHandler(DoNothingEndMessageHandler<T1>))); + + ASSERT(!h->SetStartStringHandler( + str, UpbMakeHandler((DoNothingStartStringHandler<T1, T2>)))); + ASSERT(h->SetStartStringHandler( + str, UpbMakeHandler((DoNothingStartStringHandler<T1, T1>)))); + + ASSERT(!h->SetEndStringHandler(str, UpbMakeHandler((DoNothingHandler<T2>)))); + ASSERT(h->SetEndStringHandler(str, UpbMakeHandler((DoNothingHandler<T1>)))); + + ASSERT(!h->SetStartSubMessageHandler( + msg, UpbMakeHandler((DoNothingStartHandler<T1, T2>)))); + ASSERT(h->SetStartSubMessageHandler( + msg, UpbMakeHandler((DoNothingStartHandler<T1, T1>)))); + + ASSERT( + !h->SetEndSubMessageHandler(msg, UpbMakeHandler((DoNothingHandler<T2>)))); + ASSERT( + h->SetEndSubMessageHandler(msg, UpbMakeHandler((DoNothingHandler<T1>)))); + + ASSERT(!h->SetStartSequenceHandler( + r_i32, UpbMakeHandler((DoNothingStartHandler<T1, T2>)))); + ASSERT(h->SetStartSequenceHandler( + r_i32, UpbMakeHandler((DoNothingStartHandler<T1, T1>)))); + + ASSERT(!h->SetEndSequenceHandler( + r_i32, UpbMakeHandler((DoNothingHandler<T2>)))); + ASSERT(h->SetEndSequenceHandler( + r_i32, UpbMakeHandler((DoNothingHandler<T1>)))); + + ASSERT(!h->SetStartSequenceHandler( + r_msg, UpbMakeHandler((DoNothingStartHandler<T1, T2>)))); + ASSERT(h->SetStartSequenceHandler( + r_msg, UpbMakeHandler((DoNothingStartHandler<T1, T1>)))); + + ASSERT(!h->SetEndSequenceHandler( + r_msg, UpbMakeHandler((DoNothingHandler<T2>)))); + ASSERT(h->SetEndSequenceHandler( + r_msg, UpbMakeHandler((DoNothingHandler<T1>)))); + + ASSERT(!h->SetStartSequenceHandler( + r_str, UpbMakeHandler((DoNothingStartHandler<T1, T2>)))); + ASSERT(h->SetStartSequenceHandler( + r_str, UpbMakeHandler((DoNothingStartHandler<T1, T1>)))); + + ASSERT(!h->SetEndSequenceHandler( + r_str, UpbMakeHandler((DoNothingHandler<T2>)))); + ASSERT(h->SetEndSequenceHandler( + r_str, UpbMakeHandler((DoNothingHandler<T1>)))); + + // By setting T1 as the return type for the Start* handlers we have + // established T1 as the type of the sequence and string frames. + // Setting callbacks that use T2 should fail, but T1 should succeed. + ASSERT( + !h->SetStringHandler(str, UpbMakeHandler(DoNothingStringBufHandler<T2>))); + ASSERT( + h->SetStringHandler(str, UpbMakeHandler(DoNothingStringBufHandler<T1>))); + + ASSERT(!h->SetInt32Handler(r_i32, UpbMakeHandler(DoNothingInt32Handler<T2>))); + ASSERT(h->SetInt32Handler(r_i32, UpbMakeHandler(DoNothingInt32Handler<T1>))); + + ASSERT(!h->SetStartSubMessageHandler( + r_msg, UpbMakeHandler((DoNothingStartHandler<T1, T2>)))); + ASSERT(h->SetStartSubMessageHandler( + r_msg, UpbMakeHandler((DoNothingStartHandler<T1, T1>)))); + + ASSERT(!h->SetEndSubMessageHandler(r_msg, + UpbMakeHandler((DoNothingHandler<T2>)))); + ASSERT(h->SetEndSubMessageHandler(r_msg, + UpbMakeHandler((DoNothingHandler<T1>)))); + + ASSERT(!h->SetStartStringHandler( + r_str, UpbMakeHandler((DoNothingStartStringHandler<T1, T2>)))); + ASSERT(h->SetStartStringHandler( + r_str, UpbMakeHandler((DoNothingStartStringHandler<T1, T1>)))); + + ASSERT( + !h->SetEndStringHandler(r_str, UpbMakeHandler((DoNothingHandler<T2>)))); + ASSERT(h->SetEndStringHandler(r_str, UpbMakeHandler((DoNothingHandler<T1>)))); + + ASSERT(!h->SetStringHandler(r_str, + UpbMakeHandler(DoNothingStringBufHandler<T2>))); + ASSERT(h->SetStringHandler(r_str, + UpbMakeHandler(DoNothingStringBufHandler<T1>))); + + h->ClearError(); + ASSERT(h->Freeze(NULL)); + + // For our second test we do the same in reverse. We directly set the type of + // the frame and then observe failures at registering a Start* handler that + // returns a different type. + h = upb::Handlers::New(md.get()); + + // First establish the type of a sequence frame directly. + ASSERT(h->SetInt32Handler(r_i32, UpbMakeHandler(DoNothingInt32Handler<T1>))); + + // Now setting a StartSequence callback that returns a different type should + // fail. + ASSERT(!h->SetStartSequenceHandler( + r_i32, UpbMakeHandler((DoNothingStartHandler<T2, T1>)))); + ASSERT(h->SetStartSequenceHandler( + r_i32, UpbMakeHandler((DoNothingStartHandler<T1, T1>)))); + + // Establish a string frame directly. + ASSERT(h->SetStringHandler(r_str, + UpbMakeHandler(DoNothingStringBufHandler<T1>))); + + // Fail setting a StartString callback that returns a different type. + ASSERT(!h->SetStartStringHandler( + r_str, UpbMakeHandler((DoNothingStartStringHandler<T2, T1>)))); + ASSERT(h->SetStartStringHandler( + r_str, UpbMakeHandler((DoNothingStartStringHandler<T1, T1>)))); + + // The previous established T1 as the frame for the r_str sequence. + ASSERT(!h->SetStartSequenceHandler( + r_str, UpbMakeHandler((DoNothingStartHandler<T2, T1>)))); + ASSERT(h->SetStartSequenceHandler( + r_str, UpbMakeHandler((DoNothingStartHandler<T1, T1>)))); + + // Now test for this error that is not caught until freeze time: + // Change-of-closure-type implies that a StartSequence or StartString handler + // should exist to return the closure type of the inner frame but no + // StartSequence/StartString handler is registered. + + h = upb::Handlers::New(md.get()); + + // Establish T1 as top-level closure type. + ASSERT(h->SetInt32Handler(i32, UpbMakeHandler(DoNothingInt32Handler<T1>))); + + // Establish T2 as closure type of sequence frame. + ASSERT( + h->SetInt32Handler(r_i32, UpbMakeHandler((DoNothingInt32Handler<T2>)))); + + // Now attempt to freeze; this should fail because a StartSequence handler + // needs to be registered that takes a T1 and returns a T2. + ASSERT(!h->Freeze(NULL)); + + // Now if we register the necessary StartSequence handler, the freezing should + // work. + ASSERT(h->SetStartSequenceHandler( + r_i32, UpbMakeHandler((DoNothingStartHandler<T2, T1>)))); + h->ClearError(); + ASSERT(h->Freeze(NULL)); + + // Test for a broken chain that is two deep. + h = upb::Handlers::New(md.get()); + + // Establish T1 as top-level closure type. + ASSERT(h->SetInt32Handler(i32, UpbMakeHandler(DoNothingInt32Handler<T1>))); + + // Establish T2 as the closure type of the string frame inside a sequence + // frame. + ASSERT(h->SetStringHandler(r_str, + UpbMakeHandler(DoNothingStringBufHandler<T2>))); + + // Now attempt to freeze; this should fail because a StartSequence or + // StartString handler needs to be registered that takes a T1 and returns a + // T2. + ASSERT(!h->Freeze(NULL)); + + // Now if we register a StartSequence handler it succeeds. + ASSERT(h->SetStartSequenceHandler( + r_str, UpbMakeHandler((DoNothingStartHandler<T2, T1>)))); + h->ClearError(); + ASSERT(h->Freeze(NULL)); + + // TODO(haberman): test that closure returned by StartSubMessage does not + // match top-level closure of sub-handlers. +} + extern "C" { int run_tests(int argc, char *argv[]) { @@ -753,14 +1082,17 @@ int run_tests(int argc, char *argv[]) { TestHandler<StartMsgTesterVoidMethodWithHandlerData>(); TestHandler<StartMsgTesterBoolMethodWithHandlerData>(); - TestHandler<StringBufTesterVoidFunctionNoHandlerData>(); - TestHandler<StringBufTesterSizeTFunctionNoHandlerData>(); - TestHandler<StringBufTesterVoidMethodNoHandlerData>(); - TestHandler<StringBufTesterSizeTMethodNoHandlerData>(); - TestHandler<StringBufTesterVoidFunctionWithHandlerData>(); - TestHandler<StringBufTesterSizeTFunctionWithHandlerData>(); - TestHandler<StringBufTesterVoidMethodWithHandlerData>(); - TestHandler<StringBufTesterSizeTMethodWithHandlerData>(); + TestHandler<StringBufTesterVoidMethodNoHandlerDataNoHandle>(); + TestHandler<StringBufTesterVoidMethodNoHandlerDataWithHandle>(); + TestHandler<StringBufTesterVoidMethodWithHandlerDataNoHandle>(); + TestHandler<StringBufTesterVoidMethodWithHandlerDataWithHandle>(); + TestHandler<StringBufTesterVoidFunctionNoHandlerDataNoHandle>(); + TestHandler<StringBufTesterVoidFunctionNoHandlerDataWithHandle>(); + TestHandler<StringBufTesterVoidFunctionWithHandlerDataNoHandle>(); + TestHandler<StringBufTesterVoidFunctionWithHandlerDataWithHandle>(); + TestHandler<StringBufTesterSizeTMethodNoHandlerDataNoHandle>(); + + TestMismatchedTypes(); #ifdef UPB_CXX11 #define ASSERT_STD_LAYOUT(type) \ diff --git a/tests/test_def.c b/tests/test_def.c index fb33871..bf45a73 100644 --- a/tests/test_def.c +++ b/tests/test_def.c @@ -93,10 +93,10 @@ static void test_fielddef_accessors() { ASSERT(!upb_fielddef_isfrozen(f2)); ASSERT(upb_fielddef_setname(f2, "f2", NULL)); - ASSERT(upb_fielddef_setnumber(f2, 1572, NULL)); + ASSERT(upb_fielddef_setnumber(f2, 123456789, NULL)); upb_fielddef_settype(f2, UPB_TYPE_BYTES); upb_fielddef_setlabel(f2, UPB_LABEL_REPEATED); - ASSERT(upb_fielddef_number(f2) == 1572); + ASSERT(upb_fielddef_number(f2) == 123456789); upb_fielddef_unref(f1, &f1); upb_fielddef_unref(f2, &f2); diff --git a/tests/test_vs_proto2.cc b/tests/test_vs_proto2.cc index 07946dd..22683c3 100644 --- a/tests/test_vs_proto2.cc +++ b/tests/test_vs_proto2.cc @@ -19,8 +19,8 @@ #include <stdio.h> #include <stdlib.h> #include "benchmarks/google_messages.pb.h" +#include "upb/bindings/googlepb/bridge.h" #include "upb/def.h" -#include "upb/google/bridge.h" #include "upb/handlers.h" #include "upb/pb/decoder.h" #include "upb/pb/glue.h" @@ -125,7 +125,7 @@ int run_tests(int argc, char *argv[]) MESSAGE_CIDENT msg1; MESSAGE_CIDENT msg2; - upb::reffed_ptr<const upb::Handlers> h(upb::google::NewWriteHandlers(msg1)); + upb::reffed_ptr<const upb::Handlers> h(upb::googlepb::NewWriteHandlers(msg1)); compare_metadata(msg1.GetDescriptor(), h->message_def()); @@ -142,7 +142,7 @@ int run_tests(int argc, char *argv[]) factory->GetPrototype(msg1.descriptor()); google::protobuf::Message* dyn_msg1 = prototype->New(); google::protobuf::Message* dyn_msg2 = prototype->New(); - h = upb::google::NewWriteHandlers(*dyn_msg1); + h = upb::googlepb::NewWriteHandlers(*dyn_msg1); parse_and_compare(dyn_msg1, dyn_msg2, h.get(), str, len, false); parse_and_compare(dyn_msg1, dyn_msg2, h.get(), str, len, true); delete dyn_msg1; diff --git a/tools/dump_cinit.lua b/tools/dump_cinit.lua index c83aa04..e23e907 100644 --- a/tools/dump_cinit.lua +++ b/tools/dump_cinit.lua @@ -359,13 +359,14 @@ local function dump_defs_c(symtab, basename, append) else intfmt = "0" end - -- UPB_FIELDDEF_INIT(label, type, intfmt, tagdelim, name, num, msgdef, - -- subdef, selector_base, index, default_value) - append(' UPB_FIELDDEF_INIT(%s, %s, %s, %s, "%s", %d, %s, %s, %d, %d, ' .. - '{0},' .. -- TODO: support default value + -- UPB_FIELDDEF_INIT(label, type, intfmt, tagdelim, is_extension, name, + -- num, msgdef, subdef, selector_base, index, + -- default_value) + append(' UPB_FIELDDEF_INIT(%s, %s, %s, %s, %s, "%s", %d, %s, %s, %d, ' .. + '%d, {0},' .. -- TODO: support default value '&reftables[%d], &reftables[%d]),\n', const(f, "label"), const(f, "type"), intfmt, - boolstr(f:istagdelim()), f:name(), + boolstr(f:istagdelim()), boolstr(f:is_extension()), f:name(), f:number(), linktab:addr(f:containing_type()), subdef, f:_selector_base(), f:index(), reftable, reftable + 1 diff --git a/tools/test_cinit.lua b/tools/test_cinit.lua index 72d8826..3ed77b5 100644 --- a/tools/test_cinit.lua +++ b/tools/test_cinit.lua @@ -43,7 +43,7 @@ if arg[1] == "generate" then local appendh = dump_cinit.file_appender(f_h) f:write('#include "lua.h"\n') f:write('#define ELEMENTS(array) (sizeof(array)/sizeof(*array))\n') - f:write('#include "bindings/lua/upb.h"\n') + f:write('#include "upb/bindings/lua/upb.h"\n') dump_cinit.dump_defs(symtab, "test", appendh, appendc) f:write([[int luaopen_staticdefs(lua_State *L) { lua_newtable(L); 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/bindings/linux/Makefile b/upb/bindings/linux/Makefile index 1736b61..1736b61 100644 --- a/bindings/linux/Makefile +++ b/upb/bindings/linux/Makefile diff --git a/bindings/linux/assert.h b/upb/bindings/linux/assert.h index 26d8ab6..26d8ab6 100644 --- a/bindings/linux/assert.h +++ b/upb/bindings/linux/assert.h diff --git a/bindings/linux/errno.h b/upb/bindings/linux/errno.h index f45d939..f45d939 100644 --- a/bindings/linux/errno.h +++ b/upb/bindings/linux/errno.h diff --git a/bindings/linux/stdint.h b/upb/bindings/linux/stdint.h index 2524b23..2524b23 100644 --- a/bindings/linux/stdint.h +++ b/upb/bindings/linux/stdint.h diff --git a/bindings/linux/stdio.h b/upb/bindings/linux/stdio.h index 72c1b0d..72c1b0d 100644 --- a/bindings/linux/stdio.h +++ b/upb/bindings/linux/stdio.h diff --git a/bindings/linux/stdlib.h b/upb/bindings/linux/stdlib.h index 8381b13..8381b13 100644 --- a/bindings/linux/stdlib.h +++ b/upb/bindings/linux/stdlib.h diff --git a/bindings/linux/string.h b/upb/bindings/linux/string.h index 30ebf8a..30ebf8a 100644 --- a/bindings/linux/string.h +++ b/upb/bindings/linux/string.h diff --git a/bindings/lua/table.c b/upb/bindings/lua/table.c index 4e6aae2..51ba324 100644 --- a/bindings/lua/table.c +++ b/upb/bindings/lua/table.c @@ -21,8 +21,9 @@ #include <math.h> #include <stdlib.h> #include <string.h> + #include "lauxlib.h" -#include "bindings/lua/upb.h" +#include "upb/bindings/lua/upb.h" #include "upb/def.h" static void lupbtable_setnum(lua_State *L, int tab, const char *key, diff --git a/bindings/lua/upb.c b/upb/bindings/lua/upb.c index 9eb46f3..1e7540a 100644 --- a/bindings/lua/upb.c +++ b/upb/bindings/lua/upb.c @@ -13,7 +13,7 @@ #include <stdlib.h> #include <string.h> #include "lauxlib.h" -#include "bindings/lua/upb.h" +#include "upb/bindings/lua/upb.h" #include "upb/handlers.h" #include "upb/pb/glue.h" @@ -63,6 +63,13 @@ static const char *chkname(lua_State *L, int narg) { 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) { @@ -75,9 +82,7 @@ static uint32_t chkint32(lua_State *L, int narg, const char *name) { // 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) { - if (!lua_isboolean(L, narg)) - luaL_error(L, "Must explicitly pass true or false for boolean fields"); - upb_fielddef_setdefaultbool(f, lua_toboolean(L, narg)); + upb_fielddef_setdefaultbool(f, chkbool(L, narg, "bool default")); } else { // Numeric type. lua_Number num = luaL_checknumber(L, narg); @@ -309,6 +314,11 @@ static void lupb_fielddef_dosetdefault(lua_State *L, upb_fielddef *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)) @@ -339,6 +349,14 @@ static void lupb_fielddef_dosetsubdefname(lua_State *L, upb_fielddef *f, 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)) @@ -355,21 +373,29 @@ static void lupb_fielddef_dosetintfmt(lua_State *L, upb_fielddef *f, int narg) { static void lupb_fielddef_dosettagdelim(lua_State *L, upb_fielddef *f, int narg) { - if (!lua_isboolean(L, narg)) - luaL_argerror(L, narg, "tagdelim value must be boolean"); - int32_t tagdelim = luaL_checknumber(L, narg); - if (!upb_fielddef_settagdelim(f, tagdelim)) - luaL_argerror(L, narg, "invalid field tagdelim"); + 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); @@ -440,9 +466,13 @@ static int lupb_fielddef_new(lua_State *L) { 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, "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 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); } @@ -547,6 +577,12 @@ static int lupb_fielddef_containingtype(lua_State *L) { 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)) @@ -585,6 +621,12 @@ static int lupb_fielddef_intfmt(lua_State *L) { 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)); @@ -602,11 +644,13 @@ 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}, @@ -615,7 +659,9 @@ static const struct luaL_Reg lupb_fielddef_m[] = { {"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}, diff --git a/bindings/lua/upb.h b/upb/bindings/lua/upb.h index e6b4f2f..e6b4f2f 100644 --- a/bindings/lua/upb.h +++ b/upb/bindings/lua/upb.h diff --git a/bindings/python/setup.py b/upb/bindings/python/setup.py index 8abaff8..8abaff8 100644 --- a/bindings/python/setup.py +++ b/upb/bindings/python/setup.py diff --git a/bindings/python/test.py b/upb/bindings/python/test.py index 29a6c45..29a6c45 100644 --- a/bindings/python/test.py +++ b/upb/bindings/python/test.py diff --git a/bindings/python/upb.c b/upb/bindings/python/upb.c index 497074b..497074b 100644 --- a/bindings/python/upb.c +++ b/upb/bindings/python/upb.c diff --git a/bindings/python/upb/__init__.py b/upb/bindings/python/upb/__init__.py index e69de29..e69de29 100644 --- a/bindings/python/upb/__init__.py +++ b/upb/bindings/python/upb/__init__.py diff --git a/upb/bindings/stdc++/string.h b/upb/bindings/stdc++/string.h new file mode 100644 index 0000000..668f3e3 --- /dev/null +++ b/upb/bindings/stdc++/string.h @@ -0,0 +1,60 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// Author: haberman@google.com (Josh Haberman) +// +// upb - a minimalist implementation of protocol buffers. + +#ifndef UPB_STDCPP_H_ +#define UPB_STDCPP_H_ + +namespace upb { + +template <class T> +class FillStringHandler { + public: + static void SetHandler(BytesHandler* handler) { + upb_byteshandler_setstartstr(handler, &FillStringHandler::StartString, + NULL); + upb_byteshandler_setstring(handler, &FillStringHandler::StringBuf, NULL); + } + + private: + // TODO(haberman): add UpbBind/UpbMakeHandler support to BytesHandler so these + // can be prettier callbacks. + static void* StartString(void *c, const void *hd, size_t size) { + T* str = static_cast<T*>(c); + str->clear(); + return c; + } + + static size_t StringBuf(void* c, const void* hd, const char* buf, size_t n, + const BufferHandle* h) { + T* str = static_cast<T*>(c); + try { + str->append(buf, n); + return n; + } catch (const std::exception&) { + return 0; + } + } +}; + +class StringSink { + public: + template <class T> + explicit StringSink(T* target) { + // TODO(haberman): we need to avoid rebuilding a new handler every time, + // but with class globals disallowed for google3 C++ this is tricky. + FillStringHandler<T>::SetHandler(&handler_); + input_.Reset(&handler_, target); + } + + BytesSink* input() { return &input_; } + + private: + BytesHandler handler_; + BytesSink input_; +}; + +} // namespace upb + +#endif // UPB_STDCPP_H_ diff --git a/upb/stdc/error.c b/upb/bindings/stdc/error.c index 85c9ca6..85c9ca6 100644 --- a/upb/stdc/error.c +++ b/upb/bindings/stdc/error.c diff --git a/upb/stdc/error.h b/upb/bindings/stdc/error.h index 9802097..9802097 100644 --- a/upb/stdc/error.h +++ b/upb/bindings/stdc/error.h diff --git a/upb/stdc/io.c b/upb/bindings/stdc/io.c index 5d36aa5..5d36aa5 100644 --- a/upb/stdc/io.c +++ b/upb/bindings/stdc/io.c diff --git a/upb/stdc/io.h b/upb/bindings/stdc/io.h index fd19bef..fd19bef 100644 --- a/upb/stdc/io.h +++ b/upb/bindings/stdc/io.h @@ -156,17 +156,17 @@ static bool upb_validate_field(upb_fielddef *f, upb_status *s) { if (subdef == NULL) { upb_status_seterrf(s, "field %s.%s is missing required subdef", - msgdef_name(f->msgdef), upb_fielddef_name(f)); + msgdef_name(f->msg.def), upb_fielddef_name(f)); return false; } else if (!upb_def_isfrozen(subdef) && !subdef->came_from_user) { upb_status_seterrf(s, "subdef of field %s.%s is not frozen or being frozen", - msgdef_name(f->msgdef), upb_fielddef_name(f)); + msgdef_name(f->msg.def), upb_fielddef_name(f)); return false; } else if (upb_fielddef_default_is_symbolic(f)) { upb_status_seterrf(s, "enum field %s.%s has not been resolved", - msgdef_name(f->msgdef), upb_fielddef_name(f)); + msgdef_name(f->msg.def), upb_fielddef_name(f)); return false; } } @@ -202,7 +202,7 @@ static bool assign_msg_indices(upb_msgdef *m, upb_status *s) { m->submsg_field_count = 0; for(i = 0, upb_msg_begin(&j, m); !upb_msg_done(&j); upb_msg_next(&j), i++) { upb_fielddef *f = upb_msg_iter_field(&j); - assert(f->msgdef == m); + assert(f->msg.def == m); if (!upb_validate_field(f, s)) { free(fields); return false; @@ -428,11 +428,11 @@ static void upb_fielddef_uninit_default(upb_fielddef *f) { static void visitfield(const upb_refcounted *r, upb_refcounted_visit *visit, void *closure) { const upb_fielddef *f = (const upb_fielddef*)r; - if (f->msgdef) { - visit(r, UPB_UPCAST2(f->msgdef), closure); + if (upb_fielddef_containingtype(f)) { + visit(r, UPB_UPCAST2(upb_fielddef_containingtype(f)), closure); } - if (!f->subdef_is_symbolic && f->sub.def) { - visit(r, UPB_UPCAST(f->sub.def), closure); + if (upb_fielddef_subdef(f)) { + visit(r, UPB_UPCAST(upb_fielddef_subdef(f)), closure); } } @@ -453,14 +453,16 @@ upb_fielddef *upb_fielddef_new(const void *owner) { free(f); return NULL; } - f->msgdef = NULL; + f->msg.def = NULL; f->sub.def = NULL; f->subdef_is_symbolic = false; + f->msg_is_symbolic = false; f->label_ = UPB_LABEL_OPTIONAL; f->type_ = UPB_TYPE_INT32; f->number_ = 0; f->type_is_set_ = false; f->tagdelim = false; + f->is_extension_ = false; // For the moment we default this to UPB_INTFMT_VARIABLE, since it will work // with all integer types and is in some since more "default" since the most @@ -559,16 +561,43 @@ uint32_t upb_fielddef_number(const upb_fielddef *f) { return f->number_; } +bool upb_fielddef_isextension(const upb_fielddef *f) { + return f->is_extension_; +} + const char *upb_fielddef_name(const upb_fielddef *f) { return upb_def_fullname(UPB_UPCAST(f)); } const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f) { - return f->msgdef; + return f->msg_is_symbolic ? NULL : f->msg.def; } upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f) { - return (upb_msgdef*)f->msgdef; + return (upb_msgdef*)upb_fielddef_containingtype(f); +} + +const char *upb_fielddef_containingtypename(upb_fielddef *f) { + return f->msg_is_symbolic ? f->msg.name : NULL; +} + +static void release_containingtype(upb_fielddef *f) { + if (f->msg_is_symbolic) free(f->msg.name); +} + +bool upb_fielddef_setcontainingtypename(upb_fielddef *f, const char *name, + upb_status *s) { + assert(!upb_fielddef_isfrozen(f)); + if (upb_fielddef_containingtype(f)) { + upb_status_seterrmsg(s, "field has already been added to a message."); + return false; + } + // TODO: validate name (upb_isident() doesn't quite work atm because this name + // may have a leading "."). + release_containingtype(f); + f->msg.name = upb_strdup(name); + f->msg_is_symbolic = true; + return true; } bool upb_fielddef_setname(upb_fielddef *f, const char *name, upb_status *s) { @@ -650,12 +679,7 @@ static void upb_fielddef_init_default(upb_fielddef *f) { } const upb_def *upb_fielddef_subdef(const upb_fielddef *f) { - if (upb_fielddef_hassubdef(f) && upb_fielddef_isfrozen(f)) { - assert(f->sub.def); - return f->sub.def; - } else { - return f->subdef_is_symbolic ? NULL : f->sub.def; - } + return f->subdef_is_symbolic ? NULL : f->sub.def; } const upb_msgdef *upb_fielddef_msgsubdef(const upb_fielddef *f) { @@ -678,7 +702,7 @@ const char *upb_fielddef_subdefname(const upb_fielddef *f) { } bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number, upb_status *s) { - if (f->msgdef) { + if (upb_fielddef_containingtype(f)) { upb_status_seterrmsg( s, "cannot change field number after adding to a message"); return false; @@ -800,6 +824,12 @@ upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f) { return 0; } +bool upb_fielddef_setisextension(upb_fielddef *f, bool is_extension) { + assert(!upb_fielddef_isfrozen(f)); + f->is_extension_ = is_extension; + return true; +} + void upb_fielddef_setlabel(upb_fielddef *f, upb_label_t label) { assert(!upb_fielddef_isfrozen(f)); assert(upb_fielddef_checklabel(label)); @@ -980,6 +1010,8 @@ bool upb_fielddef_setsubdefname(upb_fielddef *f, const char *name, upb_status_seterrmsg(s, "field type does not accept a subdef"); return false; } + // TODO: validate name (upb_isident() doesn't quite work atm because this name + // may have a leading "."). release_subdef(f); f->sub.name = upb_strdup(name); f->subdef_is_symbolic = true; @@ -1104,12 +1136,23 @@ bool upb_msgdef_setfullname(upb_msgdef *m, const char *fullname, bool upb_msgdef_addfields(upb_msgdef *m, upb_fielddef *const *fields, int n, const void *ref_donor, upb_status *s) { + // TODO: extensions need to have a separate namespace, because proto2 allows a + // top-level extension (ie. one not in any package) to have the same name as a + // field from the message. + // + // This also implies that there needs to be a separate lookup-by-name method + // for extensions. It seems desirable for iteration to return both extensions + // and non-extensions though. + // + // We also need to validate that the field number is in an extension range iff + // it is an extension. + // Check constraints for all fields before performing any action. for (int i = 0; i < n; i++) { upb_fielddef *f = fields[i]; // TODO(haberman): handle the case where two fields of the input duplicate // name or number. - if (f->msgdef != NULL) { + if (upb_fielddef_containingtype(f) != NULL) { upb_status_seterrmsg(s, "fielddef already belongs to a message"); return false; } else if (upb_fielddef_name(f) == NULL || upb_fielddef_number(f) == 0) { @@ -1125,7 +1168,9 @@ bool upb_msgdef_addfields(upb_msgdef *m, upb_fielddef *const *fields, int n, // Constraint checks ok, perform the action. for (int i = 0; i < n; i++) { upb_fielddef *f = fields[i]; - f->msgdef = m; + release_containingtype(f); + f->msg.def = m; + f->msg_is_symbolic = false; upb_inttable_insert(&m->itof, upb_fielddef_number(f), upb_value_ptr(f)); upb_strtable_insert(&m->ntof, upb_fielddef_name(f), upb_value_ptr(f)); upb_ref2(f, m); @@ -272,6 +272,7 @@ class upb::FieldDef /* : public upb::Def */ { Label label() const; // Defaults to UPB_LABEL_OPTIONAL. const char* name() const; // NULL if uninitialized. uint32_t number() const; // Returns 0 if uninitialized. + bool is_extension() const; // An integer that can be used as an index into an array of fields for // whatever message this field belongs to. Guaranteed to be less than @@ -279,8 +280,21 @@ class upb::FieldDef /* : public upb::Def */ { // been finalized. int index() const; - // The MessageDef to which this field belongs, or NULL if none. + // The MessageDef to which this field belongs. + // + // If this field has been added to a MessageDef, that message can be retrieved + // directly (this is always the case for frozen FieldDefs). + // + // If the field has not yet been added to a MessageDef, you can set the name + // of the containing type symbolically instead. This is mostly useful for + // extensions, where the extension is declared separately from the message. const MessageDef* containing_type() const; + const char* containing_type_name(); + + // This may only be called if containing_type() == NULL (ie. the field has not + // been added to a message yet). + bool set_containing_type_name(const char *name, Status* status); + bool set_containing_type_name(const std::string& name, Status* status); // The field's type according to the enum in descriptor.proto. This is not // the same as UPB_TYPE_*, because it distinguishes between (for example) @@ -297,6 +311,7 @@ class upb::FieldDef /* : public upb::Def */ { void set_type(Type type); void set_label(Label label); void set_descriptor_type(DescriptorType type); + void set_is_extension(bool is_extension); // "number" and "name" must be set before the FieldDef is added to a // MessageDef, and may not be set after that. @@ -395,9 +410,8 @@ class upb::FieldDef /* : public upb::Def */ { // Before a fielddef is frozen, its subdef may be set either directly (with a // upb::Def*) or symbolically. Symbolic refs must be resolved before the - // containing msgdef can be frozen (see upb_resolve() above). The client is - // responsible for making sure that "subdef" lives until this fielddef is - // frozen or deleted. + // containing msgdef can be frozen (see upb_resolve() above). upb always + // guarantees that any def reachable from a live def will also be kept alive. // // Both methods require that upb_hassubdef(f) (so the type must be set prior // to calling these methods). Returns false if this is not the case, or if @@ -423,14 +437,19 @@ struct upb_fielddef { float flt; void *bytes; } defaultval; - const upb_msgdef *msgdef; + union { + const upb_msgdef *def; // If !msg_is_symbolic. + char *name; // If msg_is_symbolic. + } msg; union { const upb_def *def; // If !subdef_is_symbolic. char *name; // If subdef_is_symbolic. } sub; // The msgdef or enumdef for this field, if upb_hassubdef(f). bool subdef_is_symbolic; + bool msg_is_symbolic; bool default_is_string; bool type_is_set_; // False until type is explicitly set. + bool is_extension_; upb_intfmt_t intfmt; bool tagdelim; upb_fieldtype_t type_; @@ -440,13 +459,14 @@ struct upb_fielddef { uint32_t index_; }; -#define UPB_FIELDDEF_INIT(label, type, intfmt, tagdelim, name, num, msgdef, \ - subdef, selector_base, index, defaultval, refs, \ - ref2s) \ - { \ - UPB_DEF_INIT(name, UPB_DEF_FIELD, refs, ref2s), defaultval, msgdef, \ - {subdef}, false, type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES, \ - true, intfmt, tagdelim, type, label, num, selector_base, index \ +#define UPB_FIELDDEF_INIT(label, type, intfmt, tagdelim, is_extension, name, \ + num, msgdef, subdef, selector_base, index, \ + defaultval, refs, ref2s) \ + { \ + UPB_DEF_INIT(name, UPB_DEF_FIELD, refs, ref2s), defaultval, {msgdef}, \ + {subdef}, false, false, \ + type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES, true, is_extension, \ + intfmt, tagdelim, type, label, num, selector_base, index \ } // Native C API. @@ -475,8 +495,10 @@ upb_descriptortype_t upb_fielddef_descriptortype(const upb_fielddef *f); upb_label_t upb_fielddef_label(const upb_fielddef *f); uint32_t upb_fielddef_number(const upb_fielddef *f); const char *upb_fielddef_name(const upb_fielddef *f); +bool upb_fielddef_isextension(const upb_fielddef *f); const upb_msgdef *upb_fielddef_containingtype(const upb_fielddef *f); upb_msgdef *upb_fielddef_containingtype_mutable(upb_fielddef *f); +const char *upb_fielddef_containingtypename(upb_fielddef *f); upb_intfmt_t upb_fielddef_intfmt(const upb_fielddef *f); uint32_t upb_fielddef_index(const upb_fielddef *f); bool upb_fielddef_istagdelim(const upb_fielddef *f); @@ -504,6 +526,9 @@ void upb_fielddef_setdescriptortype(upb_fielddef *f, int type); void upb_fielddef_setlabel(upb_fielddef *f, upb_label_t label); bool upb_fielddef_setnumber(upb_fielddef *f, uint32_t number, upb_status *s); bool upb_fielddef_setname(upb_fielddef *f, const char *name, upb_status *s); +bool upb_fielddef_setcontainingtypename(upb_fielddef *f, const char *name, + upb_status *s); +bool upb_fielddef_setisextension(upb_fielddef *f, bool is_extension); bool upb_fielddef_setintfmt(upb_fielddef *f, upb_intfmt_t fmt); bool upb_fielddef_settagdelim(upb_fielddef *f, bool tag_delim); void upb_fielddef_setdefaultint64(upb_fielddef *f, int64_t val); @@ -1043,9 +1068,15 @@ inline FieldDef::Label FieldDef::label() const { } inline uint32_t FieldDef::number() const { return upb_fielddef_number(this); } inline const char* FieldDef::name() const { return upb_fielddef_name(this); } +inline bool FieldDef::is_extension() const { + return upb_fielddef_isextension(this); +} inline const MessageDef* FieldDef::containing_type() const { return upb_fielddef_containingtype(this); } +inline const char* FieldDef::containing_type_name() { + return upb_fielddef_containingtypename(this); +} inline bool FieldDef::set_number(uint32_t number, Status* s) { return upb_fielddef_setnumber(this, number, s); } @@ -1055,9 +1086,19 @@ inline bool FieldDef::set_name(const char *name, Status* s) { inline bool FieldDef::set_name(const std::string& name, Status* s) { return upb_fielddef_setname(this, upb_safecstr(name), s); } +inline bool FieldDef::set_containing_type_name(const char *name, Status* s) { + return upb_fielddef_setcontainingtypename(this, name, s); +} +inline bool FieldDef::set_containing_type_name(const std::string &name, + Status *s) { + return upb_fielddef_setcontainingtypename(this, upb_safecstr(name), s); +} inline void FieldDef::set_type(upb_fieldtype_t type) { upb_fielddef_settype(this, type); } +inline void FieldDef::set_is_extension(bool is_extension) { + upb_fielddef_setisextension(this, is_extension); +} inline void FieldDef::set_descriptor_type(FieldDef::DescriptorType type) { upb_fielddef_setdescriptortype(this, type); } diff --git a/upb/descriptor/descriptor.upb.c b/upb/descriptor/descriptor.upb.c index f183285..8046bcd 100755 --- a/upb/descriptor/descriptor.upb.c +++ b/upb/descriptor/descriptor.upb.c @@ -39,79 +39,79 @@ const upb_msgdef google_protobuf_msgs[20] = { }; const upb_fielddef google_protobuf_fields[73] = { - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "aggregate_value", 8, &google_protobuf_msgs[18], NULL, 15, 6, {0},&reftables[40], &reftables[41]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "cc_generic_services", 16, &google_protobuf_msgs[10], NULL, 14, 5, {0},&reftables[42], &reftables[43]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "ctype", 1, &google_protobuf_msgs[7], UPB_UPCAST(&google_protobuf_enums[2]), 6, 1, {0},&reftables[44], &reftables[45]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "default_value", 7, &google_protobuf_msgs[6], NULL, 16, 7, {0},&reftables[46], &reftables[47]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, "dependency", 3, &google_protobuf_msgs[8], NULL, 30, 8, {0},&reftables[48], &reftables[49]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "deprecated", 3, &google_protobuf_msgs[7], NULL, 8, 3, {0},&reftables[50], &reftables[51]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_DOUBLE, 0, false, "double_value", 6, &google_protobuf_msgs[18], NULL, 11, 4, {0},&reftables[52], &reftables[53]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "end", 2, &google_protobuf_msgs[1], NULL, 3, 1, {0},&reftables[54], &reftables[55]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "enum_type", 4, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[2]), 16, 2, {0},&reftables[56], &reftables[57]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "enum_type", 5, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[2]), 13, 1, {0},&reftables[58], &reftables[59]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "experimental_map_key", 9, &google_protobuf_msgs[7], NULL, 9, 4, {0},&reftables[60], &reftables[61]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "extendee", 2, &google_protobuf_msgs[6], NULL, 7, 2, {0},&reftables[62], &reftables[63]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension", 7, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[6]), 19, 3, {0},&reftables[64], &reftables[65]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension", 6, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[6]), 22, 4, {0},&reftables[66], &reftables[67]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "extension_range", 5, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[1]), 19, 3, {0},&reftables[68], &reftables[69]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "field", 2, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[6]), 10, 0, {0},&reftables[70], &reftables[71]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "file", 1, &google_protobuf_msgs[9], UPB_UPCAST(&google_protobuf_msgs[8]), 5, 0, {0},&reftables[72], &reftables[73]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "identifier_value", 3, &google_protobuf_msgs[18], NULL, 6, 1, {0},&reftables[74], &reftables[75]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "input_type", 2, &google_protobuf_msgs[12], NULL, 7, 2, {0},&reftables[76], &reftables[77]), - UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_BOOL, 0, false, "is_extension", 2, &google_protobuf_msgs[19], NULL, 5, 1, {0},&reftables[78], &reftables[79]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_generate_equals_and_hash", 20, &google_protobuf_msgs[10], NULL, 17, 8, {0},&reftables[80], &reftables[81]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_generic_services", 17, &google_protobuf_msgs[10], NULL, 15, 6, {0},&reftables[82], &reftables[83]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "java_multiple_files", 10, &google_protobuf_msgs[10], NULL, 13, 4, {0},&reftables[84], &reftables[85]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "java_outer_classname", 8, &google_protobuf_msgs[10], NULL, 9, 2, {0},&reftables[86], &reftables[87]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "java_package", 1, &google_protobuf_msgs[10], NULL, 6, 1, {0},&reftables[88], &reftables[89]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "label", 4, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_enums[0]), 11, 4, {0},&reftables[90], &reftables[91]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "location", 1, &google_protobuf_msgs[16], UPB_UPCAST(&google_protobuf_msgs[17]), 5, 0, {0},&reftables[92], &reftables[93]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "message_set_wire_format", 1, &google_protobuf_msgs[11], NULL, 6, 1, {0},&reftables[94], &reftables[95]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "message_type", 4, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[0]), 10, 0, {0},&reftables[96], &reftables[97]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "method", 2, &google_protobuf_msgs[14], UPB_UPCAST(&google_protobuf_msgs[12]), 6, 0, {0},&reftables[98], &reftables[99]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "name", 2, &google_protobuf_msgs[18], UPB_UPCAST(&google_protobuf_msgs[19]), 5, 0, {0},&reftables[100], &reftables[101]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[8], NULL, 22, 6, {0},&reftables[102], &reftables[103]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[14], NULL, 8, 2, {0},&reftables[104], &reftables[105]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[12], NULL, 4, 1, {0},&reftables[106], &reftables[107]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[6], NULL, 4, 1, {0},&reftables[108], &reftables[109]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[4], NULL, 4, 1, {0},&reftables[110], &reftables[111]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[2], NULL, 8, 2, {0},&reftables[112], &reftables[113]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "name", 1, &google_protobuf_msgs[0], NULL, 24, 6, {0},&reftables[114], &reftables[115]), - UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_STRING, 0, false, "name_part", 1, &google_protobuf_msgs[19], NULL, 2, 0, {0},&reftables[116], &reftables[117]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT64, UPB_INTFMT_VARIABLE, false, "negative_int_value", 5, &google_protobuf_msgs[18], NULL, 10, 3, {0},&reftables[118], &reftables[119]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "nested_type", 3, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[0]), 13, 1, {0},&reftables[120], &reftables[121]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "no_standard_descriptor_accessor", 2, &google_protobuf_msgs[11], NULL, 7, 2, {0},&reftables[122], &reftables[123]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "number", 2, &google_protobuf_msgs[4], NULL, 7, 2, {0},&reftables[124], &reftables[125]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "number", 3, &google_protobuf_msgs[6], NULL, 10, 3, {0},&reftables[126], &reftables[127]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "optimize_for", 9, &google_protobuf_msgs[10], UPB_UPCAST(&google_protobuf_enums[3]), 12, 3, {0},&reftables[128], &reftables[129]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[2], UPB_UPCAST(&google_protobuf_msgs[3]), 7, 1, {0},&reftables[130], &reftables[131]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 8, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[10]), 20, 4, {0},&reftables[132], &reftables[133]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[14], UPB_UPCAST(&google_protobuf_msgs[15]), 7, 1, {0},&reftables[134], &reftables[135]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 7, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[11]), 23, 5, {0},&reftables[136], &reftables[137]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 4, &google_protobuf_msgs[12], UPB_UPCAST(&google_protobuf_msgs[13]), 3, 0, {0},&reftables[138], &reftables[139]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 3, &google_protobuf_msgs[4], UPB_UPCAST(&google_protobuf_msgs[5]), 3, 0, {0},&reftables[140], &reftables[141]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "options", 8, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_msgs[7]), 3, 0, {0},&reftables[142], &reftables[143]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "output_type", 3, &google_protobuf_msgs[12], NULL, 10, 3, {0},&reftables[144], &reftables[145]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "package", 2, &google_protobuf_msgs[8], NULL, 25, 7, {0},&reftables[146], &reftables[147]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "packed", 2, &google_protobuf_msgs[7], NULL, 7, 2, {0},&reftables[148], &reftables[149]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "path", 1, &google_protobuf_msgs[17], NULL, 4, 0, {0},&reftables[150], &reftables[151]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_UINT64, UPB_INTFMT_VARIABLE, false, "positive_int_value", 4, &google_protobuf_msgs[18], NULL, 9, 2, {0},&reftables[152], &reftables[153]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, "py_generic_services", 18, &google_protobuf_msgs[10], NULL, 16, 7, {0},&reftables[154], &reftables[155]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "service", 6, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[14]), 16, 2, {0},&reftables[156], &reftables[157]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, "source_code_info", 9, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[16]), 21, 5, {0},&reftables[158], &reftables[159]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "span", 2, &google_protobuf_msgs[17], NULL, 7, 1, {0},&reftables[160], &reftables[161]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, "start", 1, &google_protobuf_msgs[1], NULL, 2, 0, {0},&reftables[162], &reftables[163]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, "string_value", 7, &google_protobuf_msgs[18], NULL, 12, 5, {0},&reftables[164], &reftables[165]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, "type", 5, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_enums[1]), 12, 5, {0},&reftables[166], &reftables[167]), - UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, "type_name", 6, &google_protobuf_msgs[6], NULL, 13, 6, {0},&reftables[168], &reftables[169]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[3], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[170], &reftables[171]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[15], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[172], &reftables[173]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[11], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[174], &reftables[175]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[10], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[176], &reftables[177]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[7], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[178], &reftables[179]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[13], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[180], &reftables[181]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "uninterpreted_option", 999, &google_protobuf_msgs[5], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[182], &reftables[183]), - UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, "value", 2, &google_protobuf_msgs[2], UPB_UPCAST(&google_protobuf_msgs[4]), 6, 0, {0},&reftables[184], &reftables[185]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "aggregate_value", 8, &google_protobuf_msgs[18], NULL, 15, 6, {0},&reftables[40], &reftables[41]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, "cc_generic_services", 16, &google_protobuf_msgs[10], NULL, 14, 5, {0},&reftables[42], &reftables[43]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, "ctype", 1, &google_protobuf_msgs[7], UPB_UPCAST(&google_protobuf_enums[2]), 6, 1, {0},&reftables[44], &reftables[45]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "default_value", 7, &google_protobuf_msgs[6], NULL, 16, 7, {0},&reftables[46], &reftables[47]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_STRING, 0, false, false, "dependency", 3, &google_protobuf_msgs[8], NULL, 30, 8, {0},&reftables[48], &reftables[49]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, "deprecated", 3, &google_protobuf_msgs[7], NULL, 8, 3, {0},&reftables[50], &reftables[51]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_DOUBLE, 0, false, false, "double_value", 6, &google_protobuf_msgs[18], NULL, 11, 4, {0},&reftables[52], &reftables[53]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, "end", 2, &google_protobuf_msgs[1], NULL, 3, 1, {0},&reftables[54], &reftables[55]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "enum_type", 4, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[2]), 16, 2, {0},&reftables[56], &reftables[57]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "enum_type", 5, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[2]), 13, 1, {0},&reftables[58], &reftables[59]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "experimental_map_key", 9, &google_protobuf_msgs[7], NULL, 9, 4, {0},&reftables[60], &reftables[61]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "extendee", 2, &google_protobuf_msgs[6], NULL, 7, 2, {0},&reftables[62], &reftables[63]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "extension", 7, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[6]), 19, 3, {0},&reftables[64], &reftables[65]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "extension", 6, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[6]), 22, 4, {0},&reftables[66], &reftables[67]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "extension_range", 5, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[1]), 19, 3, {0},&reftables[68], &reftables[69]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "field", 2, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[6]), 10, 0, {0},&reftables[70], &reftables[71]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "file", 1, &google_protobuf_msgs[9], UPB_UPCAST(&google_protobuf_msgs[8]), 5, 0, {0},&reftables[72], &reftables[73]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "identifier_value", 3, &google_protobuf_msgs[18], NULL, 6, 1, {0},&reftables[74], &reftables[75]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "input_type", 2, &google_protobuf_msgs[12], NULL, 7, 2, {0},&reftables[76], &reftables[77]), + UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_BOOL, 0, false, false, "is_extension", 2, &google_protobuf_msgs[19], NULL, 5, 1, {0},&reftables[78], &reftables[79]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, "java_generate_equals_and_hash", 20, &google_protobuf_msgs[10], NULL, 17, 8, {0},&reftables[80], &reftables[81]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, "java_generic_services", 17, &google_protobuf_msgs[10], NULL, 15, 6, {0},&reftables[82], &reftables[83]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, "java_multiple_files", 10, &google_protobuf_msgs[10], NULL, 13, 4, {0},&reftables[84], &reftables[85]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "java_outer_classname", 8, &google_protobuf_msgs[10], NULL, 9, 2, {0},&reftables[86], &reftables[87]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "java_package", 1, &google_protobuf_msgs[10], NULL, 6, 1, {0},&reftables[88], &reftables[89]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, "label", 4, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_enums[0]), 11, 4, {0},&reftables[90], &reftables[91]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "location", 1, &google_protobuf_msgs[16], UPB_UPCAST(&google_protobuf_msgs[17]), 5, 0, {0},&reftables[92], &reftables[93]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, "message_set_wire_format", 1, &google_protobuf_msgs[11], NULL, 6, 1, {0},&reftables[94], &reftables[95]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "message_type", 4, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[0]), 10, 0, {0},&reftables[96], &reftables[97]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "method", 2, &google_protobuf_msgs[14], UPB_UPCAST(&google_protobuf_msgs[12]), 6, 0, {0},&reftables[98], &reftables[99]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "name", 2, &google_protobuf_msgs[18], UPB_UPCAST(&google_protobuf_msgs[19]), 5, 0, {0},&reftables[100], &reftables[101]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "name", 1, &google_protobuf_msgs[8], NULL, 22, 6, {0},&reftables[102], &reftables[103]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "name", 1, &google_protobuf_msgs[14], NULL, 8, 2, {0},&reftables[104], &reftables[105]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "name", 1, &google_protobuf_msgs[12], NULL, 4, 1, {0},&reftables[106], &reftables[107]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "name", 1, &google_protobuf_msgs[6], NULL, 4, 1, {0},&reftables[108], &reftables[109]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "name", 1, &google_protobuf_msgs[4], NULL, 4, 1, {0},&reftables[110], &reftables[111]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "name", 1, &google_protobuf_msgs[2], NULL, 8, 2, {0},&reftables[112], &reftables[113]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "name", 1, &google_protobuf_msgs[0], NULL, 24, 6, {0},&reftables[114], &reftables[115]), + UPB_FIELDDEF_INIT(UPB_LABEL_REQUIRED, UPB_TYPE_STRING, 0, false, false, "name_part", 1, &google_protobuf_msgs[19], NULL, 2, 0, {0},&reftables[116], &reftables[117]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT64, UPB_INTFMT_VARIABLE, false, false, "negative_int_value", 5, &google_protobuf_msgs[18], NULL, 10, 3, {0},&reftables[118], &reftables[119]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "nested_type", 3, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[0]), 13, 1, {0},&reftables[120], &reftables[121]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, "no_standard_descriptor_accessor", 2, &google_protobuf_msgs[11], NULL, 7, 2, {0},&reftables[122], &reftables[123]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, "number", 2, &google_protobuf_msgs[4], NULL, 7, 2, {0},&reftables[124], &reftables[125]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, "number", 3, &google_protobuf_msgs[6], NULL, 10, 3, {0},&reftables[126], &reftables[127]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, "optimize_for", 9, &google_protobuf_msgs[10], UPB_UPCAST(&google_protobuf_enums[3]), 12, 3, {0},&reftables[128], &reftables[129]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, "options", 3, &google_protobuf_msgs[2], UPB_UPCAST(&google_protobuf_msgs[3]), 7, 1, {0},&reftables[130], &reftables[131]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, "options", 8, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[10]), 20, 4, {0},&reftables[132], &reftables[133]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, "options", 3, &google_protobuf_msgs[14], UPB_UPCAST(&google_protobuf_msgs[15]), 7, 1, {0},&reftables[134], &reftables[135]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, "options", 7, &google_protobuf_msgs[0], UPB_UPCAST(&google_protobuf_msgs[11]), 23, 5, {0},&reftables[136], &reftables[137]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, "options", 4, &google_protobuf_msgs[12], UPB_UPCAST(&google_protobuf_msgs[13]), 3, 0, {0},&reftables[138], &reftables[139]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, "options", 3, &google_protobuf_msgs[4], UPB_UPCAST(&google_protobuf_msgs[5]), 3, 0, {0},&reftables[140], &reftables[141]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, "options", 8, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_msgs[7]), 3, 0, {0},&reftables[142], &reftables[143]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "output_type", 3, &google_protobuf_msgs[12], NULL, 10, 3, {0},&reftables[144], &reftables[145]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "package", 2, &google_protobuf_msgs[8], NULL, 25, 7, {0},&reftables[146], &reftables[147]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, "packed", 2, &google_protobuf_msgs[7], NULL, 7, 2, {0},&reftables[148], &reftables[149]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, "path", 1, &google_protobuf_msgs[17], NULL, 4, 0, {0},&reftables[150], &reftables[151]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_UINT64, UPB_INTFMT_VARIABLE, false, false, "positive_int_value", 4, &google_protobuf_msgs[18], NULL, 9, 2, {0},&reftables[152], &reftables[153]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BOOL, 0, false, false, "py_generic_services", 18, &google_protobuf_msgs[10], NULL, 16, 7, {0},&reftables[154], &reftables[155]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "service", 6, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[14]), 16, 2, {0},&reftables[156], &reftables[157]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_MESSAGE, 0, false, false, "source_code_info", 9, &google_protobuf_msgs[8], UPB_UPCAST(&google_protobuf_msgs[16]), 21, 5, {0},&reftables[158], &reftables[159]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, "span", 2, &google_protobuf_msgs[17], NULL, 7, 1, {0},&reftables[160], &reftables[161]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_INT32, UPB_INTFMT_VARIABLE, false, false, "start", 1, &google_protobuf_msgs[1], NULL, 2, 0, {0},&reftables[162], &reftables[163]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_BYTES, 0, false, false, "string_value", 7, &google_protobuf_msgs[18], NULL, 12, 5, {0},&reftables[164], &reftables[165]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_ENUM, 0, false, false, "type", 5, &google_protobuf_msgs[6], UPB_UPCAST(&google_protobuf_enums[1]), 12, 5, {0},&reftables[166], &reftables[167]), + UPB_FIELDDEF_INIT(UPB_LABEL_OPTIONAL, UPB_TYPE_STRING, 0, false, false, "type_name", 6, &google_protobuf_msgs[6], NULL, 13, 6, {0},&reftables[168], &reftables[169]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "uninterpreted_option", 999, &google_protobuf_msgs[3], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[170], &reftables[171]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "uninterpreted_option", 999, &google_protobuf_msgs[15], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[172], &reftables[173]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "uninterpreted_option", 999, &google_protobuf_msgs[11], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[174], &reftables[175]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "uninterpreted_option", 999, &google_protobuf_msgs[10], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[176], &reftables[177]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "uninterpreted_option", 999, &google_protobuf_msgs[7], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[178], &reftables[179]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "uninterpreted_option", 999, &google_protobuf_msgs[13], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[180], &reftables[181]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "uninterpreted_option", 999, &google_protobuf_msgs[5], UPB_UPCAST(&google_protobuf_msgs[18]), 5, 0, {0},&reftables[182], &reftables[183]), + UPB_FIELDDEF_INIT(UPB_LABEL_REPEATED, UPB_TYPE_MESSAGE, 0, false, false, "value", 2, &google_protobuf_msgs[2], UPB_UPCAST(&google_protobuf_msgs[4]), 6, 0, {0},&reftables[184], &reftables[185]), }; const upb_enumdef google_protobuf_enums[4] = { diff --git a/upb/descriptor/reader.c b/upb/descriptor/reader.c index 9dff6e9..eea6ce7 100644 --- a/upb/descriptor/reader.c +++ b/upb/descriptor/reader.c @@ -101,6 +101,7 @@ static void upb_deflist_qualify(upb_deflist *l, char *str, int32_t start) { void upb_descreader_init(upb_descreader *r, const upb_handlers *handlers, upb_status *status) { + UPB_UNUSED(status); upb_deflist_init(&r->defs); upb_sink_reset(upb_descreader_input(r), handlers, r); r->stack_len = 0; @@ -176,8 +177,9 @@ static bool file_endmsg(void *closure, const void *hd, upb_status *status) { } static size_t file_onpackage(void *closure, const void *hd, const char *buf, - size_t n) { + size_t n, const upb_bufhandle *handle) { UPB_UNUSED(hd); + UPB_UNUSED(handle); upb_descreader *r = closure; // XXX: see comment at the top of the file. upb_descreader_setscopename(r, upb_strndup(buf, n)); @@ -194,8 +196,9 @@ static bool enumval_startmsg(void *closure, const void *hd) { } static size_t enumval_onname(void *closure, const void *hd, const char *buf, - size_t n) { + size_t n, const upb_bufhandle *handle) { UPB_UNUSED(hd); + UPB_UNUSED(handle); upb_descreader *r = closure; // XXX: see comment at the top of the file. free(r->name); @@ -256,8 +259,9 @@ static bool enum_endmsg(void *closure, const void *hd, upb_status *status) { } static size_t enum_onname(void *closure, const void *hd, const char *buf, - size_t n) { + size_t n, const upb_bufhandle *handle) { UPB_UNUSED(hd); + UPB_UNUSED(handle); upb_descreader *r = closure; // XXX: see comment at the top of the file. char *fullname = upb_strndup(buf, n); @@ -349,7 +353,8 @@ static bool field_endmsg(void *closure, const void *hd, upb_status *status) { upb_descreader *r = closure; upb_fielddef *f = r->f; // TODO: verify that all required fields were present. - assert(upb_fielddef_number(f) != 0 && upb_fielddef_name(f) != NULL); + assert(upb_fielddef_number(f) != 0); + assert(upb_fielddef_name(f) != NULL); assert((upb_fielddef_subdefname(f) != NULL) == upb_fielddef_hassubdef(f)); if (r->default_string) { @@ -388,13 +393,15 @@ static bool field_onlabel(void *closure, const void *hd, int32_t val) { static bool field_onnumber(void *closure, const void *hd, int32_t val) { UPB_UNUSED(hd); upb_descreader *r = closure; - upb_fielddef_setnumber(r->f, val, NULL); + bool ok = upb_fielddef_setnumber(r->f, val, NULL); + UPB_ASSERT_VAR(ok, ok); return true; } static size_t field_onname(void *closure, const void *hd, const char *buf, - size_t n) { + size_t n, const upb_bufhandle *handle) { UPB_UNUSED(hd); + UPB_UNUSED(handle); upb_descreader *r = closure; // XXX: see comment at the top of the file. char *name = upb_strndup(buf, n); @@ -404,8 +411,9 @@ static size_t field_onname(void *closure, const void *hd, const char *buf, } static size_t field_ontypename(void *closure, const void *hd, const char *buf, - size_t n) { + size_t n, const upb_bufhandle *handle) { UPB_UNUSED(hd); + UPB_UNUSED(handle); upb_descreader *r = closure; // XXX: see comment at the top of the file. char *name = upb_strndup(buf, n); @@ -414,9 +422,22 @@ static size_t field_ontypename(void *closure, const void *hd, const char *buf, return n; } -static size_t field_ondefaultval(void *closure, const void *hd, - const char *buf, size_t n) { +static size_t field_onextendee(void *closure, const void *hd, const char *buf, + size_t n, const upb_bufhandle *handle) { + UPB_UNUSED(hd); + UPB_UNUSED(handle); + upb_descreader *r = closure; + // XXX: see comment at the top of the file. + char *name = upb_strndup(buf, n); + upb_fielddef_setcontainingtypename(r->f, name, NULL); + free(name); + return n; +} + +static size_t field_ondefaultval(void *closure, const void *hd, const char *buf, + size_t n, const upb_bufhandle *handle) { UPB_UNUSED(hd); + UPB_UNUSED(handle); upb_descreader *r = closure; // Have to convert from string to the correct type, but we might not know the // type yet, so we save it as a string until the end of the field. @@ -448,8 +469,9 @@ static bool msg_endmsg(void *closure, const void *hd, upb_status *status) { } static size_t msg_onname(void *closure, const void *hd, const char *buf, - size_t n) { + size_t n, const upb_bufhandle *handle) { UPB_UNUSED(hd); + UPB_UNUSED(handle); upb_descreader *r = closure; upb_msgdef *m = upb_descreader_top(r); // XXX: see comment at the top of the file. @@ -468,11 +490,12 @@ static bool msg_onendfield(void *closure, const void *hd) { return true; } -static bool discardfield(void *closure, const void *hd) { +static bool pushextension(void *closure, const void *hd) { UPB_UNUSED(hd); upb_descreader *r = closure; - // Discard extension field so we don't leak it. - upb_fielddef_unref(r->f, &r->defs); + assert(upb_fielddef_containingtypename(r->f)); + upb_fielddef_setisextension(r->f, true); + upb_deflist_push(&r->defs, UPB_UPCAST(r->f)); r->f = NULL; return true; } @@ -492,14 +515,12 @@ static void reghandlers(void *closure, upb_handlers *h) { upb_handlers_setendmsg(h, &msg_endmsg, NULL); upb_handlers_setstring(h, f(h, "name"), &msg_onname, NULL); upb_handlers_setendsubmsg(h, f(h, "field"), &msg_onendfield, NULL); - // TODO: support extensions - upb_handlers_setendsubmsg(h, f(h, "extension"), &discardfield, NULL); + upb_handlers_setendsubmsg(h, f(h, "extension"), &pushextension, NULL); } else if (m == GOOGLE_PROTOBUF_FILEDESCRIPTORPROTO) { upb_handlers_setstartmsg(h, &file_startmsg, NULL); upb_handlers_setendmsg(h, &file_endmsg, NULL); upb_handlers_setstring(h, f(h, "package"), &file_onpackage, NULL); - // TODO: support extensions - upb_handlers_setendsubmsg(h, f(h, "extension"), &discardfield, NULL); + upb_handlers_setendsubmsg(h, f(h, "extension"), &pushextension, NULL); } else if (m == GOOGLE_PROTOBUF_ENUMVALUEDESCRIPTORPROTO) { upb_handlers_setstartmsg(h, &enumval_startmsg, NULL); upb_handlers_setendmsg(h, &enumval_endmsg, NULL); @@ -517,6 +538,7 @@ static void reghandlers(void *closure, upb_handlers *h) { upb_handlers_setint32(h, f(h, "number"), &field_onnumber, NULL); upb_handlers_setstring(h, f(h, "name"), &field_onname, NULL); upb_handlers_setstring(h, f(h, "type_name"), &field_ontypename, NULL); + upb_handlers_setstring(h, f(h, "extendee"), &field_onextendee, NULL); upb_handlers_setstring(h, f(h, "default_value"), &field_ondefaultval, NULL); } } diff --git a/upb/google/README b/upb/google/README deleted file mode 100644 index a237583..0000000 --- a/upb/google/README +++ /dev/null @@ -1,16 +0,0 @@ -This directory contains code to interoperate with Google's official -Protocol Buffers release. Since it doesn't really have a name -besides "protobuf," calling this directory "google" seems like the -least confusing option. - -We support writing into protobuf's generated classes (and hopefully -reading too, before long). We support both the open source protobuf -release and the Google-internal version of the same code. The two -live in different namespaces, and the internal version supports some -features that are not supported in the open-source release. Also, the -internal version includes the legacy "proto1" classes which we must -support; thankfully this is mostly relegated to its own separate file. - -Our functionality requires the full google::protobuf::Message -interface; we rely on reflection so we know what fields to read/write -and where to put them, so we can't support MessageLite. diff --git a/upb/handlers-inl.h b/upb/handlers-inl.h index a101da6..0bee5a2 100644 --- a/upb/handlers-inl.h +++ b/upb/handlers-inl.h @@ -91,6 +91,39 @@ #undef UPB_LONG_IS_64BITS #undef UPB_LLONG_IS_64BITS +// C inline methods. + +// upb_bufhandle +UPB_INLINE void upb_bufhandle_init(upb_bufhandle *h) { + h->obj_ = NULL; + h->objtype_ = NULL; + h->buf_ = NULL; + h->objofs_ = 0; +} +UPB_INLINE void upb_bufhandle_uninit(upb_bufhandle *h) { + UPB_UNUSED(h); +} +UPB_INLINE void upb_bufhandle_setobj(upb_bufhandle *h, const void *obj, + const void *type) { + h->obj_ = obj; + h->objtype_ = type; +} +UPB_INLINE void upb_bufhandle_setbuf(upb_bufhandle *h, const char *buf, + size_t ofs) { + h->buf_ = buf; + h->objofs_ = ofs; +} +UPB_INLINE const void *upb_bufhandle_obj(const upb_bufhandle *h) { + return h->obj_; +} +UPB_INLINE const void *upb_bufhandle_objtype(const upb_bufhandle *h) { + return h->objtype_; +} +UPB_INLINE const char *upb_bufhandle_buf(const upb_bufhandle *h) { + return h->buf_; +} + + #ifdef __cplusplus namespace upb { @@ -122,8 +155,8 @@ typedef void CleanupFunc(void *ptr); // We define a nonsense default because otherwise it will fail to instantiate as // a function parameter type even in cases where we don't expect any caller to // actually match the overload. -class NonsenseType {}; -template <class T> struct remove_constptr { typedef NonsenseType type; }; +class CouldntRemoveConst {}; +template <class T> struct remove_constptr { typedef CouldntRemoveConst type; }; template <class T> struct remove_constptr<const T *> { typedef T *type; }; // Template that we use below to remove a template specialization from @@ -133,6 +166,44 @@ template <class T> struct disable_if_same<T, T> {}; template <class T> void DeletePointer(void *p) { delete static_cast<T *>(p); } +template <class T1, class T2> +struct FirstUnlessVoid { + typedef T1 value; +}; + +template <class T2> +struct FirstUnlessVoid<void, T2> { + typedef T2 value; +}; + +template<class T, class U> +struct is_same { + static bool value; +}; + +template<class T> +struct is_same<T, T> { + static bool value; +}; + +template<class T, class U> +bool is_same<T, U>::value = false; + +template<class T> +bool is_same<T, T>::value = true; + +// FuncInfo //////////////////////////////////////////////////////////////////// + +// Info about the user's original, pre-wrapped function. +template <class C, class R = void> +struct FuncInfo { + // The type of the closure that the function takes (its first param). + typedef C Closure; + + // The return type. + typedef R Return; +}; + // Func //////////////////////////////////////////////////////////////////////// // Func1, Func2, Func3: Template classes representing a function and its @@ -147,30 +218,45 @@ struct UnboundFunc { void *GetData() { return NULL; } }; -template <class R, class P1, R F(P1)> +template <class R, class P1, R F(P1), class I> struct Func1 : public UnboundFunc { typedef R Return; + typedef I FuncInfo; static R Call(P1 p1) { return F(p1); } }; -template <class R, class P1, class P2, R F(P1, P2)> +template <class R, class P1, class P2, R F(P1, P2), class I> struct Func2 : public UnboundFunc { typedef R Return; + typedef I FuncInfo; static R Call(P1 p1, P2 p2) { return F(p1, p2); } }; -template <class R, class P1, class P2, class P3, R F(P1, P2, P3)> +template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I> struct Func3 : public UnboundFunc { typedef R Return; + typedef I FuncInfo; static R Call(P1 p1, P2 p2, P3 p3) { return F(p1, p2, p3); } }; -template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)> +template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4), + class I> struct Func4 : public UnboundFunc { typedef R Return; + typedef I FuncInfo; static R Call(P1 p1, P2 p2, P3 p3, P4 p4) { return F(p1, p2, p3, p4); } }; +template <class R, class P1, class P2, class P3, class P4, class P5, + R F(P1, P2, P3, P4, P5), class I> +struct Func5 : public UnboundFunc { + typedef R Return; + typedef I FuncInfo; + static R Call(P1 p1, P2 p2, P3 p3, P4 p4, P5 p5) { + return F(p1, p2, p3, p4, p5); + } +}; + // BoundFunc /////////////////////////////////////////////////////////////////// // BoundFunc2, BoundFunc3: Like Func2/Func3 except also contains a value that @@ -187,24 +273,36 @@ struct BoundFunc { MutableP2 data; }; -template <class R, class P1, class P2, R F(P1, P2)> +template <class R, class P1, class P2, R F(P1, P2), class I> struct BoundFunc2 : public BoundFunc<P2> { typedef BoundFunc<P2> Base; + typedef I FuncInfo; explicit BoundFunc2(typename Base::MutableP2 arg) : Base(arg) {} }; -template <class R, class P1, class P2, class P3, R F(P1, P2, P3)> +template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I> struct BoundFunc3 : public BoundFunc<P2> { typedef BoundFunc<P2> Base; + typedef I FuncInfo; explicit BoundFunc3(typename Base::MutableP2 arg) : Base(arg) {} }; -template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)> +template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4), + class I> struct BoundFunc4 : public BoundFunc<P2> { typedef BoundFunc<P2> Base; + typedef I FuncInfo; explicit BoundFunc4(typename Base::MutableP2 arg) : Base(arg) {} }; +template <class R, class P1, class P2, class P3, class P4, class P5, + R F(P1, P2, P3, P4, P5), class I> +struct BoundFunc5 : public BoundFunc<P2> { + typedef BoundFunc<P2> Base; + typedef I FuncInfo; + explicit BoundFunc5(typename Base::MutableP2 arg) : Base(arg) {} +}; + // FuncSig ///////////////////////////////////////////////////////////////////// // FuncSig1, FuncSig2, FuncSig3: template classes reflecting a function @@ -215,49 +313,64 @@ struct BoundFunc4 : public BoundFunc<P2> { template <class R, class P1> struct FuncSig1 { template <R F(P1)> - Func1<R, P1, F> GetFunc() { - return Func1<R, P1, F>(); + Func1<R, P1, F, FuncInfo<P1, R> > GetFunc() { + return Func1<R, P1, F, FuncInfo<P1, R> >(); } }; template <class R, class P1, class P2> struct FuncSig2 { template <R F(P1, P2)> - Func2<R, P1, P2, F> GetFunc() { - return Func2<R, P1, P2, F>(); + Func2<R, P1, P2, F, FuncInfo<P1, R> > GetFunc() { + return Func2<R, P1, P2, F, FuncInfo<P1, R> >(); } template <R F(P1, P2)> - BoundFunc2<R, P1, P2, F> GetFunc(typename remove_constptr<P2>::type param2) { - return BoundFunc2<R, P1, P2, F>(param2); + BoundFunc2<R, P1, P2, F, FuncInfo<P1, R> > GetFunc( + typename remove_constptr<P2>::type param2) { + return BoundFunc2<R, P1, P2, F, FuncInfo<P1, R> >(param2); } }; template <class R, class P1, class P2, class P3> struct FuncSig3 { template <R F(P1, P2, P3)> - Func3<R, P1, P2, P3, F> GetFunc() { - return Func3<R, P1, P2, P3, F>(); + Func3<R, P1, P2, P3, F, FuncInfo<P1, R> > GetFunc() { + return Func3<R, P1, P2, P3, F, FuncInfo<P1, R> >(); } template <R F(P1, P2, P3)> - BoundFunc3<R, P1, P2, P3, F> GetFunc( + BoundFunc3<R, P1, P2, P3, F, FuncInfo<P1, R> > GetFunc( typename remove_constptr<P2>::type param2) { - return BoundFunc3<R, P1, P2, P3, F>(param2); + return BoundFunc3<R, P1, P2, P3, F, FuncInfo<P1, R> >(param2); } }; template <class R, class P1, class P2, class P3, class P4> struct FuncSig4 { template <R F(P1, P2, P3, P4)> - Func4<R, P1, P2, P3, P4, F> GetFunc() { - return Func4<R, P1, P2, P3, P4, F>(); + Func4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> > GetFunc() { + return Func4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> >(); } template <R F(P1, P2, P3, P4)> - BoundFunc4<R, P1, P2, P3, P4, F> GetFunc( + BoundFunc4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> > GetFunc( + typename remove_constptr<P2>::type param2) { + return BoundFunc4<R, P1, P2, P3, P4, F, FuncInfo<P1, R> >(param2); + } +}; + +template <class R, class P1, class P2, class P3, class P4, class P5> +struct FuncSig5 { + template <R F(P1, P2, P3, P4, P5)> + Func5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> > GetFunc() { + return Func5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> >(); + } + + template <R F(P1, P2, P3, P4, P5)> + BoundFunc5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> > GetFunc( typename remove_constptr<P2>::type param2) { - return BoundFunc4<R, P1, P2, P3, P4, F>(param2); + return BoundFunc5<R, P1, P2, P3, P4, P5, F, FuncInfo<P1, R> >(param2); } }; @@ -287,6 +400,12 @@ inline FuncSig4<R, P1, P2, P3, P4> MatchFunc(R (*f)(P1, P2, P3, P4)) { return FuncSig4<R, P1, P2, P3, P4>(); } +template <class R, class P1, class P2, class P3, class P4, class P5> +inline FuncSig5<R, P1, P2, P3, P4, P5> MatchFunc(R (*f)(P1, P2, P3, P4, P5)) { + UPB_UNUSED(f); // Only used for template parameter deduction. + return FuncSig5<R, P1, P2, P3, P4, P5>(); +} + // MethodSig /////////////////////////////////////////////////////////////////// // CallMethod*: a function template that calls a given method. @@ -310,6 +429,12 @@ R CallMethod3(C *obj, P1 arg1, P2 arg2, P3 arg3) { return ((*obj).*F)(arg1, arg2, arg3); } +template <class R, class C, class P1, class P2, class P3, class P4, + R (C::*F)(P1, P2, P3, P4)> +R CallMethod4(C *obj, P1 arg1, P2 arg2, P3 arg3, P4 arg4) { + return ((*obj).*F)(arg1, arg2, arg3, arg4); +} + // MethodSig: like FuncSig, but for member functions. // // GetFunc() returns a normal FuncN object, so after calling GetFunc() no @@ -317,50 +442,77 @@ R CallMethod3(C *obj, P1 arg1, P2 arg2, P3 arg3) { template <class R, class C> struct MethodSig0 { template <R (C::*F)()> - Func1<R, C *, CallMethod0<R, C, F> > GetFunc() { - return Func1<R, C *, CallMethod0<R, C, F> >(); + Func1<R, C *, CallMethod0<R, C, F>, FuncInfo<C *, R> > GetFunc() { + return Func1<R, C *, CallMethod0<R, C, F>, FuncInfo<C *, R> >(); } }; template <class R, class C, class P1> struct MethodSig1 { template <R (C::*F)(P1)> - Func2<R, C *, P1, CallMethod1<R, C, P1, F> > GetFunc() { - return Func2<R, C *, P1, CallMethod1<R, C, P1, F> >(); + Func2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> > GetFunc() { + return Func2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> >(); } template <R (C::*F)(P1)> - BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F> > GetFunc( + BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> > GetFunc( typename remove_constptr<P1>::type param1) { - return BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F> >(param1); + return BoundFunc2<R, C *, P1, CallMethod1<R, C, P1, F>, FuncInfo<C *, R> >( + param1); } }; template <class R, class C, class P1, class P2> struct MethodSig2 { template <R (C::*F)(P1, P2)> - Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F> > GetFunc() { - return Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F> >(); + Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>, FuncInfo<C *, R> > + GetFunc() { + return Func3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>, + FuncInfo<C *, R> >(); } template <R (C::*F)(P1, P2)> - BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F> > GetFunc( - typename remove_constptr<P1>::type param1) { - return BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F> >(param1); + BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>, FuncInfo<C *, R> > + GetFunc(typename remove_constptr<P1>::type param1) { + return BoundFunc3<R, C *, P1, P2, CallMethod2<R, C, P1, P2, F>, + FuncInfo<C *, R> >(param1); } }; template <class R, class C, class P1, class P2, class P3> struct MethodSig3 { template <R (C::*F)(P1, P2, P3)> - Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F> > GetFunc() { - return Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F> >(); + Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>, FuncInfo<C *, R> > + GetFunc() { + return Func4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>, + FuncInfo<C *, R> >(); } template <R (C::*F)(P1, P2, P3)> - BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F> > GetFunc( - typename remove_constptr<P1>::type param1) { - return BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F> >( + BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>, + FuncInfo<C *, R> > + GetFunc(typename remove_constptr<P1>::type param1) { + return BoundFunc4<R, C *, P1, P2, P3, CallMethod3<R, C, P1, P2, P3, F>, + FuncInfo<C *, R> >(param1); + } +}; + +template <class R, class C, class P1, class P2, class P3, class P4> +struct MethodSig4 { + template <R (C::*F)(P1, P2, P3, P4)> + Func5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>, + FuncInfo<C *, R> > + GetFunc() { + return Func5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>, + FuncInfo<C *, R> >(); + } + + template <R (C::*F)(P1, P2, P3, P4)> + BoundFunc5<R, C *, P1, P2, P3, P4, CallMethod4<R, C, P1, P2, P3, P4, F>, + FuncInfo<C *, R> > + GetFunc(typename remove_constptr<P1>::type param1) { + return BoundFunc5<R, C *, P1, P2, P3, P4, + CallMethod4<R, C, P1, P2, P3, P4, F>, FuncInfo<C *, R> >( param1); } }; @@ -389,6 +541,12 @@ inline MethodSig3<R, C, P1, P2, P3> MatchFunc(R (C::*f)(P1, P2, P3)) { return MethodSig3<R, C, P1, P2, P3>(); } +template <class R, class C, class P1, class P2, class P3, class P4> +inline MethodSig4<R, C, P1, P2, P3, P4> MatchFunc(R (C::*f)(P1, P2, P3, P4)) { + UPB_UNUSED(f); // Only used for template parameter deduction. + return MethodSig4<R, C, P1, P2, P3, P4>(); +} + // MaybeWrapReturn ///////////////////////////////////////////////////////////// // Template class that attempts to wrap the return value of the function so it @@ -448,58 +606,62 @@ void *CastReturnToVoidPtr3(P1 p1, P2 p2, P3 p3) { return F(p1, p2, p3); } -// For the string callback, which takes four params, returns the last param -// which is the size of the entire string. -template <class P1, class P2, class P3, void F(P1, P2, P3, size_t)> -size_t ReturnStringLen(P1 p1, P2 p2, P3 p3, size_t p4) { - F(p1, p2, p3, p4); +// For the string callback, which takes five params, returns the size param. +template <class P1, class P2, + void F(P1, P2, const char *, size_t, const BufferHandle *)> +size_t ReturnStringLen(P1 p1, P2 p2, const char *p3, size_t p4, + const BufferHandle *p5) { + F(p1, p2, p3, p4, p5); return p4; } // If we have a function returning void but want a function returning bool, wrap // it in a function that returns true. -template <class P1, class P2, void F(P1, P2)> -struct MaybeWrapReturn<Func2<void, P1, P2, F>, bool> { - typedef Func2<bool, P1, P2, ReturnTrue2<P1, P2, F> > Func; +template <class P1, class P2, void F(P1, P2), class I> +struct MaybeWrapReturn<Func2<void, P1, P2, F, I>, bool> { + typedef Func2<bool, P1, P2, ReturnTrue2<P1, P2, F>, I> Func; }; -template <class P1, class P2, class P3, void F(P1, P2, P3)> -struct MaybeWrapReturn<Func3<void, P1, P2, P3, F>, bool> { - typedef Func3<bool, P1, P2, P3, ReturnTrue3<P1, P2, P3, F> > Func; +template <class P1, class P2, class P3, void F(P1, P2, P3), class I> +struct MaybeWrapReturn<Func3<void, P1, P2, P3, F, I>, bool> { + typedef Func3<bool, P1, P2, P3, ReturnTrue3<P1, P2, P3, F>, I> Func; }; // If our function returns void but we want one returning void*, wrap it in a // function that returns the first argument. -template <class P1, class P2, void F(P1, P2)> -struct MaybeWrapReturn<Func2<void, P1, P2, F>, void *> { - typedef Func2<void *, P1, P2, ReturnClosure2<P1, P2, F> > Func; +template <class P1, class P2, void F(P1, P2), class I> +struct MaybeWrapReturn<Func2<void, P1, P2, F, I>, void *> { + typedef Func2<void *, P1, P2, ReturnClosure2<P1, P2, F>, I> Func; }; -template <class P1, class P2, class P3, void F(P1, P2, P3)> -struct MaybeWrapReturn<Func3<void, P1, P2, P3, F>, void *> { - typedef Func3<void *, P1, P2, P3, ReturnClosure3<P1, P2, P3, F> > Func; +template <class P1, class P2, class P3, void F(P1, P2, P3), class I> +struct MaybeWrapReturn<Func3<void, P1, P2, P3, F, I>, void *> { + typedef Func3<void *, P1, P2, P3, ReturnClosure3<P1, P2, P3, F>, I> Func; }; // If our function returns void but we want one returning size_t, wrap it in a -// function that returns the last argument. -template <class P1, class P2, class P3, void F(P1, P2, P3, size_t)> -struct MaybeWrapReturn<Func4<void, P1, P2, P3, size_t, F>, size_t> { - typedef Func4<size_t, P1, P2, P3, size_t, ReturnStringLen<P1, P2, P3, F> > - Func; +// function that returns the size argument. +template <class P1, class P2, + void F(P1, P2, const char *, size_t, const BufferHandle *), class I> +struct MaybeWrapReturn< + Func5<void, P1, P2, const char *, size_t, const BufferHandle *, F, I>, + size_t> { + typedef Func5<size_t, P1, P2, const char *, size_t, const BufferHandle *, + ReturnStringLen<P1, P2, F>, I> Func; }; // If our function returns R* but we want one returning void*, wrap it in a // function that casts to void*. -template <class R, class P1, class P2, R *F(P1, P2)> -struct MaybeWrapReturn<Func2<R *, P1, P2, F>, void *, +template <class R, class P1, class P2, R *F(P1, P2), class I> +struct MaybeWrapReturn<Func2<R *, P1, P2, F, I>, void *, typename disable_if_same<R *, void *>::Type> { - typedef Func2<void *, P1, P2, CastReturnToVoidPtr2<R *, P1, P2, F> > Func; + typedef Func2<void *, P1, P2, CastReturnToVoidPtr2<R *, P1, P2, F>, I> Func; }; -template <class R, class P1, class P2, class P3, R *F(P1, P2, P3)> -struct MaybeWrapReturn<Func3<R *, P1, P2, P3, F>, void *, +template <class R, class P1, class P2, class P3, R *F(P1, P2, P3), class I> +struct MaybeWrapReturn<Func3<R *, P1, P2, P3, F, I>, void *, typename disable_if_same<R *, void *>::Type> { - typedef Func3<void *, P1, P2, P3, CastReturnToVoidPtr3<R *, P1, P2, P3, F> > + typedef Func3<void *, P1, P2, P3, CastReturnToVoidPtr3<R *, P1, P2, P3, F>, I> Func; }; @@ -532,6 +694,20 @@ R IgnoreHandlerData4(void *p1, const void *hd, P2 p2, P3 p3) { return F(static_cast<P1>(p1), p2, p3); } +template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)> +R IgnoreHandlerData5(void *p1, const void *hd, P2 p2, P3 p3, P4 p4) { + UPB_UNUSED(hd); + return F(static_cast<P1>(p1), p2, p3, p4); +} + +template <class R, class P1, R F(P1, const char*, size_t)> +R IgnoreHandlerDataIgnoreHandle(void *p1, const void *hd, const char *p2, + size_t p3, const BufferHandle *handle) { + UPB_UNUSED(hd); + UPB_UNUSED(handle); + return F(static_cast<P1>(p1), p2, p3); +} + // Function that casts the handler data parameter. template <class R, class P1, class P2, R F(P1, P2)> R CastHandlerData2(void *c, const void *hd) { @@ -544,47 +720,75 @@ R CastHandlerData3(void *c, const void *hd, P3Wrapper p3) { return F(static_cast<P1>(c), static_cast<P2>(hd), p3); } -template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)> -R CastHandlerData4(void *c, const void *hd, P3 p3, P4 p4) { +template <class R, class P1, class P2, class P3, class P4, class P5, + R F(P1, P2, P3, P4, P5)> +R CastHandlerData5(void *c, const void *hd, P3 p3, P4 p4, P5 p5) { + return F(static_cast<P1>(c), static_cast<P2>(hd), p3, p4, p5); +} + +template <class R, class P1, class P2, R F(P1, P2, const char *, size_t)> +R CastHandlerDataIgnoreHandle(void *c, const void *hd, const char *p3, + size_t p4, const BufferHandle *handle) { + UPB_UNUSED(handle); return F(static_cast<P1>(c), static_cast<P2>(hd), p3, p4); } // For unbound functions, ignore the handler data. -template <class R, class P1, R F(P1)> -struct ConvertParams<Func1<R, P1, F> > { - typedef Func2<R, void *, const void *, IgnoreHandlerData2<R, P1, F> > Func; +template <class R, class P1, R F(P1), class I> +struct ConvertParams<Func1<R, P1, F, I> > { + typedef Func2<R, void *, const void *, IgnoreHandlerData2<R, P1, F>, I> Func; }; -template <class R, class P1, class P2, R F(P1, P2)> -struct ConvertParams<Func2<R, P1, P2, F> > { +template <class R, class P1, class P2, R F(P1, P2), class I> +struct ConvertParams<Func2<R, P1, P2, F, I> > { typedef typename CanonicalType<P2>::Type CanonicalP2; typedef Func3<R, void *, const void *, CanonicalP2, - IgnoreHandlerData3<R, P1, CanonicalP2, P2, F> > Func; + IgnoreHandlerData3<R, P1, CanonicalP2, P2, F>, I> Func; }; -template <class R, class P1, class P2, class P3, R F(P1, P2, P3)> -struct ConvertParams<Func3<R, P1, P2, P3, F> > { - typedef Func4<R, void *, const void *, P2, P3, - IgnoreHandlerData4<R, P1, P2, P3, F> > Func; +// For StringBuffer only; this ignores both the handler data and the +// BufferHandle. +template <class R, class P1, R F(P1, const char *, size_t), class I> +struct ConvertParams<Func3<R, P1, const char *, size_t, F, I> > { + typedef Func5<R, void *, const void *, const char *, size_t, + const BufferHandle *, IgnoreHandlerDataIgnoreHandle<R, P1, F>, + I> Func; +}; + +template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4), class I> +struct ConvertParams<Func4<R, P1, P2, P3, P4, F, I> > { + typedef Func5<R, void *, const void *, P2, P3, P4, + IgnoreHandlerData5<R, P1, P2, P3, P4, F>, I> Func; }; // For bound functions, cast the handler data. -template <class R, class P1, class P2, R F(P1, P2)> -struct ConvertParams<BoundFunc2<R, P1, P2, F> > { - typedef Func2<R, void *, const void *, CastHandlerData2<R, P1, P2, F> > Func; +template <class R, class P1, class P2, R F(P1, P2), class I> +struct ConvertParams<BoundFunc2<R, P1, P2, F, I> > { + typedef Func2<R, void *, const void *, CastHandlerData2<R, P1, P2, F>, I> + Func; }; -template <class R, class P1, class P2, class P3, R F(P1, P2, P3)> -struct ConvertParams<BoundFunc3<R, P1, P2, P3, F> > { +template <class R, class P1, class P2, class P3, R F(P1, P2, P3), class I> +struct ConvertParams<BoundFunc3<R, P1, P2, P3, F, I> > { typedef typename CanonicalType<P3>::Type CanonicalP3; typedef Func3<R, void *, const void *, CanonicalP3, - CastHandlerData3<R, P1, P2, CanonicalP3, P3, F> > Func; + CastHandlerData3<R, P1, P2, CanonicalP3, P3, F>, I> Func; }; -template <class R, class P1, class P2, class P3, class P4, R F(P1, P2, P3, P4)> -struct ConvertParams<BoundFunc4<R, P1, P2, P3, P4, F> > { - typedef Func4<R, void *, const void *, P3, P4, - CastHandlerData4<R, P1, P2, P3, P4, F> > Func; +// For StringBuffer only; this ignores the BufferHandle. +template <class R, class P1, class P2, R F(P1, P2, const char *, size_t), + class I> +struct ConvertParams<BoundFunc4<R, P1, P2, const char *, size_t, F, I> > { + typedef Func5<R, void *, const void *, const char *, size_t, + const BufferHandle *, CastHandlerDataIgnoreHandle<R, P1, P2, F>, + I> Func; +}; + +template <class R, class P1, class P2, class P3, class P4, class P5, + R F(P1, P2, P3, P4, P5), class I> +struct ConvertParams<BoundFunc5<R, P1, P2, P3, P4, P5, F, I> > { + typedef Func5<R, void *, const void *, P3, P4, P5, + CastHandlerData5<R, P1, P2, P3, P4, P5, F>, I> Func; }; // utype/ltype are upper/lower-case, ctype is canonical C type, vtype is @@ -659,6 +863,16 @@ struct ReturnOf<R (*)(P1, P2, P3, P4)> { typedef R Return; }; +template <class R, class P1, class P2, class P3, class P4, class P5> +struct ReturnOf<R (*)(P1, P2, P3, P4, P5)> { + typedef R Return; +}; + +template<class T> const void *UniquePtrForType() { + static const char ch = 0; + return &ch; +} + template <class T> template <class F> inline Handler<T>::Handler(F func) @@ -669,6 +883,25 @@ inline Handler<T>::Handler(F func) typedef typename MaybeWrapReturn<ConvertedParamsFunc, Return>::Func ReturnWrappedFunc; handler_ = ReturnWrappedFunc().Call; + + // Set attributes based on what templates can statically tell us about the + // user's function. + + // If the original function returns void, then we know that we wrapped it to + // always return ok. + bool always_ok = is_same<typename F::FuncInfo::Return, void>::value; + attr_.SetAlwaysOk(always_ok); + + // Closure parameter and return type. + attr_.SetClosureType(UniquePtrForType<typename F::FuncInfo::Closure>()); + + // We use the closure type (from the first parameter) if the return type is + // void. This is all nonsense for non START* handlers, but it doesn't matter + // because in that case the value will be ignored. + typedef typename FirstUnlessVoid<typename F::FuncInfo::Return, + typename F::FuncInfo::Closure>::value + EffectiveReturn; + attr_.SetReturnClosureType(UniquePtrForType<EffectiveReturn>()); } template <class T> @@ -682,6 +915,49 @@ inline bool HandlerAttributes::SetHandlerData(void *hd, upb_handlerfree *cleanup) { return upb_handlerattr_sethandlerdata(this, hd, cleanup); } +inline const void* HandlerAttributes::handler_data() const { + return upb_handlerattr_handlerdata(this); +} +inline bool HandlerAttributes::SetClosureType(const void *type) { + return upb_handlerattr_setclosuretype(this, type); +} +inline const void* HandlerAttributes::closure_type() const { + return upb_handlerattr_closuretype(this); +} +inline bool HandlerAttributes::SetReturnClosureType(const void *type) { + return upb_handlerattr_setreturnclosuretype(this, type); +} +inline const void* HandlerAttributes::return_closure_type() const { + return upb_handlerattr_returnclosuretype(this); +} +inline bool HandlerAttributes::SetAlwaysOk(bool always_ok) { + return upb_handlerattr_setalwaysok(this, always_ok); +} +inline bool HandlerAttributes::always_ok() const { + return upb_handlerattr_alwaysok(this); +} + +inline BufferHandle::BufferHandle() { upb_bufhandle_init(this); } +inline BufferHandle::~BufferHandle() { upb_bufhandle_uninit(this); } +inline const char* BufferHandle::buffer() const { + return upb_bufhandle_buf(this); +} +inline size_t BufferHandle::object_offset() const { + return upb_bufhandle_objofs(this); +} +inline void BufferHandle::SetBuffer(const char* buf, size_t ofs) { + upb_bufhandle_setbuf(this, buf, ofs); +} +template <class T> +void BufferHandle::SetAttachedObject(const T* obj) { + upb_bufhandle_setobj(this, obj, UniquePtrForType<T>()); +} +template <class T> +const T* BufferHandle::GetAttachedObject() const { + return upb_bufhandle_objtype(this) == UniquePtrForType<T>() + ? static_cast<const T *>(upb_bufhandle_obj(this)) + : NULL; +} inline reffed_ptr<Handlers> Handlers::New(const MessageDef *m) { upb_handlers *h = upb_handlers_new(m, &h); @@ -803,10 +1079,19 @@ inline const void *Handlers::GetHandlerData(Handlers::Selector selector) { return upb_handlers_gethandlerdata(this, selector); } +inline BytesHandler::BytesHandler() { + upb_byteshandler_init(this); +} + +inline BytesHandler::~BytesHandler() { + upb_byteshandler_uninit(this); +} + } // namespace upb #endif // __cplusplus + #undef UPB_TWO_32BIT_TYPES #undef UPB_TWO_64BIT_TYPES #undef UPB_INT32_T diff --git a/upb/handlers.c b/upb/handlers.c index baa3e06..006ff83 100644 --- a/upb/handlers.c +++ b/upb/handlers.c @@ -92,8 +92,8 @@ oom: // The selector for a submessage field is the field index. #define SUBH_F(h, f) SUBH(h, f->index_) -static int32_t getsel(upb_handlers *h, const upb_fielddef *f, - upb_handlertype_t type) { +static int32_t trygetsel(upb_handlers *h, const upb_fielddef *f, + upb_handlertype_t type) { upb_selector_t sel; assert(!upb_handlers_isfrozen(h)); if (upb_handlers_msgdef(h) != upb_fielddef_containingtype(f)) { @@ -112,7 +112,20 @@ static int32_t getsel(upb_handlers *h, const upb_fielddef *f, return sel; } -static bool doset(upb_handlers *h, int32_t sel, upb_func *func, +static upb_selector_t getsel(upb_handlers *h, const upb_fielddef *f, + upb_handlertype_t type) { + int32_t sel = trygetsel(h, f, type); + assert(sel >= 0); + return sel; +} + +static const void **returntype(upb_handlers *h, const upb_fielddef *f, + upb_handlertype_t type) { + return &h->table[getsel(h, f, type)].attr.return_closure_type_; +} + +static bool doset(upb_handlers *h, int32_t sel, const upb_fielddef *f, + upb_handlertype_t type, upb_func *func, upb_handlerattr *attr) { assert(!upb_handlers_isfrozen(h)); @@ -133,11 +146,103 @@ static bool doset(upb_handlers *h, int32_t sel, upb_func *func, set_attr = *attr; } + // Check that the given closure type matches the closure type that has been + // established for this context (if any). + const void *closure_type = upb_handlerattr_closuretype(&set_attr); + const void **context_closure_type; + + if (type == UPB_HANDLER_STRING) { + context_closure_type = returntype(h, f, UPB_HANDLER_STARTSTR); + } else if (f && upb_fielddef_isseq(f) && + type != UPB_HANDLER_STARTSEQ && + type != UPB_HANDLER_ENDSEQ) { + context_closure_type = returntype(h, f, UPB_HANDLER_STARTSEQ); + } else { + context_closure_type = &h->top_closure_type; + } + + if (closure_type && *context_closure_type && + closure_type != *context_closure_type) { + // TODO(haberman): better message for debugging. + upb_status_seterrmsg(&h->status_, "closure type does not match"); + return false; + } + + if (closure_type) + *context_closure_type = closure_type; + + // If this is a STARTSEQ or STARTSTR handler, check that the returned pointer + // matches any pre-existing expectations about what type is expected. + if (type == UPB_HANDLER_STARTSEQ || type == UPB_HANDLER_STARTSTR) { + const void *return_type = upb_handlerattr_returnclosuretype(&set_attr); + const void *table_return_type = + upb_handlerattr_returnclosuretype(&h->table[sel].attr); + if (return_type && table_return_type && return_type != table_return_type) { + upb_status_seterrmsg(&h->status_, "closure return type does not match"); + return false; + } + + if (table_return_type && !return_type) + upb_handlerattr_setreturnclosuretype(&set_attr, table_return_type); + } + h->table[sel].func = (upb_func*)func; h->table[sel].attr = set_attr; return true; } +// Returns the effective closure type for this handler (which will propagate +// from outer frames if this frame has no START* handler). Not implemented for +// UPB_HANDLER_STRING at the moment since this is not needed. Returns NULL is +// the effective closure type is unspecified (either no handler was registered +// to specify it or the handler that was registered did not specify the closure +// type). +const void *effective_closure_type(upb_handlers *h, const upb_fielddef *f, + upb_handlertype_t type) { + assert(type != UPB_HANDLER_STRING); + const void *ret = h->top_closure_type; + upb_selector_t sel; + if (upb_fielddef_isseq(f) && + type != UPB_HANDLER_STARTSEQ && + type != UPB_HANDLER_ENDSEQ && + h->table[sel = getsel(h, f, UPB_HANDLER_STARTSEQ)].func) { + ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr); + } + + if (type == UPB_HANDLER_STRING && + h->table[sel = getsel(h, f, UPB_HANDLER_STARTSTR)].func) { + ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr); + } + + // The effective type of the submessage; not used yet. + // if (type == SUBMESSAGE && + // h->table[sel = getsel(h, f, UPB_HANDLER_STARTSUBMSG)].func) { + // ret = upb_handlerattr_returnclosuretype(&h->table[sel].attr); + // } + + return ret; +} + +// Checks whether the START* handler specified by f & type is missing even +// though it is required to convert the established type of an outer frame +// ("closure_type") into the established type of an inner frame (represented in +// the return closure type of this handler's attr. +bool checkstart(upb_handlers *h, const upb_fielddef *f, upb_handlertype_t type, + upb_status *status) { + upb_selector_t sel = getsel(h, f, type); + if (h->table[sel].func) return true; + const void *closure_type = effective_closure_type(h, f, type); + const upb_handlerattr *attr = &h->table[sel].attr; + const void *return_closure_type = upb_handlerattr_returnclosuretype(attr); + if (closure_type && return_closure_type && + closure_type != return_closure_type) { + upb_status_seterrf(status, + "expected start handler to return sub type for field %f", + upb_fielddef_name(f)); + return false; + } + return true; +} /* Public interface ***********************************************************/ @@ -218,8 +323,8 @@ void upb_handlers_clearerr(upb_handlers *h) { #define SETTER(name, handlerctype, handlertype) \ bool upb_handlers_set ## name(upb_handlers *h, const upb_fielddef *f, \ handlerctype func, upb_handlerattr *attr) { \ - int32_t sel = getsel(h, f, handlertype); \ - return doset(h, sel, (upb_func*)func, attr); \ + int32_t sel = trygetsel(h, f, handlertype); \ + return doset(h, sel, f, handlertype, (upb_func*)func, attr); \ } SETTER(int32, upb_int32_handlerfunc*, UPB_HANDLER_INT32); @@ -241,13 +346,15 @@ SETTER(endseq, upb_endfield_handlerfunc*, UPB_HANDLER_ENDSEQ); bool upb_handlers_setstartmsg(upb_handlers *h, upb_startmsg_handlerfunc *func, upb_handlerattr *attr) { - return doset(h, UPB_STARTMSG_SELECTOR, (upb_func*)func, attr); + return doset(h, UPB_STARTMSG_SELECTOR, NULL, UPB_HANDLER_INT32, + (upb_func *)func, attr); } bool upb_handlers_setendmsg(upb_handlers *h, upb_endmsg_handlerfunc *func, upb_handlerattr *attr) { assert(!upb_handlers_isfrozen(h)); - return doset(h, UPB_ENDMSG_SELECTOR, (upb_func*)func, attr); + return doset(h, UPB_ENDMSG_SELECTOR, NULL, UPB_HANDLER_INT32, + (upb_func *)func, attr); } bool upb_handlers_setsubhandlers(upb_handlers *h, const upb_fielddef *f, @@ -270,6 +377,14 @@ const upb_handlers *upb_handlers_getsubhandlers(const upb_handlers *h, return SUBH_F(h, f); } +bool upb_handlers_getattr(const upb_handlers *h, upb_selector_t sel, + upb_handlerattr *attr) { + if (!upb_handlers_gethandler(h, sel)) + return false; + *attr = h->table[sel].attr; + return true; +} + const upb_handlers *upb_handlers_getsubhandlers_sel(const upb_handlers *h, upb_selector_t sel) { // STARTSUBMSG selector in sel is the field's selector base. @@ -284,12 +399,37 @@ const upb_msgdef *upb_handlers_msgdef(const upb_handlers *h) { return h->msg; } bool upb_handlers_freeze(upb_handlers *const*handlers, int n, upb_status *s) { // TODO: verify we have a transitive closure. for (int i = 0; i < n; i++) { - if (!upb_ok(&handlers[i]->status_)) { + upb_handlers *h = handlers[i]; + + if (!upb_ok(&h->status_)) { upb_status_seterrf(s, "handlers for message %s had error status: %s", - upb_msgdef_fullname(upb_handlers_msgdef(handlers[i])), - upb_status_errmsg(&handlers[i]->status_)); + upb_msgdef_fullname(upb_handlers_msgdef(h)), + upb_status_errmsg(&h->status_)); return false; } + + // Check that there are no closure mismatches due to missing Start* handlers + // or subhandlers with different type-level types. + upb_msg_iter j; + for(upb_msg_begin(&j, h->msg); !upb_msg_done(&j); upb_msg_next(&j)) { + + const upb_fielddef *f = upb_msg_iter_field(&j); + if (upb_fielddef_isseq(f)) { + if (!checkstart(h, f, UPB_HANDLER_STARTSEQ, s)) + return false; + } + + if (upb_fielddef_isstring(f)) { + if (!checkstart(h, f, UPB_HANDLER_STARTSTR, s)) + return false; + } + + if (upb_fielddef_issubmsg(f)) { + // TODO(haberman): check type of submessage. + // This is slightly tricky; also consider whether we should check that + // they match at setsubhandlers time. + } + } } if (!upb_refcounted_freeze((upb_refcounted*const*)handlers, n, s, @@ -394,13 +534,44 @@ void upb_handlerattr_uninit(upb_handlerattr *attr) { bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, void *hd, upb_handlerfree *cleanup) { - if (attr->handler_data_) - return false; attr->handler_data_ = hd; attr->cleanup = cleanup; return true; } +bool upb_handlerattr_setclosuretype(upb_handlerattr *attr, const void *type) { + attr->closure_type_ = type; + return true; +} + +const void *upb_handlerattr_closuretype(const upb_handlerattr *attr) { + return attr->closure_type_; +} + +bool upb_handlerattr_setreturnclosuretype(upb_handlerattr *attr, + const void *type) { + attr->return_closure_type_ = type; + return true; +} + +const void *upb_handlerattr_returnclosuretype(const upb_handlerattr *attr) { + return attr->return_closure_type_; +} + +bool upb_handlerattr_setalwaysok(upb_handlerattr *attr, bool alwaysok) { + attr->alwaysok_ = alwaysok; + return true; +} + +bool upb_handlerattr_alwaysok(const upb_handlerattr *attr) { + return attr->alwaysok_; +} + +/* upb_bufhandle **************************************************************/ + +size_t upb_bufhandle_objofs(const upb_bufhandle *h) { + return h->objofs_; +} /* upb_byteshandler ***********************************************************/ diff --git a/upb/handlers.h b/upb/handlers.h index ceb559f..a03c99e 100644 --- a/upb/handlers.h +++ b/upb/handlers.h @@ -27,18 +27,26 @@ #ifdef __cplusplus namespace upb { +class BufferHandle; +class BytesHandler; class HandlerAttributes; class Handlers; template <class T> class Handler; template <class T> struct CanonicalType; } // namespace upb +typedef upb::BufferHandle upb_bufhandle; +typedef upb::BytesHandler upb_byteshandler; typedef upb::HandlerAttributes upb_handlerattr; typedef upb::Handlers upb_handlers; #else +struct upb_bufhandle; +struct upb_byteshandler; struct upb_handlerattr; struct upb_handlers; struct upb_sinkframe; +typedef struct upb_bufhandle upb_bufhandle; +typedef struct upb_byteshandler upb_byteshandler; typedef struct upb_handlerattr upb_handlerattr; typedef struct upb_handlers upb_handlers; typedef struct upb_sinkframe upb_sinkframe; @@ -89,12 +97,23 @@ typedef void upb_func(); extern "C" { #endif +// Forward-declares for C inline accessors. We need to declare these here +// so we can "friend" them in the class declarations in C++. UPB_INLINE upb_func *upb_handlers_gethandler(const upb_handlers *h, upb_selector_t s); UPB_INLINE const void *upb_handlerattr_handlerdata(const upb_handlerattr *attr); UPB_INLINE const void *upb_handlers_gethandlerdata(const upb_handlers *h, upb_selector_t s); +UPB_INLINE void upb_bufhandle_init(upb_bufhandle *h); +UPB_INLINE void upb_bufhandle_setobj(upb_bufhandle *h, const void *obj, + const void *type); +UPB_INLINE void upb_bufhandle_setbuf(upb_bufhandle *h, const char *buf, + size_t ofs); +UPB_INLINE const void *upb_bufhandle_obj(const upb_bufhandle *h); +UPB_INLINE const void *upb_bufhandle_objtype(const upb_bufhandle *h); +UPB_INLINE const char *upb_bufhandle_buf(const upb_bufhandle *h); + #ifdef __cplusplus } #endif @@ -114,6 +133,7 @@ typedef void upb_handlerfree(void *d); #ifdef __cplusplus +// A set of attributes that accompanies a handler's function pointer. class upb::HandlerAttributes { public: HandlerAttributes(); @@ -126,7 +146,27 @@ class upb::HandlerAttributes { // cleanup handler will be called once for each handler it was successfully // set on. bool SetHandlerData(void *handler_data, upb_handlerfree *cleanup); - void *handler_data() const; + const void* handler_data() const; + + // Use this to specify the type of the closure. This will be checked against + // all other closure types for handler that use the same closure. + // Registration will fail if this does not match all other non-NULL closure + // types. + bool SetClosureType(const void *closure_type); + const void* closure_type() const; + + // Use this to specify the type of the returned closure. Only used for + // Start*{String,SubMessage,Sequence} handlers. This must match the closure + // type of any handlers that use it (for example, the StringBuf handler must + // match the closure returned from StartString). + bool SetReturnClosureType(const void *return_closure_type); + const void* return_closure_type() const; + + // Set to indicate that the handler always returns "ok" (either "true" or a + // non-NULL closure). This is a hint that can allow code generators to + // generate more efficient code. + bool SetAlwaysOk(bool always_ok); + bool always_ok() const; private: friend UPB_INLINE const void * ::upb_handlerattr_handlerdata( @@ -137,15 +177,81 @@ struct upb_handlerattr { #endif void *handler_data_; upb_handlerfree *cleanup; + const void *closure_type_; + const void *return_closure_type_; + bool alwaysok_; }; +#define UPB_HANDLERATTR_INITIALIZER {NULL, NULL, NULL, NULL, false} + typedef struct { upb_func *func; + // It is wasteful to include the entire attributes here: + // + // * Some of the information is redundant (like storing the closure type + // separately for each handler that must match). + // * Some of the info is only needed prior to freeze() (like closure types). + // * alignment padding wastes a lot of space for alwaysok_. + // + // If/when the size and locality of handlers is an issue, we can optimize this + // not to store the entire attr like this. We do not expose the table's + // layout to allow this optimization in the future. upb_handlerattr attr; } upb_handlers_tabent; #ifdef __cplusplus +// Extra information about a buffer that is passed to a StringBuf handler. +// TODO(haberman): allow the handle to be pinned so that it will outlive +// the handler invocation. +class upb::BufferHandle { + public: + BufferHandle(); + ~BufferHandle(); + + // The beginning of the buffer. This may be different than the pointer + // passed to a StringBuf handler because the handler may receive data + // that is from the middle or end of a larger buffer. + const char* buffer() const; + + // The offset within the attached object where this buffer begins. Only + // meaningful if there is an attached object. + size_t object_offset() const; + + // Note that object_offset is the offset of "buf" within the attached object. + void SetBuffer(const char* buf, size_t object_offset); + + // The BufferHandle can have an "attached object", which can be used to + // tunnel through a pointer to the buffer's underlying representation. + template <class T> + void SetAttachedObject(const T* obj); + + // Returns NULL if the attached object is not of this type. + template <class T> + const T* GetAttachedObject() const; + + private: + friend UPB_INLINE void ::upb_bufhandle_init(upb_bufhandle *h); + friend UPB_INLINE void ::upb_bufhandle_setobj(upb_bufhandle *h, + const void *obj, + const void *type); + friend UPB_INLINE void ::upb_bufhandle_setbuf(upb_bufhandle *h, + const char *buf, size_t ofs); + friend UPB_INLINE const void* ::upb_bufhandle_obj(const upb_bufhandle *h); + friend UPB_INLINE const void* ::upb_bufhandle_objtype( + const upb_bufhandle *h); + friend UPB_INLINE const char* ::upb_bufhandle_buf(const upb_bufhandle *h); +#else +struct upb_bufhandle { +#endif + const char *buf_; + const void *obj_; + const void *objtype_; + size_t objofs_; +}; + +#ifdef __cplusplus + // A upb::Handlers object represents the set of handlers associated with a // message in the graph of messages. You can think of it as a big virtual // table with functions corresponding to all the events that can fire while @@ -167,8 +273,8 @@ class upb::Handlers { typedef Handler<bool (*)(void *, const void *)> StartMessageHandler; typedef Handler<bool (*)(void *, const void *, Status*)> EndMessageHandler; typedef Handler<void *(*)(void *, const void *, size_t)> StartStringHandler; - typedef Handler<size_t(*)(void *, const void *, const char *, size_t)> - StringHandler; + typedef Handler<size_t (*)(void *, const void *, const char *, size_t, + const BufferHandle *)> StringHandler; template <class T> struct ValueHandler { typedef Handler<bool(*)(void *, const void *, T)> H; @@ -224,7 +330,7 @@ class upb::Handlers { // Freezes the given set of handlers. You may not freeze a handler without // also freezing any handlers they point to. static bool Freeze(Handlers*const* handlers, int n, Status* s); - static bool Freeze(const vector<Handlers*>& handlers, Status* s); + static bool Freeze(const std::vector<Handlers*>& handlers, Status* s); // Returns the msgdef associated with this handlers object. const MessageDef* message_def() const; @@ -401,6 +507,9 @@ class upb::Handlers { // responsibility to cast to the correct function type before calling it. GenericFunction* GetHandler(Selector selector); + // Sets the given attributes to the attributes for this selector. + bool GetAttributes(Selector selector, HandlerAttributes* attr); + // Returns the handler data that was registered with this handler. const void* GetHandlerData(Selector selector); @@ -424,6 +533,7 @@ struct upb_handlers { upb_refcounted base; const upb_msgdef *msg; const upb_handlers **sub; + const void *top_closure_type; upb_status status_; // Used only when mutable. upb_handlers_tabent table[1]; // Dynamically-sized field handler array. }; @@ -538,31 +648,38 @@ typedef bool upb_bool_handlerfunc(void *c, const void *hd, bool val); typedef void *upb_startstr_handlerfunc(void *c, const void *hd, size_t size_hint); typedef size_t upb_string_handlerfunc(void *c, const void *hd, const char *buf, - size_t n); -// upb_handlerattr -#define UPB_HANDLERATTR_INITIALIZER {NULL, NULL} + size_t n, const upb_bufhandle* handle); +// upb_bufhandle +size_t upb_bufhandle_objofs(const upb_bufhandle *h); + +// upb_handlerattr void upb_handlerattr_init(upb_handlerattr *attr); void upb_handlerattr_uninit(upb_handlerattr *attr); bool upb_handlerattr_sethandlerdata(upb_handlerattr *attr, void *hd, upb_handlerfree *cleanup); +bool upb_handlerattr_setclosuretype(upb_handlerattr *attr, const void *type); +const void *upb_handlerattr_closuretype(const upb_handlerattr *attr); +bool upb_handlerattr_setreturnclosuretype(upb_handlerattr *attr, + const void *type); +const void *upb_handlerattr_returnclosuretype(const upb_handlerattr *attr); +bool upb_handlerattr_setalwaysok(upb_handlerattr *attr, bool alwaysok); +bool upb_handlerattr_alwaysok(const upb_handlerattr *attr); + UPB_INLINE const void *upb_handlerattr_handlerdata( const upb_handlerattr *attr) { return attr->handler_data_; } -typedef void upb_handlers_callback(void *closure, upb_handlers *h); - // upb_handlers +typedef void upb_handlers_callback(void *closure, upb_handlers *h); upb_handlers *upb_handlers_new(const upb_msgdef *m, const void *owner); const upb_handlers *upb_handlers_newfrozen(const upb_msgdef *m, const void *owner, upb_handlers_callback *callback, void *closure); - -// From upb_refcounted. bool upb_handlers_isfrozen(const upb_handlers *h); void upb_handlers_ref(const upb_handlers *h, const void *owner); void upb_handlers_unref(const upb_handlers *h, const void *owner); @@ -630,17 +747,32 @@ UPB_INLINE upb_func *upb_handlers_gethandler(const upb_handlers *h, return (upb_func *)h->table[s].func; } +bool upb_handlers_getattr(const upb_handlers *h, upb_selector_t s, + upb_handlerattr *attr); + UPB_INLINE const void *upb_handlers_gethandlerdata(const upb_handlers *h, upb_selector_t s) { return upb_handlerattr_handlerdata(&h->table[s].attr); } +#ifdef __cplusplus + // Handler types for single fields. // Right now we only have one for TYPE_BYTES but ones for other types // should follow. // // These follow the same handlers protocol for fields of a message. -typedef struct { upb_handlers_tabent table[3]; } upb_byteshandler; +class upb::BytesHandler { + public: + BytesHandler(); + ~BytesHandler(); + + // TODO(haberman): make private and figure out what to friend. +#else +struct upb_byteshandler { +#endif + upb_handlers_tabent table[3]; +}; void upb_byteshandler_init(upb_byteshandler *h); void upb_byteshandler_uninit(upb_byteshandler *h); @@ -659,7 +791,7 @@ bool upb_byteshandler_setendstr(upb_byteshandler *h, #ifdef __cplusplus namespace upb { -typedef upb_byteshandler BytesHandler; +typedef upb_byteshandler BytesHandler; } #endif diff --git a/upb/pb/compile_decoder_x64.c b/upb/pb/compile_decoder_x64.c index 429f690..44331b8 100644 --- a/upb/pb/compile_decoder_x64.c +++ b/upb/pb/compile_decoder_x64.c @@ -56,8 +56,6 @@ typedef struct { // Used by DynASM to store globals. void **globals; - - bool chkret; } jitcompiler; // Functions called by codegen. @@ -72,7 +70,6 @@ static int pcofs(jitcompiler* jc); static jitcompiler *newjitcompiler(mgroup *group) { jitcompiler *jc = malloc(sizeof(jitcompiler)); - jc->chkret = false; jc->group = group; jc->pclabel_count = 0; jc->lastlabelofs = -1; diff --git a/upb/pb/compile_decoder_x64.dasc b/upb/pb/compile_decoder_x64.dasc index fec822a..571aa9b 100644 --- a/upb/pb/compile_decoder_x64.dasc +++ b/upb/pb/compile_decoder_x64.dasc @@ -23,6 +23,7 @@ |.define ARG3_32, edx |.define ARG3_64, rdx |.define ARG4_64, rcx +|.define ARG5_64, r8 |.define XMMARG1, xmm0 | |// Register allocation / type map. @@ -159,6 +160,16 @@ static upb_func *gethandler(const upb_handlers *h, upb_selector_t sel) { return h ? upb_handlers_gethandler(h, sel) : NULL; } +// Should only be called when the associated handler is known to exist. +static bool alwaysok(const upb_handlers *h, upb_selector_t sel) { + upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; + bool ok = upb_handlers_getattr(h, sel, &attr); + UPB_ASSERT_VAR(ok, ok); + bool ret = upb_handlerattr_alwaysok(&attr); + upb_handlerattr_uninit(&attr); + return ret; +} + // Emit static assembly routines; code that does not vary based on the message // schema. Since it's not input-dependent, we only need one single copy of it. // For the moment we generate a single copy per generated handlers. Eventually @@ -623,9 +634,9 @@ static void jitprimitive(jitcompiler *jc, opcode op, | mov ARG1_64, CLOSURE | load_handler_data h, sel | callp handler - if (jc->chkret) { + if (!alwaysok(h, sel)) { | test al, al - | jz >5 + | jnz >5 | call ->suspend | jmp <1 |5: @@ -887,10 +898,11 @@ static void jitbytecode(jitcompiler *jc) { | mov ARG1_64, CLOSURE | load_handler_data h, UPB_STARTMSG_SELECTOR | callp startmsg - if (jc->chkret) { + if (!alwaysok(h, UPB_STARTMSG_SELECTOR)) { | test al, al - | jnz <2 + | jnz >2 | call ->suspend + | jmp <1 |2: } } @@ -960,7 +972,7 @@ static void jitbytecode(jitcompiler *jc) { | sub ARG3_64, PTR } | callp start - if (jc->chkret) { + if (!alwaysok(h, arg)) { | test rax, rax | jnz >2 | call ->suspend @@ -986,7 +998,7 @@ static void jitbytecode(jitcompiler *jc) { | mov ARG1_64, CLOSURE | load_handler_data h, arg | callp end - if (jc->chkret) { + if (!alwaysok(h, arg)) { | test al, al | jnz >2 | call ->suspend @@ -1016,9 +1028,10 @@ static void jitbytecode(jitcompiler *jc) { | mov ARG3_64, PTR | mov ARG4_64, DATAEND | sub ARG4_64, PTR + | mov ARG5_64, qword DECODER->handle | callp str | add PTR, rax - if (jc->chkret) { + if (!alwaysok(h, arg)) { | cmp PTR, DATAEND | je >3 | call ->strret_fallback diff --git a/upb/pb/decoder.c b/upb/pb/decoder.c index 6fd6576..c5fae0e 100644 --- a/upb/pb/decoder.c +++ b/upb/pb/decoder.c @@ -148,10 +148,11 @@ static void checkpoint(upb_pbdecoder *d) { // Resumes the decoder from an initial state or from a previous suspend. void *upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf, - size_t size) { + size_t size, const upb_bufhandle *handle) { UPB_UNUSED(p); // Useless; just for the benefit of the JIT. d->buf_param = buf; d->size_param = size; + d->handle = handle; d->skip = 0; if (d->residual_end > d->residual) { // We have residual bytes from the last buffer. @@ -488,11 +489,11 @@ upb_pbdecoder_frame *outer_frame(upb_pbdecoder *d) { /* The main decoding loop *****************************************************/ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, - size_t size) { + size_t size, const upb_bufhandle *handle) { upb_pbdecoder *d = closure; const mgroup *group = hd; assert(buf); - upb_pbdecoder_resume(d, NULL, buf, size); + upb_pbdecoder_resume(d, NULL, buf, size, handle); UPB_UNUSED(group); #define VMCASE(op, code) \ @@ -578,7 +579,8 @@ size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, ) VMCASE(OP_STRING, uint32_t len = curbufleft(d); - CHECK_SUSPEND(upb_sink_putstring(&d->top->sink, arg, ptr(d), len)); + CHECK_SUSPEND( + upb_sink_putstring(&d->top->sink, arg, ptr(d), len, handle)); advance(d, len); if (d->delim_end == NULL) { // String extends beyond this buf? d->pc--; @@ -683,6 +685,7 @@ void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint) { void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint) { UPB_UNUSED(hd); + UPB_UNUSED(size_hint); upb_pbdecoder *d = closure; d->call_len = 0; return d; @@ -712,7 +715,7 @@ bool upb_pbdecoder_end(void *closure, const void *handler_data) { if (group->jit_code) { if (d->top != d->stack) d->stack->end_ofs = 0; - group->jit_code(closure, method->code_base.ptr, &dummy, 0); + group->jit_code(closure, method->code_base.ptr, &dummy, 0, NULL); } else { #endif d->stack->end_ofs = end; @@ -726,7 +729,7 @@ bool upb_pbdecoder_end(void *closure, const void *handler_data) { getop(*d->pc) == OP_TAGN); d->pc = p; } - upb_pbdecoder_decode(closure, handler_data, &dummy, 0); + upb_pbdecoder_decode(closure, handler_data, &dummy, 0, NULL); #ifdef UPB_USE_JIT_X64 } #endif @@ -762,7 +765,9 @@ void upb_pbdecoder_reset(upb_pbdecoder *d) { // Not currently required, but to support outgrowing the static stack we need // this. -void upb_pbdecoder_uninit(upb_pbdecoder *d) {} +void upb_pbdecoder_uninit(upb_pbdecoder *d) { + UPB_UNUSED(d); +} const upb_pbdecodermethod *upb_pbdecoder_method(const upb_pbdecoder *d) { return d->method_; diff --git a/upb/pb/decoder.h b/upb/pb/decoder.h index 4529324..4313bb3 100644 --- a/upb/pb/decoder.h +++ b/upb/pb/decoder.h @@ -234,6 +234,7 @@ struct upb_pbdecoder { // Stores the user buffer passed to our decode function. const char *buf_param; size_t size_param; + const upb_bufhandle *handle; #ifdef UPB_USE_JIT_X64 // Used momentarily by the generated code to store a value while a user diff --git a/upb/pb/decoder.int.h b/upb/pb/decoder.int.h index 1c10eb3..20afa68 100644 --- a/upb/pb/decoder.int.h +++ b/upb/pb/decoder.int.h @@ -108,12 +108,12 @@ typedef struct { void *upb_pbdecoder_startbc(void *closure, const void *pc, size_t size_hint); void *upb_pbdecoder_startjit(void *closure, const void *hd, size_t size_hint); size_t upb_pbdecoder_decode(void *closure, const void *hd, const char *buf, - size_t size); + size_t size, const upb_bufhandle *handle); bool upb_pbdecoder_end(void *closure, const void *handler_data); // Decoder-internal functions that the JIT calls to handle fallback paths. void *upb_pbdecoder_resume(upb_pbdecoder *d, void *p, const char *buf, - size_t size); + size_t size, const upb_bufhandle *handle); size_t upb_pbdecoder_suspend(upb_pbdecoder *d); int32_t upb_pbdecoder_skipunknown(upb_pbdecoder *d, uint32_t fieldnum, uint8_t wire_type); diff --git a/upb/pb/textprinter.c b/upb/pb/textprinter.c index 0c12571..8a49c73 100644 --- a/upb/pb/textprinter.c +++ b/upb/pb/textprinter.c @@ -3,6 +3,9 @@ * * Copyright (c) 2009 Google Inc. See LICENSE for details. * Author: Josh Haberman <jhaberman@gmail.com> + * + * OPT: This is not optimized at all. It uses printf() which parses the format + * string every time, and it allocates memory for every put. */ #include "upb/pb/textprinter.h" @@ -16,29 +19,29 @@ #include "upb/sink.h" -struct _upb_textprinter { - int indent_depth; - bool single_line; - upb_status status; -}; - #define CHECK(x) if ((x) < 0) goto err; +static const char *shortname(const char *longname) { + const char *last = strrchr(longname, '.'); + return last ? last + 1 : longname; +} + static int indent(upb_textprinter *p) { int i; - if (!p->single_line) - for (i = 0; i < p->indent_depth * 2; i++) - putchar(' '); + if (!p->single_line_) + for (i = 0; i < p->indent_depth_; i++) + upb_bytessink_putbuf(p->output_, p->subc, " ", 2, NULL); return 0; - return -1; } static int endfield(upb_textprinter *p) { - putchar(p->single_line ? ' ' : '\n'); + const char ch = (p->single_line_ ? ' ' : '\n'); + upb_bytessink_putbuf(p->output_, p->subc, &ch, 1, NULL); return 0; } -static int putescaped(const char* buf, size_t len, bool preserve_utf8) { +static int putescaped(upb_textprinter *p, const char *buf, size_t len, + bool preserve_utf8) { // Based on CEscapeInternal() from Google's protobuf release. char dstbuf[4096], *dst = dstbuf, *dstend = dstbuf + sizeof(dstbuf); const char *end = buf + len; @@ -50,7 +53,7 @@ static int putescaped(const char* buf, size_t len, bool preserve_utf8) { for (; buf < end; buf++) { if (dstend - dst < 4) { - fwrite(dstbuf, dst - dstbuf, 1, stdout); + upb_bytessink_putbuf(p->output_, p->subc, dstbuf, dst - dstbuf, NULL); dst = dstbuf; } @@ -78,18 +81,57 @@ static int putescaped(const char* buf, size_t len, bool preserve_utf8) { last_hex_escape = is_hex_escape; } // Flush remaining data. - fwrite(dst, dst - dstbuf, 1, stdout); + upb_bytessink_putbuf(p->output_, p->subc, dstbuf, dst - dstbuf, NULL); return 0; } +bool putf(upb_textprinter *p, const char *fmt, ...) { + va_list args; + va_start(args, fmt); + + // Run once to get the length of the string. + va_list args_copy; + va_copy(args_copy, args); + int len = vsnprintf(NULL, 0, fmt, args_copy); + va_end(args_copy); + + // + 1 for NULL terminator (vsnprintf() requires it even if we don't). + char *str = malloc(len + 1); + if (!str) return false; + int written = vsnprintf(str, len + 1, fmt, args); + va_end(args); + UPB_ASSERT_VAR(written, written == len); + + bool ok = upb_bytessink_putbuf(p->output_, p->subc, str, len, NULL); + free(str); + return ok; +} + + +/* handlers *******************************************************************/ + +static bool startmsg(void *c, const void *hd) { + upb_textprinter *p = c; + if (p->indent_depth_ == 0) { + upb_bytessink_start(p->output_, 0, &p->subc); + } + return true; +} + +static bool endmsg(void *c, const void *hd, upb_status *s) { + upb_textprinter *p = c; + if (p->indent_depth_ == 0) { + upb_bytessink_end(p->output_); + } + return true; +} + #define TYPE(name, ctype, fmt) \ static bool put ## name(void *closure, const void *handler_data, ctype val) {\ upb_textprinter *p = closure; \ const upb_fielddef *f = handler_data; \ CHECK(indent(p)); \ - puts(upb_fielddef_name(f)); \ - puts(": "); \ - printf(fmt, val); \ + putf(p, "%s: " fmt, upb_fielddef_name(f), val); \ CHECK(endfield(p)); \ return true; \ err: \ @@ -100,9 +142,7 @@ static bool putbool(void *closure, const void *handler_data, bool val) { upb_textprinter *p = closure; const upb_fielddef *f = handler_data; CHECK(indent(p)); - puts(upb_fielddef_name(f)); - puts(": "); - puts(val ? "true" : "false"); + putf(p, "%s: %s", upb_fielddef_name(f), val ? "true" : "false"); CHECK(endfield(p)); return true; err: @@ -121,11 +161,14 @@ TYPE(double, double, "%." STRINGIFY_MACROVAL(DBL_DIG) "g") // Output a symbolic value from the enum if found, else just print as int32. static bool putenum(void *closure, const void *handler_data, int32_t val) { + upb_textprinter *p = closure; const upb_fielddef *f = handler_data; const upb_enumdef *enum_def = upb_downcast_enumdef(upb_fielddef_subdef(f)); const char *label = upb_enumdef_iton(enum_def, val); if (label) { - puts(label); + indent(p); + putf(p, "%s: %s", upb_fielddef_name(f), label); + endfield(p); } else { CHECK(putint32(closure, handler_data, val)); } @@ -136,25 +179,27 @@ err: static void *startstr(void *closure, const void *handler_data, size_t size_hint) { - UPB_UNUSED(handler_data); + const upb_fielddef *f = handler_data; UPB_UNUSED(size_hint); upb_textprinter *p = closure; - putchar('"'); + putf(p, "%s: \"", upb_fielddef_name(f)); return p; } static bool endstr(void *closure, const void *handler_data) { - UPB_UNUSED(closure); UPB_UNUSED(handler_data); - putchar('"'); + upb_textprinter *p = closure; + putf(p, "\""); + endfield(p); return true; } static size_t putstr(void *closure, const void *hd, const char *buf, - size_t len) { - UPB_UNUSED(closure); + size_t len, const upb_bufhandle *handle) { + UPB_UNUSED(handle); + upb_textprinter *p = closure; const upb_fielddef *f = hd; - CHECK(putescaped(buf, len, upb_fielddef_type(f) == UPB_TYPE_STRING)); + CHECK(putescaped(p, buf, len, upb_fielddef_type(f) == UPB_TYPE_STRING)); return len; err: return 0; @@ -162,12 +207,10 @@ err: static void *startsubmsg(void *closure, const void *handler_data) { upb_textprinter *p = closure; - const upb_fielddef *f = handler_data; + const char *name = handler_data; CHECK(indent(p)); - printf("%s {", upb_fielddef_name(f)); - if (!p->single_line) - putchar('\n'); - p->indent_depth++; + putf(p, "%s {%c", name, p->single_line_ ? ' ' : '\n'); + p->indent_depth_++; return p; err: return UPB_BREAK; @@ -176,30 +219,36 @@ err: static bool endsubmsg(void *closure, const void *handler_data) { UPB_UNUSED(handler_data); upb_textprinter *p = closure; - p->indent_depth--; + p->indent_depth_--; CHECK(indent(p)); - putchar('}'); + upb_bytessink_putbuf(p->output_, p->subc, "}", 1, NULL); CHECK(endfield(p)); return true; err: return false; } -upb_textprinter *upb_textprinter_new() { - upb_textprinter *p = malloc(sizeof(*p)); - return p; + +/* Public API *****************************************************************/ + +void upb_textprinter_init(upb_textprinter *p, const upb_handlers *h) { + p->single_line_ = false; + p->indent_depth_ = 0; + upb_sink_reset(&p->input_, h, p); } -void upb_textprinter_free(upb_textprinter *p) { free(p); } +void upb_textprinter_uninit(upb_textprinter *p) {} void upb_textprinter_reset(upb_textprinter *p, bool single_line) { - p->single_line = single_line; - p->indent_depth = 0; + p->single_line_ = single_line; + p->indent_depth_ = 0; } static void onmreg(void *c, upb_handlers *h) { (void)c; const upb_msgdef *m = upb_handlers_msgdef(h); + upb_handlers_setstartmsg(h, startmsg, NULL); + upb_handlers_setendmsg(h, endmsg, NULL); upb_msg_iter i; for(upb_msg_begin(&i, m); !upb_msg_done(&i); upb_msg_next(&i)) { upb_fielddef *f = upb_msg_iter_field(&i); @@ -233,20 +282,37 @@ static void onmreg(void *c, upb_handlers *h) { upb_handlers_setstring(h, f, putstr, &attr); upb_handlers_setendstr(h, f, endstr, &attr); break; - case UPB_TYPE_MESSAGE: + case UPB_TYPE_MESSAGE: { + const char *name = + upb_fielddef_istagdelim(f) + ? shortname(upb_msgdef_fullname(upb_fielddef_msgsubdef(f))) + : upb_fielddef_name(f); + // TODO(haberman): add "setconsthandlerdata"? If we pass NULL for + // cleanup then we don't need a non-const pointer. + upb_handlerattr_sethandlerdata(&attr, (void*)name, NULL); upb_handlers_setstartsubmsg(h, f, startsubmsg, &attr); upb_handlers_setendsubmsg(h, f, endsubmsg, &attr); break; + } case UPB_TYPE_ENUM: upb_handlers_setint32(h, f, putenum, &attr); - default: - assert(false); break; } } } -const upb_handlers *upb_textprinter_newhandlers(const void *owner, - const upb_msgdef *m) { +const upb_handlers *upb_textprinter_newhandlers(const upb_msgdef *m, + const void *owner) { return upb_handlers_newfrozen(m, owner, &onmreg, NULL); } + +upb_sink *upb_textprinter_input(upb_textprinter *p) { return &p->input_; } + +bool upb_textprinter_resetoutput(upb_textprinter *p, upb_bytessink *output) { + p->output_ = output; + return true; +} + +void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line) { + p->single_line_ = single_line; +} diff --git a/upb/pb/textprinter.h b/upb/pb/textprinter.h index 7b653e7..eb3e132 100644 --- a/upb/pb/textprinter.h +++ b/upb/pb/textprinter.h @@ -8,23 +8,87 @@ #ifndef UPB_TEXT_H_ #define UPB_TEXT_H_ -#include "upb/handlers.h" +#include "upb/sink.h" + +#ifdef __cplusplus +namespace upb { +namespace pb { +class TextPrinter; +} // namespace pb +} // namespace upb + +typedef upb::pb::TextPrinter upb_textprinter; +#else +struct upb_textprinter; +typedef struct upb_textprinter upb_textprinter; +#endif + +#ifdef __cplusplus +class upb::pb::TextPrinter { + public: + // The given handlers must have come from NewHandlers(). It must outlive the + // TextPrinter. + explicit TextPrinter(const upb::Handlers* handlers); + + void SetSingleLineMode(bool single_line); + + bool ResetOutput(BytesSink* output); + Sink* input(); + + // If handler caching becomes a requirement we can add a code cache as in + // decoder.h + static reffed_ptr<const Handlers> NewHandlers(const MessageDef* md); + + private: +#else +struct upb_textprinter { +#endif + upb_sink input_; + upb_bytessink *output_; + int indent_depth_; + bool single_line_; + void *subc; +}; #ifdef __cplusplus extern "C" { #endif -struct _upb_textprinter; -typedef struct _upb_textprinter upb_textprinter; +// C API. +void upb_textprinter_init(upb_textprinter *p, const upb_handlers *h); +void upb_textprinter_uninit(upb_textprinter *p); +bool upb_textprinter_resetoutput(upb_textprinter *p, upb_bytessink *output); +void upb_textprinter_setsingleline(upb_textprinter *p, bool single_line); +upb_sink *upb_textprinter_input(upb_textprinter *p); -upb_textprinter *upb_textprinter_new(); -void upb_textprinter_free(upb_textprinter *p); -void upb_textprinter_reset(upb_textprinter *p, bool single_line); -const upb_handlers *upb_textprinter_newhandlers(const void *owner, - const upb_msgdef *m); +const upb_handlers *upb_textprinter_newhandlers(const upb_msgdef *m, + const void *owner); #ifdef __cplusplus } /* extern "C" */ + +namespace upb { +namespace pb { +inline TextPrinter::TextPrinter(const upb::Handlers* handlers) { + upb_textprinter_init(this, handlers); +} +inline void TextPrinter::SetSingleLineMode(bool single_line) { + upb_textprinter_setsingleline(this, single_line); +} +inline bool TextPrinter::ResetOutput(BytesSink* output) { + return upb_textprinter_resetoutput(this, output); +} +inline Sink* TextPrinter::input() { + return upb_textprinter_input(this); +} +inline reffed_ptr<const Handlers> TextPrinter::NewHandlers( + const MessageDef *md) { + const Handlers* h = upb_textprinter_newhandlers(md, &h); + return reffed_ptr<const Handlers>(h, &h); +} +} // namespace pb +} // namespace upb + #endif #endif /* UPB_TEXT_H_ */ diff --git a/upb/shim/shim.c b/upb/shim/shim.c index 5c3e026..797a2d1 100644 --- a/upb/shim/shim.c +++ b/upb/shim/shim.c @@ -38,6 +38,7 @@ bool upb_shim_set(upb_handlers *h, const upb_fielddef *f, size_t offset, upb_handlerattr attr = UPB_HANDLERATTR_INITIALIZER; upb_handlerattr_sethandlerdata(&attr, d, free); + upb_handlerattr_setalwaysok(&attr, true); #define TYPE(u, l) \ case UPB_TYPE_##u: \ @@ -120,7 +120,8 @@ class upb::Sink { // For StartString(), the function will write a sink for the string to "sub." // The sub-sink must be used for any/all PutStringBuffer() calls. bool StartString(Handlers::Selector s, size_t size_hint, Sink* sub); - size_t PutStringBuffer(Handlers::Selector s, const char *buf, size_t len); + size_t PutStringBuffer(Handlers::Selector s, const char *buf, size_t len, + const BufferHandle *handle); bool EndString(Handlers::Selector s); // For submessage fields. @@ -160,13 +161,14 @@ class upb::BytesSink { // // TODO(haberman): once the Handlers know the expected closure type, verify // that T matches it. - template <class T> BytesSink(const Handlers* handlers, T* closure); + template <class T> BytesSink(const BytesHandler* handler, T* closure); // Resets the value of the sink. - template <class T> void Reset(const Handlers* handlers, T* closure); + template <class T> void Reset(const BytesHandler* handler, T* closure); bool Start(size_t size_hint, void **subc); - size_t PutBuffer(void *subc, const char *buf, size_t len); + size_t PutBuffer(void *subc, const char *buf, size_t len, + const BufferHandle *handle); bool End(); #else @@ -219,6 +221,7 @@ UPB_INLINE void upb_bytessink_reset(upb_bytessink *s, const upb_byteshandler *h, UPB_INLINE bool upb_bytessink_start(upb_bytessink *s, size_t size_hint, void **subc) { + *subc = NULL; if (!s->handler) return true; upb_startstr_handlerfunc *start = (upb_startstr_handlerfunc *)s->handler->table[UPB_STARTSTR_SELECTOR].func; @@ -231,7 +234,8 @@ UPB_INLINE bool upb_bytessink_start(upb_bytessink *s, size_t size_hint, } UPB_INLINE size_t upb_bytessink_putbuf(upb_bytessink *s, void *subc, - const char *buf, size_t size) { + const char *buf, size_t size, + const upb_bufhandle* handle) { if (!s->handler) return true; upb_string_handlerfunc *putbuf = (upb_string_handlerfunc *)s->handler->table[UPB_STRING_SELECTOR].func; @@ -239,7 +243,7 @@ UPB_INLINE size_t upb_bytessink_putbuf(upb_bytessink *s, void *subc, if (!putbuf) return true; return putbuf(subc, upb_handlerattr_handlerdata( &s->handler->table[UPB_STRING_SELECTOR].attr), - buf, size); + buf, size, handle); } UPB_INLINE bool upb_bytessink_end(upb_bytessink *s) { @@ -256,10 +260,18 @@ UPB_INLINE bool upb_bytessink_end(upb_bytessink *s) { UPB_INLINE bool upb_bufsrc_putbuf(const char *buf, size_t len, upb_bytessink *sink) { void *subc; - return - upb_bytessink_start(sink, len, &subc) && - (len == 0 || upb_bytessink_putbuf(sink, subc, buf, len) == len) && - upb_bytessink_end(sink); + upb_bufhandle handle; + upb_bufhandle_init(&handle); + upb_bufhandle_setbuf(&handle, buf, 0); + bool ret = upb_bytessink_start(sink, len, &subc); + if (ret && len != 0) { + ret = (upb_bytessink_putbuf(sink, subc, buf, len, &handle) == len); + } + if (ret) { + ret = upb_bytessink_end(sink); + } + upb_bufhandle_uninit(&handle); + return ret; } #define PUTVAL(type, ctype) \ @@ -287,15 +299,16 @@ UPB_INLINE void upb_sink_reset(upb_sink *s, const upb_handlers *h, void *c) { s->closure = c; } -UPB_INLINE size_t -upb_sink_putstring(upb_sink *s, upb_selector_t sel, const char *buf, size_t n) { +UPB_INLINE size_t upb_sink_putstring(upb_sink *s, upb_selector_t sel, + const char *buf, size_t n, + const upb_bufhandle *handle) { if (!s->handlers) return n; upb_string_handlerfunc *handler = (upb_string_handlerfunc *)upb_handlers_gethandler(s->handlers, sel); if (!handler) return n; const void *hd = upb_handlers_gethandlerdata(s->handlers, sel); - return handler(s->closure, hd, buf, n); + return handler(s->closure, hd, buf, n, handle); } UPB_INLINE bool upb_sink_startmsg(upb_sink *s) { @@ -443,8 +456,8 @@ inline bool Sink::StartString(Handlers::Selector sel, size_t size_hint, return upb_sink_startstr(this, sel, size_hint, sub); } inline size_t Sink::PutStringBuffer(Handlers::Selector sel, const char *buf, - size_t len) { - return upb_sink_putstring(this, sel, buf, len); + size_t len, const BufferHandle* handle) { + return upb_sink_putstring(this, sel, buf, len, handle); } inline bool Sink::EndString(Handlers::Selector sel) { return upb_sink_endstr(this, sel); @@ -462,11 +475,16 @@ inline bool Sink::EndSequence(Handlers::Selector sel) { return upb_sink_endseq(this, sel); } +template <class T> +void BytesSink::Reset(const BytesHandler *handler, T *closure) { + upb_bytessink_reset(this, handler, closure); +} inline bool BytesSink::Start(size_t size_hint, void **subc) { return upb_bytessink_start(this, size_hint, subc); } -inline size_t BytesSink::PutBuffer(void *subc, const char *buf, size_t len) { - return upb_bytessink_putbuf(this, subc, buf, len); +inline size_t BytesSink::PutBuffer(void *subc, const char *buf, size_t len, + const BufferHandle *handle) { + return upb_bytessink_putbuf(this, subc, buf, len, handle); } inline bool BytesSink::End() { return upb_bytessink_end(this); diff --git a/upb/stdc/README b/upb/stdc/README deleted file mode 100644 index 1815af4..0000000 --- a/upb/stdc/README +++ /dev/null @@ -1,15 +0,0 @@ -This directory contains code that is ANSI C but uses parts of the -standard library that are not available to very limited environments -like Linux Kernel modules. The standard calls environments like this -"freestanding implementations." - -This does *not* imply that the upb core can be compiled directly on a -freestanding implementation. Even the core uses library functions -that are not directly available on freestanding implementations -(notably malloc()/free(), vsnprintf(), and assert()). So compiling on -freestanding implementations may require implementing compatibility -versions of functions like malloc(). - -Also, Linux is not technically a freestanding implementation either, -since it does not accept functions that return float or double on -x86-64 (these use SSE registers which are disabled in kernel mode). diff --git a/upb/symtab.c b/upb/symtab.c index a3acd16..099aa8d 100644 --- a/upb/symtab.c +++ b/upb/symtab.c @@ -146,10 +146,10 @@ static bool upb_resolve_dfs(const upb_def *def, upb_strtable *addtab, if (def->type == UPB_DEF_FIELD) continue; upb_value v; if (upb_strtable_lookup(addtab, upb_def_fullname(def), &v)) { - // Because we memoize we should not visit a node after we have dup'd it. - assert(((upb_def*)upb_value_getptr(v))->came_from_user); need_dup = true; } + + // For messages, continue the recursion by visiting all subdefs. const upb_msgdef *m = upb_dyncast_msgdef(def); if (m) { upb_msg_iter i; @@ -188,6 +188,8 @@ oom: return false; } +// TODO(haberman): we need a lot more testing of error conditions. +// The came_from_user stuff in particular is not tested. bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, upb_status *status) { upb_def **add_defs = NULL; @@ -197,7 +199,7 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, return false; } - // Add new defs to table. + // Add new defs to our "add" set. for (int i = 0; i < n; i++) { upb_def *def = defs[i]; if (upb_def_isfrozen(def)) { @@ -211,20 +213,79 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, status, "Anonymous defs cannot be added to a symtab"); goto err; } - if (upb_strtable_lookup(&addtab, fullname, NULL)) { - upb_status_seterrf(status, "Conflicting defs named '%s'", fullname); + + upb_fielddef *f = upb_dyncast_fielddef_mutable(def); + + if (f) { + if (!upb_fielddef_containingtypename(f)) { + upb_status_seterrmsg(status, + "Standalone fielddefs must have a containing type " + "(extendee) name set"); + goto err; + } + } else { + if (upb_strtable_lookup(&addtab, fullname, NULL)) { + upb_status_seterrf(status, "Conflicting defs named '%s'", fullname); + goto err; + } + // We need this to back out properly, because if there is a failure we + // need to donate the ref back to the caller. + def->came_from_user = true; + upb_def_donateref(def, ref_donor, s); + if (!upb_strtable_insert(&addtab, fullname, upb_value_ptr(def))) + goto oom_err; + } + } + + // Add standalone fielddefs (ie. extensions) to the appropriate messages. + // If the appropriate message only exists in the existing symtab, duplicate + // it so we have a mutable copy we can add the fields to. + for (int i = 0; i < n; i++) { + upb_def *def = defs[i]; + upb_fielddef *f = upb_dyncast_fielddef_mutable(def); + if (!f) continue; + const char *msgname = upb_fielddef_containingtypename(f); + // We validated this earlier in this function. + assert(msgname); + + // If the extendee name is absolutely qualified, move past the initial ".". + // TODO(haberman): it is not obvious what it would mean if this was not + // absolutely qualified. + if (msgname[0] == '.') { + msgname++; + } + + upb_value v; + upb_msgdef *m; + if (upb_strtable_lookup(&addtab, msgname, &v)) { + // Extendee is in the set of defs the user asked us to add. + m = upb_value_getptr(v); + } else { + // Need to find and dup the extendee from the existing symtab. + const upb_msgdef *frozen_m = upb_symtab_lookupmsg(s, msgname, &frozen_m); + if (!frozen_m) { + upb_status_seterrf(status, + "Tried to extend message %s that does not exist " + "in this SymbolTable.", + msgname); + goto err; + } + m = upb_msgdef_dup(frozen_m, s); + upb_msgdef_unref(frozen_m, &frozen_m); + if (!m) goto oom_err; + if (!upb_strtable_insert(&addtab, msgname, upb_value_ptr(m))) { + upb_msgdef_unref(m, s); + goto oom_err; + } + } + + if (!upb_msgdef_addfield(m, f, ref_donor, status)) { goto err; } - // We need this to back out properly, because if there is a failure we need - // to donate the ref back to the caller. - def->came_from_user = true; - upb_def_donateref(def, ref_donor, s); - if (!upb_strtable_insert(&addtab, fullname, upb_value_ptr(def))) - goto oom_err; } // Add dups of any existing def that can reach a def with the same name as - // one of "defs." + // anything in our "add" set. upb_inttable seen; if (!upb_inttable_init(&seen, UPB_CTYPE_BOOL)) goto oom_err; upb_strtable_iter i; @@ -236,7 +297,7 @@ bool upb_symtab_add(upb_symtab *s, upb_def *const*defs, int n, void *ref_donor, } upb_inttable_uninit(&seen); - // Now using the table, resolve symbolic references. + // Now using the table, resolve symbolic references for subdefs. upb_strtable_begin(&i, &addtab); for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { upb_def *def = upb_value_getptr(upb_strtable_iter_value(&i)); @@ -305,12 +366,13 @@ err: { upb_strtable_begin(&i, &addtab); for (; !upb_strtable_done(&i); upb_strtable_next(&i)) { upb_def *def = upb_value_getptr(upb_strtable_iter_value(&i)); - if (def->came_from_user) { + bool came_from_user = def->came_from_user; + def->came_from_user = false; + if (came_from_user) { upb_def_donateref(def, s, ref_donor); } else { upb_def_unref(def, s); } - def->came_from_user = false; } } upb_strtable_uninit(&addtab); |