From 08e7ad94f99b5944405a40af5c28b9aa95e9c0b0 Mon Sep 17 00:00:00 2001 From: Joshua Haberman Date: Fri, 19 Aug 2011 22:30:13 -0700 Subject: Renamed lang_ext -> bindings, README updates. --- Makefile | 20 +- README | 8 +- bindings/cpp/upb/handlers.hpp | 142 ++++++ bindings/lua/test.lua | 109 +++++ bindings/lua/upb.c | 1012 +++++++++++++++++++++++++++++++++++++++ bindings/python/setup.py | 14 + bindings/python/test.py | 72 +++ bindings/python/upb.c | 724 ++++++++++++++++++++++++++++ bindings/python/upb/__init__.py | 0 lang_ext/cpp/upb/handlers.hpp | 142 ------ lang_ext/lua/test.lua | 109 ----- lang_ext/lua/upb.c | 1012 --------------------------------------- lang_ext/python/setup.py | 14 - lang_ext/python/test.py | 72 --- lang_ext/python/upb.c | 724 ---------------------------- lang_ext/python/upb/__init__.py | 0 upb/descriptor.c | 3 + 17 files changed, 2088 insertions(+), 2089 deletions(-) create mode 100644 bindings/cpp/upb/handlers.hpp create mode 100644 bindings/lua/test.lua create mode 100644 bindings/lua/upb.c create mode 100644 bindings/python/setup.py create mode 100644 bindings/python/test.py create mode 100644 bindings/python/upb.c create mode 100644 bindings/python/upb/__init__.py delete mode 100644 lang_ext/cpp/upb/handlers.hpp delete mode 100644 lang_ext/lua/test.lua delete mode 100644 lang_ext/lua/upb.c delete mode 100644 lang_ext/python/setup.py delete mode 100644 lang_ext/python/test.py delete mode 100644 lang_ext/python/upb.c delete mode 100644 lang_ext/python/upb/__init__.py diff --git a/Makefile b/Makefile index ca04d71..3fef33d 100644 --- a/Makefile +++ b/Makefile @@ -126,8 +126,8 @@ clean_leave_profile: rm -rf $(TESTS) tests/t.* rm -rf upb/descriptor.pb rm -rf tools/upbc deps - rm -rf lang_ext/lua/upb.so - rm -rf lang_ext/python/build + rm -rf bindings/lua/upb.so + rm -rf bindings/python/build clean: clean_leave_profile rm -rf $(call rwildcard,,*.gcno) $(call rwildcard,,*.gcda) @@ -464,21 +464,21 @@ else LUA_LDFLAGS = endif -LUAEXT=lang_ext/lua/upb.so +LUAEXT=bindings/lua/upb.so lua: $(LUAEXT) -lang_ext/lua/upb.so: lang_ext/lua/upb.c $(LIBUPB_PIC) - $(E) CC lang_ext/lua/upb.c +bindings/lua/upb.so: bindings/lua/upb.c $(LIBUPB_PIC) + $(E) CC bindings/lua/upb.c $(Q) $(CC) $(CFLAGS) $(CPPFLAGS) $(LUA_CPPFLAGS) -fpic -shared -o $@ $< upb/libupb_pic.a $(LUA_LDFLAGS) # Python extension ############################################################# PYTHON=python -PYTHONEXT=lang_ext/python/build/install/lib/python/upb/__init__.so +PYTHONEXT=bindings/python/build/install/lib/python/upb/__init__.so python: $(PYTHONEXT) -$(PYTHONEXT): $(LIBUPB_PIC) lang_ext/python/upb.c - $(E) PYTHON lang_ext/python/upb.c - $(Q) cd lang_ext/python && $(PYTHON) setup.py build --debug install --home=build/install +$(PYTHONEXT): $(LIBUPB_PIC) bindings/python/upb.c + $(E) PYTHON bindings/python/upb.c + $(Q) cd bindings/python && $(PYTHON) setup.py build --debug install --home=build/install pythontest: $(PYTHONEXT) - cd lang_ext/python && cp test.py build/install/lib/python && valgrind $(PYTHON) ./build/install/lib/python/test.py + cd bindings/python && cp test.py build/install/lib/python && valgrind $(PYTHON) ./build/install/lib/python/test.py diff --git a/README b/README index 8b88451..45e9ff0 100644 --- a/README +++ b/README @@ -1,9 +1,9 @@ -upb - a minimalist implementation of protocol buffers. +upb - a small, low-level protocol buffer library For API documentation, see the header files. -To build (the core library is ANSI C and has no dependencies): +To build (the core library is ANSI C99 and has no dependencies): $ make Other useful targets: @@ -33,10 +33,6 @@ the major things that are broken or not yet implemented yet: - serialization isn't written yet (only deserialization) -- the language extensions that exist so far (Python and Lua) are totally - incomplete/broken. They are not usable for anything yet. This will - be remedied very soon. - CONTACT ======= diff --git a/bindings/cpp/upb/handlers.hpp b/bindings/cpp/upb/handlers.hpp new file mode 100644 index 0000000..b083f15 --- /dev/null +++ b/bindings/cpp/upb/handlers.hpp @@ -0,0 +1,142 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2011 Google Inc. See LICENSE for details. + * Author: Josh Haberman + * + * Note! This file is a proof-of-concept for C++ wrappers and does not + * yet build. + * + * upb::Handlers is a generic visitor-like interface for iterating over a + * stream of protobuf data. You can register function pointers that will be + * called for each message and/or field as the data is being parsed or iterated + * over, without having to know the source format that we are parsing from. + * This decouples the parsing logic from the processing logic. + */ + +#ifndef UPB_HANDLERS_HPP +#define UPB_HANDLERS_HPP + +#include "upb_handlers.h" + +namespace upb { + +typedef upb_flow_t Flow; + +class FieldHandlers : public upb_fhandlers { + public: + typedef upb_value_handler ValueHandler; + typedef upb_startfield_handler StartFieldHandler; + typedef upb_endfield_handler EndFieldHandler; + + // The FieldHandlers will live at least as long as the upb::Handlers to + // which it belongs, but can be Ref'd/Unref'd to make it live longer (which + // will prolong the life of the underlying upb::Handlers also). + void Ref() { upb_fhandlers_ref(this); } + void Unref() { upb_fhandlers_unref(this); } + + // Functions to set this field's handlers. + // These return "this" so they can be conveniently chained, eg. + // message_handlers->NewField(...) + // ->SetStartSequenceHandler(&StartSequence), + // ->SetEndSequenceHandler(&EndSequence), + // ->SetValueHandler(&Value); + FieldHandlers* SetValueHandler(ValueHandler* h) { + upb_fhandlers_setvalue(this, h); return this; + } + FieldHandlers* SetStartSequenceHandler(StartFieldHandler* h) { + upb_fhandlers_setstartseq(this, h); return this; + } + FieldHandlers* SetEndSequenceHandler(EndFieldHandler* h) { + upb_fhandlers_endseq(this, h); return this; + } + FieldHandlers* SetStartSubmessageHandler(StartFieldHandler* h) { + upb_fhandlers_setstartsubmsg(this, h); return this; + } + FieldHandlers* SetEndSubmessageHandler(EndFieldHandler* h) { + upb_fhandlers_endsubmsg(this, h); return this; + } + + // Get/Set the field's bound value, which will be passed to its handlers. + Value GetBoundValue() { return upb_fhandlers_getfval(this); } + FieldHandlers* SetBoundValue(Value val) { + upb_fhandlers_setfval(this, val); return this; + } + + private: + FieldHandlers(); // Only created by upb::Handlers. + ~FieldHandlers(); // Only destroyed by refcounting. +}; + + +class MessageHandlers : public upb_mhandlers { + public: + typedef upb_startmsg_handler StartMessageHandler; + typedef upb_endmsg_handler EndMessageHandler; + + // The MessageHandlers will live at least as long as the upb::Handlers to + // which it belongs, but can be Ref'd/Unref'd to make it live longer (which + // will prolong the life of the underlying upb::Handlers also). + void Ref() { upb_mhandlers_ref(this); } + void Unref() { upb_mhandlers_unref(this); } + + // Functions to set this message's handlers. + // These return "this" so they can be conveniently chained, eg. + // handlers->NewMessage() + // ->SetStartMessageHandler(&StartMessage) + // ->SetEndMessageHandler(&EndMessage); + MessageHandlers* SetStartMessageHandler(StartMessageHandler* h) { + upb_mhandlers_setstartmsg(this, h); return this; + } + MessageHandlers* SetEndMessageHandler(EndMessageHandler* h) { + upb_mhandlers_setendmsg(this, h); return this; + } + + // Functions to create new FieldHandlers for this message. + FieldHandlers* NewFieldHandlers(uint32_t fieldnum, upb_fieldtype_t type, + bool repeated) { + return upb_mhandlers_newfhandlers(this, fieldnum, type, repeated); + } + FieldHandlers* NewFieldHandlers(FieldDef* f) { + return upb_mhandlers_newfhandlers_fordef(f); + } + + // Like the previous but for MESSAGE or GROUP fields. For GROUP fields, the + // given submessage must not have any fields with this field number. + FieldHandlers* NewFieldHandlersForSubmessage(uint32_t n, FieldType type, + bool repeated, + MessageHandlers* subm) { + return upb_mhandlers_newsubmsgfhandlers(this, n, type, repeated, subm); + } + + FieldHandlers* NewFieldHandlersForSubmessage(FieldDef* f, + MessageHandlers* subm) { + return upb_mhandlers_newsubmsgfhandlers_fordef(f); + } + + + private: + MessageHandlers(); // Only created by upb::Handlers. + ~MessageHandlers(); // Only destroyed by refcounting. +}; + +class Handlers : public upb_handlers { + public: + // Creates a new Handlers instance. + Handlers* New() { return static_cast(upb_handlers_new()); } + + void Ref() { upb_handlers_ref(this); } + void Unref() { upb_handlers_unref(this); } + + // Returns a new MessageHandlers object. The first such message that is + // obtained will be the top-level message for this Handlers object. + MessageHandlers* NewMessageHandlers() { return upb_handlers_newmhandlers(); } + + private: + FieldHandlers(); // Only created by Handlers::New(). + ~FieldHandlers(); // Only destroyed by refcounting. +}; + +} // namespace upb + +#endif diff --git a/bindings/lua/test.lua b/bindings/lua/test.lua new file mode 100644 index 0000000..42bce25 --- /dev/null +++ b/bindings/lua/test.lua @@ -0,0 +1,109 @@ + +require "upb" + +symtab = upb.SymbolTable{ + upb.MessageDef{fqname="A", fields={ + upb.FieldDef{name="a", type=upb.TYPE_INT32, number=1}, + upb.FieldDef{name="b", type=upb.TYPE_DOUBLE, number=2}} + } +} + +symtab = upb.SymbolTable{ + upb.MessageDef{fqname="A", fields={ + upb.FieldDef{name="a", type=upb.TYPE_INT32, number=1}, + upb.FieldDef{name="b", type=upb.TYPE_DOUBLE, number=2}} + }, + upb.MessageDef{fqname="B"} +} +A, B, C = symtab:lookup("A", "B") +print(A) +print(B) +print(C) + +a = A() +a2 = upb.Message(A) +print("YO! a.a=" .. tostring(a.a) .. ", a2.a=" .. tostring(a2.a)) +a.a = 2 +a2.a = 3 +print("YO! a.a=" .. tostring(a.a) .. ", a2.a=" .. tostring(a2.a)) + +A = symtab:lookup("A") +if not A then + error("Could not find A") +end + +f = io.open("../../upb/descriptor.pb") +if not f then + error("Couldn't open descriptor.pb, try running 'make descriptorgen'") +end +symtab:parsedesc(f:read("*all")) +symtab:load_descriptor() +symtab:load_descriptor_file() + +upb.pb.load_descriptor(f:read("*all")) + +upb.pb.load_descriptor_file("../../src/descriptor.pb", symtab) + +f = io.open("../../benchmarks/google_messages.proto.pb") +if not f then + error("Couldn't open google_messages.proto.pb, try running 'make benchmarks'") +end +symtab:parsedesc(f:read("*all")) + +for _, def in ipairs(symtab:getdefs(-1)) do + print(def:name()) +end + +SpeedMessage1 = symtab:lookup("benchmarks.SpeedMessage1") +SpeedMessage2 = symtab:lookup("benchmarks.SpeedMessage2") +print(SpeedMessage1:name()) + +msg = MyType() +msg:Decode(str) + +msg:DecodeJSON(str) + +msg = upb.pb.decode(str, MyType) +str = upb.pb.encode(msg) + +msg = upb.pb.decode_text(str, MyType) +str = upb.pb.encode_text(msg) + +upb.clear(msg) +upb.msgdef(msg) +upb.has(msg, "foo_bar") + +msg = upb.json.decode(str, MyType) + +msg = upb.pb.DecodeText(str) +msg = upb.pb.EncodeText(msg) +upb. + +upb.pb.decode_into(msg, str) + +str = upb.json.Encode(msg) +upb.json.DecodeInto(msg, str) +f = assert(io.open("../../benchmarks/google_message1.dat")) +msg:Parse(f:read("*all")) +print(msg:ToText()) +print(upb.json.encode(msg)) + +msg = SpeedMessage2() +f = assert(io.open("../../benchmarks/google_message2.dat")) +msg:Parse(f:read("*all")) +print(msg:ToText()) +--msg:Serialize() +--msg:FromText(str) +-- print(msg.field129) +-- print(msg.field271) +--print(msg.field15.field15) +--msg.field15.field15 = "my override" +--print(msg.field15.field15) +-- print(msg.field1) +-- print(msg.field1) +-- msg.field1 = "YEAH BABY!" +-- print(msg.field1) +-- print(msg.field129) +-- msg.field129 = 5 +-- print(msg.field129) +--]] diff --git a/bindings/lua/upb.c b/bindings/lua/upb.c new file mode 100644 index 0000000..fe523e7 --- /dev/null +++ b/bindings/lua/upb.c @@ -0,0 +1,1012 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2009 Google Inc. See LICENSE for details. + * Author: Josh Haberman + * + * A Lua extension for upb. + */ + +#include +#include +#include +#include "lauxlib.h" +#include "upb/def.h" +#include "upb/msg.h" +#include "upb/pb/glue.h" + +#if LUA_VERSION_NUM == 501 +#define lua_rawlen lua_objlen +#endif + +static bool streql(const char *a, const char *b) { return strcmp(a, b) == 0; } + +static bool lupb_isint(double n) { return (double)(int)n == n; } + +static uint8_t lupb_touint8(lua_State *L, int narg, const char *name) { + lua_Number n = lua_tonumber(L, narg); + if (n > UINT8_MAX || n < 0 || rint(n) != n) + luaL_error(L, "Invalid %s", name); + return n; +} + +static uint32_t lupb_touint32(lua_State *L, int narg, const char *name) { + lua_Number n = lua_tonumber(L, narg); + if (n > UINT32_MAX || n < 0 || rint(n) != n) + luaL_error(L, "Invalid %s", name); + return n; +} + +static void lupb_pushstring(lua_State *L, upb_strref *ref) { + if (ref->ptr) { + lua_pushlstring(L, ref->ptr, ref->len); + } else { + // Lua requires a continguous string; must copy+allocate. + char *str = upb_strref_dup(ref); + lua_pushlstring(L, str, ref->len); + free(str); + } +} + +static void lupb_pushvalue(lua_State *L, upb_value val, upb_fielddef *f) { + switch (f->type) { + case UPB_TYPE(INT32): + case UPB_TYPE(SINT32): + case UPB_TYPE(SFIXED32): + case UPB_TYPE(ENUM): + lua_pushnumber(L, upb_value_getint32(val)); break; + case UPB_TYPE(INT64): + case UPB_TYPE(SINT64): + case UPB_TYPE(SFIXED64): + lua_pushnumber(L, upb_value_getint64(val)); break; + case UPB_TYPE(UINT32): + case UPB_TYPE(FIXED32): + lua_pushnumber(L, upb_value_getuint32(val)); break; + case UPB_TYPE(UINT64): + case UPB_TYPE(FIXED64): + lua_pushnumber(L, upb_value_getuint64(val)); break; + case UPB_TYPE(DOUBLE): + lua_pushnumber(L, upb_value_getdouble(val)); break; + case UPB_TYPE(FLOAT): + lua_pushnumber(L, upb_value_getfloat(val)); break; + case UPB_TYPE(BOOL): + lua_pushboolean(L, upb_value_getbool(val)); break; + default: luaL_error(L, "internal error"); + } +} + +// Returns a scalar value (ie. not a submessage) as a upb_value. +static upb_value lupb_getvalue(lua_State *L, int narg, upb_fielddef *f, + upb_strref *ref) { + assert(!upb_issubmsg(f)); + upb_value val; + 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_value_setbool(&val, lua_toboolean(L, narg)); + } else if (upb_fielddef_type(f) == UPB_TYPE(STRING)) { + size_t len; + ref->ptr = luaL_checklstring(L, narg, &len); + ref->len = len; + upb_value_setstrref(&val, ref); + } else { + // Numeric type. + lua_Number num = 0; + num = luaL_checknumber(L, narg); + switch (upb_fielddef_type(f)) { + case UPB_TYPE(INT32): + case UPB_TYPE(SINT32): + case UPB_TYPE(SFIXED32): + case UPB_TYPE(ENUM): + if (num > INT32_MAX || num < INT32_MIN || num != rint(num)) + luaL_error(L, "Cannot convert %f to 32-bit integer", num); + upb_value_setint32(&val, num); + break; + case UPB_TYPE(INT64): + case UPB_TYPE(SINT64): + case UPB_TYPE(SFIXED64): + if (num > INT64_MAX || num < INT64_MIN || num != rint(num)) + luaL_error(L, "Cannot convert %f to 64-bit integer", num); + upb_value_setint64(&val, num); + break; + case UPB_TYPE(UINT32): + case UPB_TYPE(FIXED32): + if (num > UINT32_MAX || num < 0 || num != rint(num)) + luaL_error(L, "Cannot convert %f to unsigned 32-bit integer", num); + upb_value_setuint32(&val, num); + break; + case UPB_TYPE(UINT64): + case UPB_TYPE(FIXED64): + if (num > UINT64_MAX || num < 0 || num != rint(num)) + luaL_error(L, "Cannot convert %f to unsigned 64-bit integer", num); + upb_value_setuint64(&val, num); + break; + case UPB_TYPE(DOUBLE): + if (num > DBL_MAX || num < -DBL_MAX) { + // This could happen if lua_Number was long double. + luaL_error(L, "Cannot convert %f to double", num); + } + upb_value_setdouble(&val, num); + break; + case UPB_TYPE(FLOAT): + if (num > FLT_MAX || num < -FLT_MAX) + luaL_error(L, "Cannot convert %f to float", num); + upb_value_setfloat(&val, num); + break; + } + } + return val; +} + +static void lupb_typecheck(lua_State *L, int narg, upb_fielddef *f) { + upb_strref ref; + lupb_getvalue(L, narg, f, &ref); +} + +//static void lupb_msg_getorcreate(lua_State *L, upb_msg *msg, upb_msgdef *md); +static void lupb_fielddef_getorcreate(lua_State *L, upb_fielddef *f); +static upb_msgdef *lupb_msgdef_check(lua_State *L, int narg); +static void lupb_msg_pushnew(lua_State *L, void *md); + +void lupb_checkstatus(lua_State *L, upb_status *s) { + if (!upb_ok(s)) { + upb_status_print(s, stderr); + // Need to copy the string to the stack, so we can free it and not leak + // it (since luaL_error() does not return). + char buf[strlen(s->str)+1]; + strcpy(buf, s->str); + upb_status_uninit(s); + luaL_error(L, "%s", buf); + } + upb_status_uninit(s); +} + + +/* object cache ***************************************************************/ + +// We cache all the lua objects (userdata) we vend in a weak table, indexed by +// the C pointer of the object they are caching. + +static void *lupb_cache_getorcreate_size( + lua_State *L, void *cobj, const char *type, size_t size) { + // Lookup our cache in the registry (we don't put our objects in the registry + // directly because we need our cache to be a weak table). + void **obj = NULL; + lua_getfield(L, LUA_REGISTRYINDEX, "upb.objcache"); + assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb. + lua_pushlightuserdata(L, cobj); + lua_rawget(L, -2); + // Stack: objcache, cached value. + if (lua_isnil(L, -1)) { + // Remove bad cached value and push new value. + lua_pop(L, 1); + // We take advantage of the fact that all of our objects are currently a + // single pointer, and thus have the same layout. + obj = lua_newuserdata(L, size); + *obj = cobj; + luaL_getmetatable(L, type); + assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb. + lua_setmetatable(L, -2); + + // Set it in the cache. + lua_pushlightuserdata(L, cobj); + lua_pushvalue(L, -2); + lua_rawset(L, -4); + } + lua_insert(L, -2); + lua_pop(L, 1); + return obj; +} + +// Most types are just 1 pointer and can use this helper. +static bool lupb_cache_getorcreate(lua_State *L, void *cobj, const char *type) { + return lupb_cache_getorcreate_size(L, cobj, type, sizeof(void*)) != NULL; +} + +static void lupb_cache_create(lua_State *L, void *cobj, const char *type) { + bool created = + lupb_cache_getorcreate_size(L, cobj, type, sizeof(void*)) != NULL; + (void)created; // For NDEBUG + assert(created); +} + + +/* lupb_def *******************************************************************/ + +// All the def types share the same C layout, even though they are different Lua +// types with different metatables. +typedef struct { + upb_def *def; +} lupb_def; + +static lupb_def *lupb_def_check(lua_State *L, int narg) { + void *ldef = luaL_checkudata(L, narg, "upb.msgdef"); + if (!ldef) ldef = luaL_checkudata(L, narg, "upb.enumdef"); + if (!ldef) luaL_typerror(L, narg, "upb def"); + return ldef; +} + +static void lupb_def_getorcreate(lua_State *L, upb_def *def, int owned) { + bool created = false; + switch(def->type) { + case UPB_DEF_MSG: + created = lupb_cache_getorcreate(L, def, "upb.msgdef"); + break; + case UPB_DEF_ENUM: + created = lupb_cache_getorcreate(L, def, "upb.enumdef"); + break; + default: + luaL_error(L, "unknown deftype %d", def->type); + } + if (!owned && created) { + upb_def_ref(def); + } else if (owned && !created) { + upb_def_unref(def); + } +} + + +/* lupb_fielddef **************************************************************/ + +typedef struct { + upb_fielddef *field; +} lupb_fielddef; + +static lupb_fielddef *lupb_fielddef_check(lua_State *L, int narg) { + lupb_fielddef *f = luaL_checkudata(L, narg, "upb.fielddef"); + if (!f) luaL_typerror(L, narg, "upb fielddef"); + return f; +} + +static int lupb_fielddef_index(lua_State *L) { + lupb_fielddef *f = lupb_fielddef_check(L, 1); + const char *str = luaL_checkstring(L, 2); + if (streql(str, "name")) { + lua_pushstring(L, upb_fielddef_name(f->field)); + } else if (streql(str, "number")) { + lua_pushinteger(L, upb_fielddef_number(f->field)); + } else if (streql(str, "type")) { + lua_pushinteger(L, upb_fielddef_type(f->field)); + } else if (streql(str, "label")) { + lua_pushinteger(L, upb_fielddef_label(f->field)); + } else if (streql(str, "subdef")) { + lupb_def_getorcreate(L, upb_fielddef_subdef(f->field), false); + } else if (streql(str, "msgdef")) { + lupb_def_getorcreate(L, UPB_UPCAST(upb_fielddef_msgdef(f->field)), false); + } else { + luaL_error(L, "Invalid fielddef member '%s'", str); + } + return 1; +} + +static void lupb_fielddef_set(lua_State *L, upb_fielddef *f, + const char *field, int narg) { + if (!upb_fielddef_ismutable(f)) luaL_error(L, "fielddef is not mutable."); + if (streql(field, "name")) { + const char *name = lua_tostring(L, narg); + if (!name || !upb_fielddef_setname(f, name)) + luaL_error(L, "Invalid name"); + } else if (streql(field, "number")) { + if (!upb_fielddef_setnumber(f, lupb_touint32(L, narg, "number"))) + luaL_error(L, "Invalid number"); + } else if (streql(field, "type")) { + if (!upb_fielddef_settype(f, lupb_touint8(L, narg, "type"))) + luaL_error(L, "Invalid type"); + } else if (streql(field, "label")) { + if (!upb_fielddef_setlabel(f, lupb_touint8(L, narg, "label"))) + luaL_error(L, "Invalid label"); + } else if (streql(field, "type_name")) { + const char *name = lua_tostring(L, narg); + if (!name || !upb_fielddef_settypename(f, name)) + luaL_error(L, "Invalid type_name"); + } else if (streql(field, "default_value")) { + if (!upb_fielddef_type(f)) + luaL_error(L, "Must set type before setting default_value"); + upb_strref ref; + upb_fielddef_setdefault(f, lupb_getvalue(L, narg, f, &ref)); + } else { + luaL_error(L, "Cannot set fielddef member '%s'", field); + } +} + +static int lupb_fielddef_new(lua_State *L) { + upb_fielddef *f = upb_fielddef_new(); + lupb_cache_create(L, f, "upb.fielddef"); + + if (lua_gettop(L) == 0) return 1; + + // User can specify initialization values like so: + // upb.FieldDef{label=upb.LABEL_REQUIRED, name="my_field", number=5, + // type=upb.TYPE_INT32, default_value=12, type_name="Foo"} + luaL_checktype(L, 1, LUA_TTABLE); + // Iterate over table. + lua_pushnil(L); // first key + while (lua_next(L, 1)) { + luaL_checktype(L, -2, LUA_TSTRING); + const char *key = lua_tostring(L, -2); + lupb_fielddef_set(L, f, key, -1); + lua_pop(L, 1); + } + return 1; +} + +static void lupb_fielddef_getorcreate(lua_State *L, upb_fielddef *f) { + bool created = lupb_cache_getorcreate(L, f, "upb.fielddef"); + if (created) upb_fielddef_ref(f); +} + +static int lupb_fielddef_newindex(lua_State *L) { + lupb_fielddef *f = lupb_fielddef_check(L, 1); + lupb_fielddef_set(L, f->field, luaL_checkstring(L, 2), 3); + return 0; +} + +static int lupb_fielddef_gc(lua_State *L) { + lupb_fielddef *lfielddef = lupb_fielddef_check(L, 1); + upb_fielddef_unref(lfielddef->field); + return 0; +} + +static const struct luaL_Reg lupb_fielddef_mm[] = { + {"__gc", lupb_fielddef_gc}, + {"__index", lupb_fielddef_index}, + {"__newindex", lupb_fielddef_newindex}, + {NULL, NULL} +}; + + +/* lupb_msgdef ****************************************************************/ + +static upb_msgdef *lupb_msgdef_check(lua_State *L, int narg) { + lupb_def *ldef = luaL_checkudata(L, narg, "upb.msgdef"); + luaL_argcheck(L, ldef != NULL, narg, "upb msgdef expected"); + return upb_downcast_msgdef(ldef->def); +} + +static int lupb_msgdef_gc(lua_State *L) { + lupb_def *ldef = luaL_checkudata(L, 1, "upb.msgdef"); + upb_def_unref(ldef->def); + return 0; +} + +static int lupb_msgdef_call(lua_State *L) { + upb_msgdef *md = lupb_msgdef_check(L, 1); + lupb_msg_pushnew(L, md); + return 1; +} + +static int lupb_msgdef_new(lua_State *L) { + upb_msgdef *md = upb_msgdef_new(); + lupb_cache_create(L, md, "upb.msgdef"); + + if (lua_gettop(L) == 0) return 1; + + // User can specify initialization values like so: + // upb.MessageDef{fqname="MyMessage", extstart=8000, fields={...}} + luaL_checktype(L, 1, LUA_TTABLE); + // Iterate over table. + lua_pushnil(L); // first key + while (lua_next(L, 1)) { + luaL_checktype(L, -2, LUA_TSTRING); + const char *key = lua_tostring(L, -2); + + if (streql(key, "fqname")) { // fqname="MyMessage" + const char *fqname = lua_tostring(L, -1); + if (!fqname || !upb_def_setfqname(UPB_UPCAST(md), fqname)) + luaL_error(L, "Invalid fqname"); + } else if (streql(key, "fields")) { // fields={...} + // Iterate over the list of fields. + lua_pushnil(L); + luaL_checktype(L, -2, LUA_TTABLE); + while (lua_next(L, -2)) { + lupb_fielddef *f = lupb_fielddef_check(L, -1); + if (!upb_msgdef_addfield(md, f->field)) { + // TODO: more specific error. + luaL_error(L, "Could not add field."); + } + lua_pop(L, 1); + } + } else { + // TODO: extrange= + luaL_error(L, "Unknown initializer key '%s'", key); + } + lua_pop(L, 1); + } + return 1; +} + +static int lupb_msgdef_fqname(lua_State *L) { + upb_msgdef *m = lupb_msgdef_check(L, 1); + lua_pushstring(L, m->base.fqname); + return 1; +} + +static int lupb_msgdef_fieldbyname(lua_State *L) { + upb_msgdef *m = lupb_msgdef_check(L, 1); + upb_fielddef *f = upb_msgdef_ntof(m, luaL_checkstring(L, 2)); + if (f) { + lupb_fielddef_getorcreate(L, f); + } else { + lua_pushnil(L); + } + return 1; +} + +static int lupb_msgdef_fieldbynum(lua_State *L) { + upb_msgdef *m = lupb_msgdef_check(L, 1); + int num = luaL_checkint(L, 2); + upb_fielddef *f = upb_msgdef_itof(m, num); + if (f) { + lupb_fielddef_getorcreate(L, f); + } else { + lua_pushnil(L); + } + return 1; +} + +static const struct luaL_Reg lupb_msgdef_mm[] = { + {"__call", lupb_msgdef_call}, + {"__gc", lupb_msgdef_gc}, + {NULL, NULL} +}; + +static const struct luaL_Reg lupb_msgdef_m[] = { + {"fieldbyname", lupb_msgdef_fieldbyname}, + {"fieldbynum", lupb_msgdef_fieldbynum}, + {"fqname", lupb_msgdef_fqname}, + {NULL, NULL} +}; + + +/* lupb_enumdef ***************************************************************/ + +static upb_enumdef *lupb_enumdef_check(lua_State *L, int narg) { + lupb_def *ldef = luaL_checkudata(L, narg, "upb.enumdef"); + return upb_downcast_enumdef(ldef->def); +} + +static int lupb_enumdef_gc(lua_State *L) { + upb_enumdef *e = lupb_enumdef_check(L, 1); + upb_def_unref(UPB_UPCAST(e)); + return 0; +} + +static int lupb_enumdef_name(lua_State *L) { + upb_enumdef *e = lupb_enumdef_check(L, 1); + lua_pushstring(L, e->base.fqname); + return 1; +} + +static const struct luaL_Reg lupb_enumdef_mm[] = { + {"__gc", lupb_enumdef_gc}, + {NULL, NULL} +}; + +static const struct luaL_Reg lupb_enumdef_m[] = { + {"name", lupb_enumdef_name}, + {NULL, NULL} +}; + + +/* lupb_symtab ****************************************************************/ + +typedef struct { + upb_symtab *symtab; +} lupb_symtab; + +static upb_accessor_vtbl *lupb_accessor(upb_fielddef *f); + +// Inherits a ref on the symtab. +// Checks that narg is a proper lupb_symtab object. If it is, leaves its +// metatable on the stack for cache lookups/updates. +lupb_symtab *lupb_symtab_check(lua_State *L, int narg) { + return luaL_checkudata(L, narg, "upb.symtab"); +} + +// narg is a lua table containing a list of defs to add. +void lupb_symtab_doadd(lua_State *L, upb_symtab *s, int narg) { + luaL_checktype(L, narg, LUA_TTABLE); + // Iterate over table twice. First iteration to count entries and + // check constraints. + int n = 0; + lua_pushnil(L); // first key + while (lua_next(L, narg)) { + lupb_def_check(L, -1); + ++n; + lua_pop(L, 1); + } + + // Second iteration to build deflist and layout. + upb_def **defs = malloc(n * sizeof(*defs)); + n = 0; + lua_pushnil(L); // first key + while (lua_next(L, 1)) { + upb_def *def = lupb_def_check(L, -1)->def; + defs[n++] = def; + upb_msgdef *md = upb_dyncast_msgdef(def); + if (md) { + upb_msg_iter i; + for(i = upb_msg_begin(md); !upb_msg_done(i); i = upb_msg_next(md, i)) { + upb_fielddef *f = upb_msg_iter_field(i); + upb_fielddef_setaccessor(f, lupb_accessor(f)); + } + upb_msgdef_layout(md); + } + lua_pop(L, 1); + } + + upb_status status = UPB_STATUS_INIT; + upb_symtab_add(s, defs, n, &status); + free(defs); + lupb_checkstatus(L, &status); +} + +static int lupb_symtab_new(lua_State *L) { + upb_symtab *s = upb_symtab_new(); + lupb_cache_create(L, s, "upb.symtab"); + if (lua_gettop(L) == 0) return 1; + lupb_symtab_doadd(L, s, 1); + return 1; +} + +static int lupb_symtab_add(lua_State *L) { + lupb_symtab *s = lupb_symtab_check(L, 1); + lupb_symtab_doadd(L, s->symtab, 2); + return 0; +} + +static int lupb_symtab_gc(lua_State *L) { + lupb_symtab *s = lupb_symtab_check(L, 1); + upb_symtab_unref(s->symtab); + return 0; +} + +static int lupb_symtab_lookup(lua_State *L) { + lupb_symtab *s = lupb_symtab_check(L, 1); + for (int i = 2; i <= lua_gettop(L); i++) { + upb_def *def = upb_symtab_lookup(s->symtab, luaL_checkstring(L, i)); + if (def) { + lupb_def_getorcreate(L, def, true); + } else { + lua_pushnil(L); + } + lua_replace(L, i); + } + return lua_gettop(L) - 1; +} + +static int lupb_symtab_getdefs(lua_State *L) { + lupb_symtab *s = lupb_symtab_check(L, 1); + upb_deftype_t type = luaL_checkint(L, 2); + int count; + upb_def **defs = upb_symtab_getdefs(s->symtab, &count, type); + + // Create the table in which we will return the defs. + lua_createtable(L, count, 0); + for (int i = 0; i < count; i++) { + upb_def *def = defs[i]; + lupb_def_getorcreate(L, def, true); + lua_rawseti(L, -2, i + 1); + } + free(defs); + return 1; +} + +static const struct luaL_Reg lupb_symtab_m[] = { + {"add", lupb_symtab_add}, + {"getdefs", lupb_symtab_getdefs}, + {"lookup", lupb_symtab_lookup}, + {NULL, NULL} +}; + +static const struct luaL_Reg lupb_symtab_mm[] = { + {"__gc", lupb_symtab_gc}, + {NULL, NULL} +}; + + +/* lupb_msg********************************************************************/ + +// Messages are userdata. Primitive values (numbers and bools, and their +// hasbits) are stored right in the userdata. Other values are stored using +// integer entries in the environment table and no hasbits are used (since +// "nil" in the environment table can indicate "not present"). +// +// The environment table looks like: +// {msgdef, } + +// Must pass a upb_fielddef as the pointer. +static void lupb_array_pushnew(lua_State *L, void *f); + +static void *lupb_msg_check(lua_State *L, int narg, upb_msgdef **md) { + void *msg = luaL_checkudata(L, narg, "upb.msg"); + luaL_argcheck(L, msg != NULL, narg, "msg expected"); + // If going all the way to the environment table for the msgdef is an + // efficiency issue, we could put the pointer right in the userdata. + lua_getfenv(L, narg); + lua_rawgeti(L, -1, 1); + // Shouldn't have to check msgdef userdata validity, environment table can't + // be accessed from Lua. + lupb_def *lmd = lua_touserdata(L, -1); + *md = upb_downcast_msgdef(lmd->def); + return msg; +} + +static void lupb_msg_pushnew(lua_State *L, void *md) { + void *msg = lua_newuserdata(L, upb_msgdef_size(md)); + luaL_getmetatable(L, "upb.msg"); + assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb. + lua_setmetatable(L, -2); + upb_msg_clear(msg, md); + lua_getfenv(L, -1); + lupb_cache_getorcreate(L, md, "upb.msgdef"); + lua_rawseti(L, -2, 1); + lua_pop(L, 1); // Pop the fenv. +} + +static int lupb_msg_new(lua_State *L) { + upb_msgdef *md = lupb_msgdef_check(L, 1); + lupb_msg_pushnew(L, md); + return 1; +} + +static int lupb_msg_index(lua_State *L) { + upb_msgdef *md; + void *m = lupb_msg_check(L, 1, &md); + upb_fielddef *f = upb_msgdef_ntof(md, luaL_checkstring(L, 2)); + if (!f) luaL_argerror(L, 2, "not a field name"); + if (upb_isprimitivetype(upb_fielddef_type(f))) { + upb_value v = upb_msg_has(m, f) ? upb_msg_get(m, f) : upb_fielddef_default(f); + lupb_pushvalue(L, v, f); + } else { + lua_getfenv(L, 1); + lua_rawgeti(L, -1, f->offset); + if (lua_isnil(L, -1)) { + // Need to lazily create array, string, or submessage. + if (upb_isseq(f)) { + lupb_array_pushnew(L, f); + } else if (upb_isstring(f)) { + // TODO: (need to figure out default string ownership). + } else if (upb_issubmsg(f)) { + lupb_msg_pushnew(L, upb_downcast_msgdef(upb_fielddef_subdef(f))); + } else { + luaL_error(L, "internal error"); + } + lua_rawseti(L, -2, f->offset); + } + } + return 1; +} + +static int lupb_msg_newindex(lua_State *L) { + upb_msgdef *md; + void *m = lupb_msg_check(L, 1, &md); + upb_fielddef *f = upb_msgdef_ntof(md, luaL_checkstring(L, 2)); + if (!f) luaL_error(L, "not a field name"); + if (upb_isprimitivetype(upb_fielddef_type(f))) { + if (lua_isnil(L, 3)) + upb_msg_clearbit(m, f); + else + upb_msg_set(m, f, lupb_getvalue(L, 3, f, NULL)); + } else { + if (!lua_isnil(L, 3)) lupb_typecheck(L, 3, f); + lua_getfenv(L, 1); + lua_pushvalue(L, 3); + lua_rawseti(L, -1, f->offset); + } + return 0; +} + +static const struct luaL_Reg lupb_msg_mm[] = { + {"__index", lupb_msg_index}, + {"__newindex", lupb_msg_newindex}, + {NULL, NULL} +}; + +// Functions that operate on msgdefs but do not live in the msgdef namespace. +static int lupb_clear(lua_State *L) { + upb_msgdef *md; + void *m = lupb_msg_check(L, 1, &md); + upb_msg_clear(m, md); + return 0; +} + +static int lupb_has(lua_State *L) { + upb_msgdef *md; + void *m = lupb_msg_check(L, 1, &md); + upb_fielddef *f = upb_msgdef_ntof(md, luaL_checkstring(L, 2)); + if (!f) luaL_argerror(L, 2, "not a field name"); + lua_pushboolean(L, upb_msg_has(m, f)); + return 1; +} + +static int lupb_msgdef(lua_State *L) { + upb_msgdef *md; + lupb_msg_check(L, 1, &md); + lupb_def_getorcreate(L, UPB_UPCAST(md), false); + return 1; +} + +// Accessors for arrays, strings, and submessages need access to the current +// userdata's environment table, which can only be stored in Lua space. +// Options for storing it are: +// +// - put the env tables for all messages and arrays in the registry, keyed by +// userdata pointer (light userdata), or by a reference using luaL_ref(). +// Then we can just let upb's parse stack track the stack of env tables. +// Easy but requires all messages and arrays to be in the registry, which +// seems too heavyweight. +// +// - store the stack of env tables in the Lua stack. Convenient, but requires +// special code to handle resumable decoders. +// +// There is also the question of how to obtain the lua_State* pointer. +// The main options for this are: +// +// - make our closure point to a struct: +// struct { void *msg; lua_State *L; } +// But then we can't use standard accessors, which expect the closure +// to point to the data itself. Using the standard accessors for +// primitive values is both a simplicity and a performance win. +// +// - store a lua_State* pointer inside each userdata. Convenient and +// efficient, but makes every message sizeof(void*) larger. +// Currently we take this route. +// +// - use thread-local storage. Convenient and efficient, but not portable. + +typedef void createfunc_t(lua_State *L, void *param); + +static upb_sflow_t lupb_msg_start(void *m, upb_fielddef *f, bool array, + createfunc_t *pushnew, void *param) { + lua_State *L = *(lua_State**)m; + int offset = array ? lua_rawlen(L, -1) : f->offset; + if (!lua_checkstack(L, 3)) luaL_error(L, "stack full"); + lua_rawgeti(L, -1, offset); + if (lua_isnil(L, -1)) { + lua_pop(L, 1); + pushnew(L, param); + lua_pushvalue(L, -1); + lua_rawseti(L, -3, offset); + } + void *subval = lua_touserdata(L, -1); + lua_getfenv(L, -1); + lua_replace(L, -2); // Replace subval userdata with fenv. + return UPB_CONTINUE_WITH(subval); +} + +static upb_flow_t lupb_msg_string(void *m, upb_value fval, upb_value val, + bool array) { + // Could add lazy materialization of strings here. + upb_fielddef *f = upb_value_getfielddef(fval); + lua_State *L = *(lua_State**)m; + int offset = array ? lua_rawlen(L, -1) : f->offset; + if (!lua_checkstack(L, 1)) luaL_error(L, "stack full"); + lupb_pushstring(L, upb_value_getstrref(val)); + lua_rawseti(L, -2, offset); + return UPB_CONTINUE; +} + +static upb_sflow_t lupb_msg_startseq(void *m, upb_value fval) { + upb_fielddef *f = upb_value_getfielddef(fval); + return lupb_msg_start(m, f, false, lupb_array_pushnew, f); +} + +static upb_sflow_t lupb_msg_startsubmsg(void *m, upb_value fval) { + upb_fielddef *f = upb_value_getfielddef(fval); + return lupb_msg_start(m, f, false, lupb_msg_pushnew, upb_fielddef_subdef(f)); +} + +static upb_sflow_t lupb_msg_startsubmsg_r(void *a, upb_value fval) { + upb_fielddef *f = upb_value_getfielddef(fval); + return lupb_msg_start(a, f, true, lupb_msg_pushnew, upb_fielddef_subdef(f)); +} + +static upb_flow_t lupb_msg_stringval(void *m, upb_value fval, upb_value val) { + return lupb_msg_string(m, fval, val, false); +} + +static upb_flow_t lupb_msg_stringval_r(void *a, upb_value fval, upb_value val) { + return lupb_msg_string(a, fval, val, true); +} + +#define STDMSG(type, size) static upb_accessor_vtbl vtbl = { \ + &lupb_msg_startsubmsg, \ + &upb_stdmsg_set ## type, \ + &lupb_msg_startseq, \ + &lupb_msg_startsubmsg_r, \ + &upb_stdmsg_set ## type ## _r, \ + &upb_stdmsg_has, \ + &upb_stdmsg_getptr, \ + &upb_stdmsg_get ## type, \ + &upb_stdmsg_seqbegin, \ + &upb_stdmsg_ ## size ## byte_seqnext, \ + &upb_stdmsg_seqget ## type}; + +#define RETURN_STDMSG(type, size) { STDMSG(type, size); return &vtbl; } + +static upb_accessor_vtbl *lupb_accessor(upb_fielddef *f) { + switch (f->type) { + case UPB_TYPE(DOUBLE): RETURN_STDMSG(double, 8) + case UPB_TYPE(FLOAT): RETURN_STDMSG(float, 4) + case UPB_TYPE(UINT64): + case UPB_TYPE(FIXED64): RETURN_STDMSG(uint64, 8) + case UPB_TYPE(INT64): + case UPB_TYPE(SFIXED64): + case UPB_TYPE(SINT64): RETURN_STDMSG(int64, 8) + case UPB_TYPE(INT32): + case UPB_TYPE(SINT32): + case UPB_TYPE(ENUM): + case UPB_TYPE(SFIXED32): RETURN_STDMSG(int32, 4) + case UPB_TYPE(UINT32): + case UPB_TYPE(FIXED32): RETURN_STDMSG(uint32, 4) + case UPB_TYPE(BOOL): { STDMSG(bool, 1); return &vtbl; } + case UPB_TYPE(GROUP): + case UPB_TYPE(MESSAGE): RETURN_STDMSG(ptr, 8) // TODO: 32-bit + case UPB_TYPE(STRING): + case UPB_TYPE(BYTES): { + STDMSG(ptr, 8); + vtbl.set = &lupb_msg_stringval; + vtbl.append = &lupb_msg_stringval_r; + return &vtbl; + } + } + return NULL; +} + + +/* lupb_array ****************************************************************/ + +// Array: we store all elements in the environment table. Could optimize by +// storing primitive arrays in our own memory; this would be significantly more +// space efficient. Lua array elements are 16 bytes each; our own array would +// be 1/4 the space for 32-bit integers, or 1/16 the space for booleans. +// +// The first element of the environment table stores our type (which will be +// either an integer from upb.TYPE_* or a upb.msgdef), the remaining elements +// store the elements. We always keep all elements contiguous so we can use +// lua_objlen()/lua_rawlen() (for Lua 5.1/5.2 respectively) to report its len). + +// narg is offset of environment table. +static size_t lupb_array_getlen(lua_State *L, int narg) { + return lua_rawlen(L, narg) - 1; +} + +static void lupb_array_check(lua_State *L, int narg) { + if (!luaL_checkudata(L, narg, "upb.array")) + luaL_typerror(L, narg, "upb array"); +} + +static void lupb_array_pushnew(lua_State *L, void *f) { + (void)L; + (void)f; +} + +static int lupb_array_new(lua_State *L) { + (void)L; + return 0; +} + +static int lupb_array_len(lua_State *L) { + lupb_array_check(L, 1); + lua_getfenv(L, 1); + lua_pushnumber(L, lupb_array_getlen(L, -1)); + return 1; +} + +static int lupb_array_index(lua_State *L) { + assert(lua_gettop(L) == 2); // __index should always be called with 2 args. + lupb_array_check(L, 1); + lua_Number num = luaL_checknumber(L, 2); + if (!lupb_isint(num)) luaL_typerror(L, 2, "integer"); + + lua_getfenv(L, 1); + size_t len = lupb_array_getlen(L, -1); + if (num < 1 || num > len) luaL_error(L, "array bounds check failed"); + lua_rawgeti(L, -1, num + 1); + return 1; +} + +static int lupb_array_newindex(lua_State *L) { + assert(lua_gettop(L) == 3); // __newindex should always be called with 3 args. + lupb_array_check(L, 1); + lua_Number num = luaL_checknumber(L, 2); + if (rint(num) != num) luaL_typerror(L, 2, "integer"); + + lua_getfenv(L, 1); + size_t len = lupb_array_getlen(L, -1); + // We only allow extending the index one beyond the end. + if (num < 1 || num > len + 1) luaL_error(L, "array bounds check failed"); + lua_pushvalue(L, 3); + lua_rawseti(L, -2, num); + return 0; +} + +static const struct luaL_Reg lupb_array_mm[] = { + {"__len", lupb_array_len}, + {"__index", lupb_array_index}, + {"__newindex", lupb_array_newindex}, + {NULL, NULL} +}; + +/* lupb toplevel **************************************************************/ + +static const struct luaL_Reg lupb_toplevel_m[] = { + {"SymbolTable", lupb_symtab_new}, + {"MessageDef", lupb_msgdef_new}, + {"FieldDef", lupb_fielddef_new}, + + {"Message", lupb_msg_new}, + {"Array", lupb_array_new}, + + {"clear", lupb_clear}, + {"msgdef", lupb_msgdef}, + {"has", lupb_has}, + + {NULL, NULL} +}; + +// Register the given type with the given methods and metamethods. +static void lupb_register_type(lua_State *L, const char *name, + const luaL_Reg *m, const luaL_Reg *mm) { + luaL_newmetatable(L, name); + luaL_register(L, NULL, mm); // Register all mm in the metatable. + lua_createtable(L, 0, 0); + if (m) { + // Methods go in the mt's __index method. This implies that you can't + // implement __index and also set methods yourself. + luaL_register(L, NULL, m); + lua_setfield(L, -2, "__index"); + } + lua_pop(L, 1); // The mt. +} + +static void lupb_setfieldi(lua_State *L, const char *field, int i) { + lua_pushnumber(L, i); + lua_setfield(L, -2, field); +} + +int luaopen_upb(lua_State *L) { + lupb_register_type(L, "upb.msgdef", lupb_msgdef_m, lupb_msgdef_mm); + lupb_register_type(L, "upb.enumdef", lupb_enumdef_m, lupb_enumdef_mm); + lupb_register_type(L, "upb.fielddef", NULL, lupb_fielddef_mm); + lupb_register_type(L, "upb.symtab", lupb_symtab_m, lupb_symtab_mm); + + lupb_register_type(L, "upb.msg", NULL, lupb_msg_mm); + lupb_register_type(L, "upb.array", NULL, lupb_msg_mm); + + // Create our object cache. + lua_createtable(L, 0, 0); + lua_createtable(L, 0, 1); // Cache metatable. + lua_pushstring(L, "v"); // Values are weak. + lua_setfield(L, -2, "__mode"); + lua_setfield(L, LUA_REGISTRYINDEX, "upb.objcache"); + + luaL_register(L, "upb", lupb_toplevel_m); + + // Register constants. + lupb_setfieldi(L, "LABEL_OPTIONAL", UPB_LABEL(OPTIONAL)); + lupb_setfieldi(L, "LABEL_REQUIRED", UPB_LABEL(REQUIRED)); + lupb_setfieldi(L, "LABEL_REPEATED", UPB_LABEL(REPEATED)); + + lupb_setfieldi(L, "TYPE_DOUBLE", UPB_TYPE(DOUBLE)); + lupb_setfieldi(L, "TYPE_FLOAT", UPB_TYPE(FLOAT)); + lupb_setfieldi(L, "TYPE_INT64", UPB_TYPE(INT64)); + lupb_setfieldi(L, "TYPE_UINT64", UPB_TYPE(UINT64)); + lupb_setfieldi(L, "TYPE_INT32", UPB_TYPE(INT32)); + lupb_setfieldi(L, "TYPE_FIXED64", UPB_TYPE(FIXED64)); + lupb_setfieldi(L, "TYPE_FIXED32", UPB_TYPE(FIXED32)); + lupb_setfieldi(L, "TYPE_BOOL", UPB_TYPE(BOOL)); + lupb_setfieldi(L, "TYPE_STRING", UPB_TYPE(STRING)); + lupb_setfieldi(L, "TYPE_GROUP", UPB_TYPE(GROUP)); + lupb_setfieldi(L, "TYPE_MESSAGE", UPB_TYPE(MESSAGE)); + lupb_setfieldi(L, "TYPE_BYTES", UPB_TYPE(BYTES)); + lupb_setfieldi(L, "TYPE_UINT32", UPB_TYPE(UINT32)); + lupb_setfieldi(L, "TYPE_ENUM", UPB_TYPE(ENUM)); + lupb_setfieldi(L, "TYPE_SFIXED32", UPB_TYPE(SFIXED32)); + lupb_setfieldi(L, "TYPE_SFIXED64", UPB_TYPE(SFIXED64)); + lupb_setfieldi(L, "TYPE_SINT32", UPB_TYPE(SINT32)); + lupb_setfieldi(L, "TYPE_SINT64", UPB_TYPE(SINT64)); + + return 1; // Return package table. +} diff --git a/bindings/python/setup.py b/bindings/python/setup.py new file mode 100644 index 0000000..8abaff8 --- /dev/null +++ b/bindings/python/setup.py @@ -0,0 +1,14 @@ +from distutils.core import setup, Extension + +setup(name='upb', + version='0.1', + ext_modules=[ + Extension('upb.__init__', ['upb.c'], + include_dirs=['../../'], + define_macros=[("UPB_UNALIGNED_READS_OK", 1)], + library_dirs=['../../upb'], + libraries=['upb_pic'], + ), + ], + packages=['upb'] + ) diff --git a/bindings/python/test.py b/bindings/python/test.py new file mode 100644 index 0000000..29a6c45 --- /dev/null +++ b/bindings/python/test.py @@ -0,0 +1,72 @@ + +import upb +import unittest + +class TestFieldDef(unittest.TestCase): + def test_construction(self): + fielddef1 = upb.FieldDef() + self.assertTrue(fielddef1.number is None) + self.assertTrue(fielddef1.name is None) + self.assertTrue(fielddef1.type is None) + self.assertEqual(fielddef1.label, upb.LABEL_OPTIONAL) + + fielddef2 = upb.FieldDef(number=5, name="field2", + label=upb.LABEL_REQUIRED, type=upb.TYPE_INT32, + type_name="MyType") + + self.assertTrue(id(fielddef1) != id(fielddef2)) + self.assertEqual(fielddef2.number, 5) + self.assertEqual(fielddef2.name, "field2") + self.assertEqual(fielddef2.label, upb.LABEL_REQUIRED) + self.assertEqual(fielddef2.type, upb.TYPE_INT32) + self.assertEqual(fielddef2.type_name, "MyType") + + fielddef2.number = 8 + self.assertEqual(fielddef2.number, 8) + + fielddef2.name = "xxx" + self.assertEqual(fielddef2.name, "xxx") + + fielddef2.label = upb.LABEL_REPEATED + self.assertEqual(fielddef2.label, upb.LABEL_REPEATED) + + fielddef2.type = upb.TYPE_FLOAT + self.assertEqual(fielddef2.type, upb.TYPE_FLOAT) + + def test_nosubclasses(self): + def create_subclass(): + class MyClass(upb.FieldDef): + pass + + self.assertRaises(TypeError, create_subclass) + + # TODO: test that assigning invalid values is properly prevented. + +class TestMessageDef(unittest.TestCase): + def test_construction(self): + msgdef1 = upb.MessageDef() + self.assertTrue(msgdef1.fqname is None) + self.assertEqual(msgdef1.fields(), []) + + fields = [upb.FieldDef(number=1, name="field1", type=upb.TYPE_INT32)] + msgdef2 = upb.MessageDef(fqname="Message2", fields=fields) + + self.assertEqual(set(msgdef2.fields()), set(fields)) + + f2 = upb.FieldDef(number=2, name="field2", type=upb.TYPE_INT64) + msgdef2.add_field(f2) + + fields.append(f2) + self.assertEqual(set(msgdef2.fields()), set(fields)) + +class TestSymbolTable(unittest.TestCase): + def test_construction(self): + s = upb.SymbolTable() + self.assertEqual(s.defs(), []); + + s.add_def(upb.MessageDef(fqname="A")) + self.assertTrue(s.lookup("A") is not None) + self.assertTrue(s.lookup("A") is s.lookup("A")) + +if __name__ == '__main__': + unittest.main() diff --git a/bindings/python/upb.c b/bindings/python/upb.c new file mode 100644 index 0000000..ffb3d52 --- /dev/null +++ b/bindings/python/upb.c @@ -0,0 +1,724 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2009 Google Inc. See LICENSE for details. + * Author: Josh Haberman + * + * Python extension exposing the core of upb: definitions, handlers, + * and a message type. + */ + +#include +#include +#include "upb/def.h" +#include "upb/msg.h" + +static bool streql(const char *a, const char *b) { return strcmp(a, b) == 0; } + +PyObject *PyUpb_Error(const char *str) { + PyErr_SetString(PyExc_TypeError, str); + return NULL; +} + +int PyUpb_ErrorInt(const char *str) { + PyErr_SetString(PyExc_TypeError, str); + return -1; +} + +#define PyUpb_CheckStatus(status) \ + if (!upb_ok(status)) return PyUpb_Error((status)->str); + +static upb_accessor_vtbl *PyUpb_AccessorForField(upb_fielddef *f); + + +/* Object cache ***************************************************************/ + +// For objects that are just wrappers around a C object pointer, we keep a +// cache mapping C pointer -> wrapper object. This allows us to consistently +// vend the same Python object given the same C object. This prevents us from +// creating too many Python objects unnecessarily. More importantly, it provides +// the expected semantics: +// +// if field.subdef is field.subdef: +// print "Sanity prevails." +// +// If we conjured up a new wrapper object every time, the above would not be +// true. +// +// The cost is having to put all such objects in a table, but since this only +// applies to schema-level objects (defs, handlers, etc) this seems acceptable. +// We do *not* have to put all message objects in this table. +// +// We use weak refs so that the cache does not prevent the wrapper objects from +// being collected. The table is stored as a static variable; to use +// sub-interpreters this would need to change, but I believe that using +// sub-interpreters is exceedingly rare in practice. + +typedef struct { + PyObject_HEAD; + void *obj; + PyObject *weakreflist; +} PyUpb_ObjWrapper; + +static PyObject *obj_cache = NULL; +static PyObject *reverse_cache = NULL; +static PyObject *weakref_callback = NULL; + +// Utility functions for manipulating Python dictionaries keyed by pointer. + +static PyObject *PyUpb_StringForPointer(void *ptr) { + PyObject *o = PyString_FromStringAndSize((const char *)&ptr, sizeof(void*)); + assert(o); + return o; +} + +static PyObject *PyUpb_ObjCacheDeleteCallback(PyObject *self, PyObject *ref) { + // Python very unfortunately clears the weakref before running our callback. + // This prevents us from using the weakref to find the C pointer we need to + // remove from the cache. As a result we are forced to keep a second map + // mapping weakref->C pointer. + PyObject *ptr_str = PyDict_GetItem(reverse_cache, ref); + assert(ptr_str); + int err = PyDict_DelItem(obj_cache, ptr_str); + assert(!err); + err = PyDict_DelItem(reverse_cache, ref); + assert(!err); + return Py_None; +} + +static PyObject *PyUpb_ObjCacheGet(void *obj, PyTypeObject *type) { + PyObject *kv = PyUpb_StringForPointer(obj); + PyObject *ref = PyDict_GetItem(obj_cache, kv); + PyObject *ret; + if (ref) { + ret = PyWeakref_GetObject(ref); + assert(ret != Py_None); + Py_INCREF(ret); + } else { + PyUpb_ObjWrapper *wrapper = (PyUpb_ObjWrapper*)type->tp_alloc(type, 0); + wrapper->obj = obj; + wrapper->weakreflist = NULL; + ret = (PyObject*)wrapper; + ref = PyWeakref_NewRef(ret, weakref_callback); + assert(PyWeakref_GetObject(ref) == ret); + assert(ref); + PyDict_SetItem(obj_cache, kv, ref); + PyDict_SetItem(reverse_cache, ref, kv); + } + assert(ret); + Py_DECREF(kv); + return ret; +} + + +/* PyUpb_Def ******************************************************************/ + +static PyTypeObject *PyUpb_TypeForDef(upb_def *def); + +static void PyUpb_Def_dealloc(PyObject *obj) { + PyUpb_ObjWrapper *wrapper = (void*)obj; + upb_def_unref((upb_def*)wrapper->obj); + obj->ob_type->tp_free(obj); +} + +PyObject *PyUpb_Def_GetOrCreate(upb_def *def) { + return def ? PyUpb_ObjCacheGet(def, PyUpb_TypeForDef(def)) : Py_None; +} + +// Will need to expand once other kinds of defs are supported. +#define Check_Def(o, badret) Check_MessageDef(o, badret) + + +/* PyUpb_FieldDef *************************************************************/ + +static PyTypeObject PyUpb_FieldDefType; +static int PyUpb_FieldDef_setattro(PyObject *o, PyObject *key, PyObject *val); + +#define Check_FieldDef(o, badret) \ + (void*)(((PyUpb_ObjWrapper*)o)->obj); do { \ + if(!PyObject_TypeCheck(o, &PyUpb_FieldDefType)) { \ + PyErr_SetString(PyExc_TypeError, "must be a upb.FieldDef"); \ + return badret; \ + } \ + } while(0) + +static PyObject *PyUpb_FieldDef_GetOrCreate(upb_fielddef *f) { + return PyUpb_ObjCacheGet(f, &PyUpb_FieldDefType); +} + +static PyObject *PyUpb_FieldDef_new(PyTypeObject *subtype, + PyObject *args, PyObject *kwds) { + return PyUpb_ObjCacheGet(upb_fielddef_new(), subtype); +} + +static int PyUpb_FieldDef_init(PyObject *self, PyObject *args, PyObject *kwds) { + if (!kwds) return 0; + PyObject *key, *value; + Py_ssize_t pos = 0; + while (PyDict_Next(kwds, &pos, &key, &value)) + PyUpb_FieldDef_setattro(self, key, value); + return 0; +} + +static void PyUpb_FieldDef_dealloc(PyObject *obj) { + PyUpb_ObjWrapper *wrapper = (void*)obj; + if (wrapper->weakreflist) PyObject_ClearWeakRefs(obj); + upb_fielddef_unref((upb_fielddef*)wrapper->obj); + obj->ob_type->tp_free(obj); +} + +static PyObject *PyUpb_FieldDef_getattro(PyObject *obj, PyObject *attr_name) { + upb_fielddef *f = Check_FieldDef(obj, NULL); + if (!upb_fielddef_ismutable(f)) { + PyErr_SetString(PyExc_TypeError, "fielddef is not mutable."); + return NULL; + } + const char *name = PyString_AsString(attr_name); + if (streql(name, "name")) { + const char *name = upb_fielddef_name(f); + return name == NULL ? Py_None : PyString_FromString(name); + } else if (streql(name, "number")) { + uint32_t num = upb_fielddef_number(f); + return num == 0 ? Py_None : PyInt_FromLong(num); + } else if (streql(name, "type")) { + uint8_t type = upb_fielddef_type(f); + return type == 0 ? Py_None : PyInt_FromLong(type); + } else if (streql(name, "label")) { + return PyInt_FromLong(upb_fielddef_label(f)); + } else if (streql(name, "type_name")) { + const char *name = upb_fielddef_typename(f); + return name == NULL ? Py_None : PyString_FromString(name); + } else if (streql(name, "subdef")) { + // NYI; + return NULL; + } else if (streql(name, "msgdef")) { + // NYI; + return NULL; + } else { + return PyUpb_Error("Invalid fielddef member."); + } +} + +static int PyUpb_FieldDef_setattro(PyObject *o, PyObject *key, PyObject *val) { + upb_fielddef *f = Check_FieldDef(o, -1); + const char *field = PyString_AsString(key); + if (!upb_fielddef_ismutable(f)) + return PyUpb_ErrorInt("fielddef is not mutable."); + if (streql(field, "name")) { + const char *name = PyString_AsString(val); + if (!name || !upb_fielddef_setname(f, name)) + return PyUpb_ErrorInt("Invalid name"); + } else if (streql(field, "number")) { + // TODO: should check truncation. Non-security issue. + // Non-int will return -1, which is already invalid as a field number. + if (!upb_fielddef_setnumber(f, PyInt_AsLong(val))) + return PyUpb_ErrorInt("Invalid number"); + } else if (streql(field, "type")) { + // TODO: should check truncation. Non-security issue. + if (!upb_fielddef_settype(f, PyInt_AsLong(val))) + return PyUpb_ErrorInt("Invalid type"); + } else if (streql(field, "label")) { + // TODO: should check truncation. Non-security issue. + if (!upb_fielddef_setlabel(f, PyInt_AsLong(val))) + return PyUpb_ErrorInt("Invalid label"); + } else if (streql(field, "type_name")) { + const char *name = PyString_AsString(val); + if (!name || !upb_fielddef_settypename(f, name)) + return PyUpb_ErrorInt("Invalid type_name"); + } else if (streql(field, "default_value")) { + // NYI + return -1; + } else { + return PyUpb_ErrorInt("Invalid fielddef member."); + } + return 0; +} + +static PyTypeObject PyUpb_FieldDefType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "upb.FieldDef", /* tp_name */ + sizeof(PyUpb_ObjWrapper), /* tp_basicsize */ + 0, /* tp_itemsize */ + &PyUpb_FieldDef_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* TODO */ /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + &PyUpb_FieldDef_getattro, /* tp_getattro */ + &PyUpb_FieldDef_setattro, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(PyUpb_ObjWrapper, weakreflist),/* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + 0, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + &PyUpb_FieldDef_init, /* tp_init */ + 0, /* tp_alloc */ + &PyUpb_FieldDef_new, /* tp_new */ + 0, /* tp_free */ +}; + + +/* PyUpb_MessageDef ***********************************************************/ + +static PyTypeObject PyUpb_MessageDefType; +static int PyUpb_MessageDef_setattro(PyObject *o, PyObject *key, PyObject *val); + +#define Check_MessageDef(o, badret) \ + (void*)(((PyUpb_ObjWrapper*)o)->obj); do { \ + if(!PyObject_TypeCheck(o, &PyUpb_MessageDefType)) { \ + PyErr_SetString(PyExc_TypeError, "must be a upb.MessageDef"); \ + return badret; \ + } \ + } while(0) + +static PyObject *PyUpb_MessageDef_new(PyTypeObject *subtype, + PyObject *args, PyObject *kwds) { + return PyUpb_ObjCacheGet(upb_msgdef_new(), subtype); +} + +static PyObject *PyUpb_MessageDef_add_fields(PyObject *o, PyObject *args); + +static int PyUpb_MessageDef_init(PyObject *self, PyObject *args, PyObject *kwds) { + if (!kwds) return 0; + PyObject *key, *value; + Py_ssize_t pos = 0; + while (PyDict_Next(kwds, &pos, &key, &value)) { + const char *field = PyString_AsString(key); + if (streql(field, "fields")) { + PyUpb_MessageDef_add_fields(self, value); + } else { + PyUpb_MessageDef_setattro(self, key, value); + } + } + return 0; +} + +static PyObject *PyUpb_MessageDef_getattro(PyObject *obj, PyObject *attr_name) { + upb_msgdef *m = Check_MessageDef(obj, NULL); + const char *name = PyString_AsString(attr_name); + if (streql(name, "fqname")) { + const char *fqname = upb_def_fqname(UPB_UPCAST(m)); + return fqname == NULL ? Py_None : PyString_FromString(fqname); + } + return PyObject_GenericGetAttr(obj, attr_name); +} + +static int PyUpb_MessageDef_setattro(PyObject *o, PyObject *key, PyObject *val) { + upb_msgdef *m = Check_MessageDef(o, -1); + if (!upb_def_ismutable(UPB_UPCAST(m))) { + PyErr_SetString(PyExc_TypeError, "MessageDef is not mutable."); + return -1; + } + const char *name = PyString_AsString(key); + if (streql(name, "fqname")) { + const char *fqname = PyString_AsString(val); + if (!fqname || !upb_def_setfqname(UPB_UPCAST(m), fqname)) + return PyUpb_ErrorInt("Invalid fqname"); + } else { + return PyUpb_ErrorInt("Invalid MessageDef member."); + } + return 0; +} + +static PyObject *PyUpb_MessageDef_fields(PyObject *obj, PyObject *args) { + upb_msgdef *m = Check_MessageDef(obj, NULL); + PyObject *ret = PyList_New(0); + upb_msg_iter i; + for(i = upb_msg_begin(m); !upb_msg_done(i); i = upb_msg_next(m, i)) { + upb_fielddef *f = upb_msg_iter_field(i); + PyList_Append(ret, PyUpb_FieldDef_GetOrCreate(f)); + } + return ret; +} + +static PyObject *PyUpb_MessageDef_add_fields(PyObject *o, PyObject *fields) { + upb_msgdef *m = Check_MessageDef(o, NULL); + if (!PySequence_Check(fields)) return PyUpb_Error("Must be a sequence"); + Py_ssize_t len = PySequence_Length(fields); + if (len > UPB_MAX_FIELDS) return PyUpb_Error("Too many fields."); + upb_fielddef *f[len]; + int i; + for (i = 0; i < len; i++) { + PyObject *field = PySequence_GetItem(fields, i); + f[i] = Check_FieldDef(field, NULL); + } + upb_msgdef_addfields(m, f, len); + return Py_None; +} + +static PyObject *PyUpb_MessageDef_add_field(PyObject *o, PyObject *field) { + upb_msgdef *m = Check_MessageDef(o, NULL); + upb_fielddef *f = Check_FieldDef(field, NULL); + upb_msgdef_addfield(m, f); + return Py_None; +} + +static PyMethodDef PyUpb_MessageDef_methods[] = { + {"add_field", &PyUpb_MessageDef_add_field, METH_O, "Adds a list of fields."}, + {"add_fields", &PyUpb_MessageDef_add_fields, METH_O, "Adds a list of fields."}, + {"fields", &PyUpb_MessageDef_fields, METH_NOARGS, "Returns list of fields."}, + {NULL, NULL} +}; + +static PyTypeObject PyUpb_MessageDefType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "upb.MessageDef", /* tp_name */ + sizeof(PyUpb_ObjWrapper), /* tp_basicsize */ + 0, /* tp_itemsize */ + &PyUpb_Def_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* TODO */ /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + &PyUpb_MessageDef_getattro, /* tp_getattro */ + &PyUpb_MessageDef_setattro, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(PyUpb_ObjWrapper, weakreflist),/* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + PyUpb_MessageDef_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + &PyUpb_MessageDef_init, /* tp_init */ + 0, /* tp_alloc */ + &PyUpb_MessageDef_new, /* tp_new */ + 0, /* tp_free */ +}; + + +static PyTypeObject *PyUpb_TypeForDef(upb_def *def) { + switch(def->type) { + case UPB_DEF_MSG: return &PyUpb_MessageDefType; + default: return NULL; + } +} + +/* PyUpb_SymbolTable **********************************************************/ + +static PyTypeObject PyUpb_SymbolTableType; + +#define Check_SymbolTable(o, badret) \ + (void*)(((PyUpb_ObjWrapper*)o)->obj); do { \ + if(!PyObject_TypeCheck(o, &PyUpb_SymbolTableType)) { \ + PyErr_SetString(PyExc_TypeError, "must be a upb.MessageDef"); \ + return badret; \ + } \ + } while(0) + +static PyObject *PyUpb_SymbolTable_new(PyTypeObject *subtype, + PyObject *args, PyObject *kwds) { + return PyUpb_ObjCacheGet(upb_symtab_new(), subtype); +} + +static int PyUpb_SymbolTable_init(PyObject *self, PyObject *args, PyObject *kwds) { + return 0; +} + +static void PyUpb_SymbolTable_dealloc(PyObject *obj) { + PyUpb_ObjWrapper *wrapper = (void*)obj; + upb_symtab_unref((upb_symtab*)wrapper->obj); + obj->ob_type->tp_free(obj); +} + +// narg is a lua table containing a list of defs to add. +static PyObject *PyUpb_SymbolTable_add_defs(PyObject *o, PyObject *defs) { + upb_symtab *s = Check_SymbolTable(o, NULL); + if (!PySequence_Check(defs)) return PyUpb_Error("Must be a sequence"); + Py_ssize_t n = PySequence_Length(defs); + + // Prevent stack overflow. + if (n > 2048) return PyUpb_Error("Too many defs"); + upb_def *cdefs[n]; + + int i = 0; + for (i = 0; i < n; i++) { + PyObject *pydef = PySequence_GetItem(defs, i); + upb_def *def = Check_MessageDef(pydef, NULL); + cdefs[i++] = def; + upb_msgdef *md = upb_dyncast_msgdef(def); + if (!md) continue; + upb_msg_iter j; + for(j = upb_msg_begin(md); !upb_msg_done(j); j = upb_msg_next(md, j)) { + upb_fielddef *f = upb_msg_iter_field(j); + upb_fielddef_setaccessor(f, PyUpb_AccessorForField(f)); + } + upb_msgdef_layout(md); + } + + upb_status status = UPB_STATUS_INIT; + upb_symtab_add(s, cdefs, n, &status); + PyUpb_CheckStatus(&status); + return Py_None; +} + +static PyObject *PyUpb_SymbolTable_add_def(PyObject *o, PyObject *def) { + PyObject *defs = PyList_New(1); + PyList_SetItem(defs, 0, def); + return PyUpb_SymbolTable_add_defs(o, defs); +} + +// TODO: update to allow user to choose type of defs. +static PyObject *PyUpb_SymbolTable_defs(PyObject *o, PyObject *none) { + upb_symtab *s = Check_SymbolTable(o, NULL); + int count; + upb_def **defs = upb_symtab_getdefs(s, &count, UPB_DEF_ANY); + PyObject *ret = PyList_New(count); + int i; + for(i = 0; i < count; i++) + PyList_SetItem(ret, i, PyUpb_Def_GetOrCreate(defs[i])); + return ret; +} + +static PyObject *PyUpb_SymbolTable_lookup(PyObject *o, PyObject *arg) { + upb_symtab *s = Check_SymbolTable(o, NULL); + const char *name = PyString_AsString(arg); + upb_def *def = upb_symtab_lookup(s, name); + return PyUpb_Def_GetOrCreate(def); +} + +static PyMethodDef PyUpb_SymbolTable_methods[] = { + {"add_def", &PyUpb_SymbolTable_add_def, METH_O, NULL}, + {"add_defs", &PyUpb_SymbolTable_add_defs, METH_O, NULL}, + {"defs", &PyUpb_SymbolTable_defs, METH_NOARGS, NULL}, + {"lookup", &PyUpb_SymbolTable_lookup, METH_O, NULL}, + {NULL, NULL} +}; + +static PyTypeObject PyUpb_SymbolTableType = { + PyObject_HEAD_INIT(NULL) + 0, /* ob_size */ + "upb.SymbolTable", /* tp_name */ + sizeof(PyUpb_ObjWrapper), /* tp_basicsize */ + 0, /* tp_itemsize */ + &PyUpb_SymbolTable_dealloc, /* tp_dealloc */ + 0, /* tp_print */ + 0, /* tp_getattr */ + 0, /* tp_setattr */ + 0, /* tp_compare */ + 0, /* TODO */ /* tp_repr */ + 0, /* tp_as_number */ + 0, /* tp_as_sequence */ + 0, /* tp_as_mapping */ + 0, /* tp_hash */ + 0, /* tp_call */ + 0, /* tp_str */ + 0, /* tp_getattro */ + 0, /* tp_setattro */ + 0, /* tp_as_buffer */ + Py_TPFLAGS_DEFAULT, /* tp_flags */ + 0, /* tp_doc */ + 0, /* tp_traverse */ + 0, /* tp_clear */ + 0, /* tp_richcompare */ + offsetof(PyUpb_ObjWrapper, weakreflist),/* tp_weaklistoffset */ + 0, /* tp_iter */ + 0, /* tp_iternext */ + PyUpb_SymbolTable_methods, /* tp_methods */ + 0, /* tp_members */ + 0, /* tp_getset */ + 0, /* tp_base */ + 0, /* tp_dict */ + 0, /* tp_descr_get */ + 0, /* tp_descr_set */ + 0, /* tp_dictoffset */ + &PyUpb_SymbolTable_init, /* tp_init */ + 0, /* tp_alloc */ + &PyUpb_SymbolTable_new, /* tp_new */ + 0, /* tp_free */ +}; + + +/* Accessor and PyUpb_Message *************************************************/ + +typedef struct { + PyTypeObject type; + PyTypeObject *alt_type; +} PyUpb_MessageType; + +typedef struct { + PyObject_HEAD; + PyObject *msgdef; + char data[1]; +} PyUpb_Message; + +PyObject **PyUpb_Accessor_GetPtr(PyObject *_m, upb_value fval) { + PyUpb_Message *m = (PyUpb_Message*)_m; + upb_fielddef *f = upb_value_getfielddef(fval); + return (PyObject**)&m->data[f->offset]; +} + +static upb_sflow_t PyUpb_Message_StartSequence(void *m, upb_value fval) { + PyObject **seq = PyUpb_Accessor_GetPtr(m, fval); + PyTypeObject *type = ((PyUpb_MessageType*)Py_TYPE(m))->alt_type; + if (!*seq) *seq = type->tp_alloc(type, 0); + upb_stdmsg_sethas(m, fval); + return UPB_CONTINUE_WITH(*seq); +} + +static upb_sflow_t PyUpb_Message_StartSubmessage(void *m, upb_value fval) { + PyObject **submsg = PyUpb_Accessor_GetPtr(m, fval); + PyTypeObject *type = Py_TYPE(m); + if (!*submsg) *submsg = type->tp_alloc(type, 0); + upb_stdmsg_sethas(m, fval); + return UPB_CONTINUE_WITH(*submsg); +} + +static upb_sflow_t PyUpb_Message_StartRepeatedSubmessage(void *a, upb_value fval) { + (void)fval; + PyObject **elem = upb_stdarray_append(a, sizeof(void*)); + PyTypeObject *type = ((PyUpb_MessageType*)Py_TYPE(a))->alt_type; + if (!*elem) *elem = type->tp_alloc(type, 0); + return UPB_CONTINUE_WITH(*elem); +} + +static upb_flow_t PyUpb_Message_StringValue(void *m, upb_value fval, upb_value val) { + PyObject **str = PyUpb_Accessor_GetPtr(m, fval); + if (*str) Py_DECREF(*str); + *str = PyString_FromStringAndSize(NULL, upb_value_getstrref(val)->len); + upb_strref_read(upb_value_getstrref(val), PyString_AsString(*str)); + upb_stdmsg_sethas(m, fval); + return UPB_CONTINUE; +} + +static upb_flow_t PyUpb_Message_AppendStringValue(void *a, upb_value fval, upb_value val) { + (void)fval; + PyObject **elem = upb_stdarray_append(a, sizeof(void*)); + *elem = PyString_FromStringAndSize(NULL, upb_value_getstrref(val)->len); + upb_strref_read(upb_value_getstrref(val), PyString_AsString(*elem)); + return UPB_CONTINUE; +} + +#define STDMSG(type, size) static upb_accessor_vtbl vtbl = { \ + &PyUpb_Message_StartSubmessage, \ + &upb_stdmsg_set ## type, \ + &PyUpb_Message_StartSequence, \ + &PyUpb_Message_StartRepeatedSubmessage, \ + &upb_stdmsg_set ## type ## _r, \ + &upb_stdmsg_has, \ + &upb_stdmsg_getptr, \ + &upb_stdmsg_get ## type, \ + &upb_stdmsg_seqbegin, \ + &upb_stdmsg_ ## size ## byte_seqnext, \ + &upb_stdmsg_seqget ## type}; + +#define RETURN_STDMSG(type, size) { STDMSG(type, size); return &vtbl; } + +static upb_accessor_vtbl *PyUpb_AccessorForField(upb_fielddef *f) { + switch (f->type) { + case UPB_TYPE(DOUBLE): RETURN_STDMSG(double, 8) + case UPB_TYPE(FLOAT): RETURN_STDMSG(float, 4) + case UPB_TYPE(UINT64): + case UPB_TYPE(FIXED64): RETURN_STDMSG(uint64, 8) + case UPB_TYPE(INT64): + case UPB_TYPE(SFIXED64): + case UPB_TYPE(SINT64): RETURN_STDMSG(int64, 8) + case UPB_TYPE(INT32): + case UPB_TYPE(SINT32): + case UPB_TYPE(ENUM): + case UPB_TYPE(SFIXED32): RETURN_STDMSG(int32, 4) + case UPB_TYPE(UINT32): + case UPB_TYPE(FIXED32): RETURN_STDMSG(uint32, 4) + case UPB_TYPE(BOOL): { STDMSG(bool, 1); return &vtbl; } + case UPB_TYPE(GROUP): + case UPB_TYPE(MESSAGE): RETURN_STDMSG(ptr, 8) // TODO: 32-bit + case UPB_TYPE(STRING): + case UPB_TYPE(BYTES): { + STDMSG(ptr, 8); + vtbl.set = &PyUpb_Message_StringValue; + vtbl.append = &PyUpb_Message_AppendStringValue; + return &vtbl; + } + } + return NULL; +} + + +/* Toplevel *******************************************************************/ + +static PyMethodDef methods[] = { + {NULL, NULL} +}; + +// PyModule_AddObject steals a ref, but our object is statically allocated +// and must not be deleted. +#define PyUpb_AddType(mod, name, type) \ + if (PyType_Ready(type) < 0) return; \ + Py_INCREF(type); \ + PyModule_AddObject(mod, name, (PyObject*)type); + +PyMODINIT_FUNC initupb(void) { + PyObject *mod = Py_InitModule("upb", methods); + + PyUpb_AddType(mod, "FieldDef", &PyUpb_FieldDefType); + PyUpb_AddType(mod, "MessageDef", &PyUpb_MessageDefType); + PyUpb_AddType(mod, "SymbolTable", &PyUpb_SymbolTableType); + + PyModule_AddIntConstant(mod, "LABEL_OPTIONAL", UPB_LABEL(OPTIONAL)); + PyModule_AddIntConstant(mod, "LABEL_REQUIRED", UPB_LABEL(REQUIRED)); + PyModule_AddIntConstant(mod, "LABEL_REPEATED", UPB_LABEL(REPEATED)); + + PyModule_AddIntConstant(mod, "TYPE_DOUBLE", UPB_TYPE(DOUBLE)); + PyModule_AddIntConstant(mod, "TYPE_FLOAT", UPB_TYPE(FLOAT)); + PyModule_AddIntConstant(mod, "TYPE_INT64", UPB_TYPE(INT64)); + PyModule_AddIntConstant(mod, "TYPE_UINT64", UPB_TYPE(UINT64)); + PyModule_AddIntConstant(mod, "TYPE_INT32", UPB_TYPE(INT32)); + PyModule_AddIntConstant(mod, "TYPE_FIXED64", UPB_TYPE(FIXED64)); + PyModule_AddIntConstant(mod, "TYPE_FIXED32", UPB_TYPE(FIXED32)); + PyModule_AddIntConstant(mod, "TYPE_BOOL", UPB_TYPE(BOOL)); + PyModule_AddIntConstant(mod, "TYPE_STRING", UPB_TYPE(STRING)); + PyModule_AddIntConstant(mod, "TYPE_GROUP", UPB_TYPE(GROUP)); + PyModule_AddIntConstant(mod, "TYPE_MESSAGE", UPB_TYPE(MESSAGE)); + PyModule_AddIntConstant(mod, "TYPE_BYTES", UPB_TYPE(BYTES)); + PyModule_AddIntConstant(mod, "TYPE_UINT32", UPB_TYPE(UINT32)); + PyModule_AddIntConstant(mod, "TYPE_ENUM", UPB_TYPE(ENUM)); + PyModule_AddIntConstant(mod, "TYPE_SFIXED32", UPB_TYPE(SFIXED32)); + PyModule_AddIntConstant(mod, "TYPE_SFIXED64", UPB_TYPE(SFIXED64)); + PyModule_AddIntConstant(mod, "TYPE_SINT32", UPB_TYPE(SINT32)); + PyModule_AddIntConstant(mod, "TYPE_SINT64", UPB_TYPE(SINT64)); + + obj_cache = PyDict_New(); + reverse_cache = PyDict_New(); + static PyMethodDef method = { + "WeakRefCallback", &PyUpb_ObjCacheDeleteCallback, METH_O, NULL}; + PyObject *pyname = PyString_FromString(method.ml_name); + weakref_callback = PyCFunction_NewEx(&method, NULL, pyname); + Py_DECREF(pyname); +} diff --git a/bindings/python/upb/__init__.py b/bindings/python/upb/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/lang_ext/cpp/upb/handlers.hpp b/lang_ext/cpp/upb/handlers.hpp deleted file mode 100644 index b083f15..0000000 --- a/lang_ext/cpp/upb/handlers.hpp +++ /dev/null @@ -1,142 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2011 Google Inc. See LICENSE for details. - * Author: Josh Haberman - * - * Note! This file is a proof-of-concept for C++ wrappers and does not - * yet build. - * - * upb::Handlers is a generic visitor-like interface for iterating over a - * stream of protobuf data. You can register function pointers that will be - * called for each message and/or field as the data is being parsed or iterated - * over, without having to know the source format that we are parsing from. - * This decouples the parsing logic from the processing logic. - */ - -#ifndef UPB_HANDLERS_HPP -#define UPB_HANDLERS_HPP - -#include "upb_handlers.h" - -namespace upb { - -typedef upb_flow_t Flow; - -class FieldHandlers : public upb_fhandlers { - public: - typedef upb_value_handler ValueHandler; - typedef upb_startfield_handler StartFieldHandler; - typedef upb_endfield_handler EndFieldHandler; - - // The FieldHandlers will live at least as long as the upb::Handlers to - // which it belongs, but can be Ref'd/Unref'd to make it live longer (which - // will prolong the life of the underlying upb::Handlers also). - void Ref() { upb_fhandlers_ref(this); } - void Unref() { upb_fhandlers_unref(this); } - - // Functions to set this field's handlers. - // These return "this" so they can be conveniently chained, eg. - // message_handlers->NewField(...) - // ->SetStartSequenceHandler(&StartSequence), - // ->SetEndSequenceHandler(&EndSequence), - // ->SetValueHandler(&Value); - FieldHandlers* SetValueHandler(ValueHandler* h) { - upb_fhandlers_setvalue(this, h); return this; - } - FieldHandlers* SetStartSequenceHandler(StartFieldHandler* h) { - upb_fhandlers_setstartseq(this, h); return this; - } - FieldHandlers* SetEndSequenceHandler(EndFieldHandler* h) { - upb_fhandlers_endseq(this, h); return this; - } - FieldHandlers* SetStartSubmessageHandler(StartFieldHandler* h) { - upb_fhandlers_setstartsubmsg(this, h); return this; - } - FieldHandlers* SetEndSubmessageHandler(EndFieldHandler* h) { - upb_fhandlers_endsubmsg(this, h); return this; - } - - // Get/Set the field's bound value, which will be passed to its handlers. - Value GetBoundValue() { return upb_fhandlers_getfval(this); } - FieldHandlers* SetBoundValue(Value val) { - upb_fhandlers_setfval(this, val); return this; - } - - private: - FieldHandlers(); // Only created by upb::Handlers. - ~FieldHandlers(); // Only destroyed by refcounting. -}; - - -class MessageHandlers : public upb_mhandlers { - public: - typedef upb_startmsg_handler StartMessageHandler; - typedef upb_endmsg_handler EndMessageHandler; - - // The MessageHandlers will live at least as long as the upb::Handlers to - // which it belongs, but can be Ref'd/Unref'd to make it live longer (which - // will prolong the life of the underlying upb::Handlers also). - void Ref() { upb_mhandlers_ref(this); } - void Unref() { upb_mhandlers_unref(this); } - - // Functions to set this message's handlers. - // These return "this" so they can be conveniently chained, eg. - // handlers->NewMessage() - // ->SetStartMessageHandler(&StartMessage) - // ->SetEndMessageHandler(&EndMessage); - MessageHandlers* SetStartMessageHandler(StartMessageHandler* h) { - upb_mhandlers_setstartmsg(this, h); return this; - } - MessageHandlers* SetEndMessageHandler(EndMessageHandler* h) { - upb_mhandlers_setendmsg(this, h); return this; - } - - // Functions to create new FieldHandlers for this message. - FieldHandlers* NewFieldHandlers(uint32_t fieldnum, upb_fieldtype_t type, - bool repeated) { - return upb_mhandlers_newfhandlers(this, fieldnum, type, repeated); - } - FieldHandlers* NewFieldHandlers(FieldDef* f) { - return upb_mhandlers_newfhandlers_fordef(f); - } - - // Like the previous but for MESSAGE or GROUP fields. For GROUP fields, the - // given submessage must not have any fields with this field number. - FieldHandlers* NewFieldHandlersForSubmessage(uint32_t n, FieldType type, - bool repeated, - MessageHandlers* subm) { - return upb_mhandlers_newsubmsgfhandlers(this, n, type, repeated, subm); - } - - FieldHandlers* NewFieldHandlersForSubmessage(FieldDef* f, - MessageHandlers* subm) { - return upb_mhandlers_newsubmsgfhandlers_fordef(f); - } - - - private: - MessageHandlers(); // Only created by upb::Handlers. - ~MessageHandlers(); // Only destroyed by refcounting. -}; - -class Handlers : public upb_handlers { - public: - // Creates a new Handlers instance. - Handlers* New() { return static_cast(upb_handlers_new()); } - - void Ref() { upb_handlers_ref(this); } - void Unref() { upb_handlers_unref(this); } - - // Returns a new MessageHandlers object. The first such message that is - // obtained will be the top-level message for this Handlers object. - MessageHandlers* NewMessageHandlers() { return upb_handlers_newmhandlers(); } - - private: - FieldHandlers(); // Only created by Handlers::New(). - ~FieldHandlers(); // Only destroyed by refcounting. -}; - -} // namespace upb - -#endif diff --git a/lang_ext/lua/test.lua b/lang_ext/lua/test.lua deleted file mode 100644 index 42bce25..0000000 --- a/lang_ext/lua/test.lua +++ /dev/null @@ -1,109 +0,0 @@ - -require "upb" - -symtab = upb.SymbolTable{ - upb.MessageDef{fqname="A", fields={ - upb.FieldDef{name="a", type=upb.TYPE_INT32, number=1}, - upb.FieldDef{name="b", type=upb.TYPE_DOUBLE, number=2}} - } -} - -symtab = upb.SymbolTable{ - upb.MessageDef{fqname="A", fields={ - upb.FieldDef{name="a", type=upb.TYPE_INT32, number=1}, - upb.FieldDef{name="b", type=upb.TYPE_DOUBLE, number=2}} - }, - upb.MessageDef{fqname="B"} -} -A, B, C = symtab:lookup("A", "B") -print(A) -print(B) -print(C) - -a = A() -a2 = upb.Message(A) -print("YO! a.a=" .. tostring(a.a) .. ", a2.a=" .. tostring(a2.a)) -a.a = 2 -a2.a = 3 -print("YO! a.a=" .. tostring(a.a) .. ", a2.a=" .. tostring(a2.a)) - -A = symtab:lookup("A") -if not A then - error("Could not find A") -end - -f = io.open("../../upb/descriptor.pb") -if not f then - error("Couldn't open descriptor.pb, try running 'make descriptorgen'") -end -symtab:parsedesc(f:read("*all")) -symtab:load_descriptor() -symtab:load_descriptor_file() - -upb.pb.load_descriptor(f:read("*all")) - -upb.pb.load_descriptor_file("../../src/descriptor.pb", symtab) - -f = io.open("../../benchmarks/google_messages.proto.pb") -if not f then - error("Couldn't open google_messages.proto.pb, try running 'make benchmarks'") -end -symtab:parsedesc(f:read("*all")) - -for _, def in ipairs(symtab:getdefs(-1)) do - print(def:name()) -end - -SpeedMessage1 = symtab:lookup("benchmarks.SpeedMessage1") -SpeedMessage2 = symtab:lookup("benchmarks.SpeedMessage2") -print(SpeedMessage1:name()) - -msg = MyType() -msg:Decode(str) - -msg:DecodeJSON(str) - -msg = upb.pb.decode(str, MyType) -str = upb.pb.encode(msg) - -msg = upb.pb.decode_text(str, MyType) -str = upb.pb.encode_text(msg) - -upb.clear(msg) -upb.msgdef(msg) -upb.has(msg, "foo_bar") - -msg = upb.json.decode(str, MyType) - -msg = upb.pb.DecodeText(str) -msg = upb.pb.EncodeText(msg) -upb. - -upb.pb.decode_into(msg, str) - -str = upb.json.Encode(msg) -upb.json.DecodeInto(msg, str) -f = assert(io.open("../../benchmarks/google_message1.dat")) -msg:Parse(f:read("*all")) -print(msg:ToText()) -print(upb.json.encode(msg)) - -msg = SpeedMessage2() -f = assert(io.open("../../benchmarks/google_message2.dat")) -msg:Parse(f:read("*all")) -print(msg:ToText()) ---msg:Serialize() ---msg:FromText(str) --- print(msg.field129) --- print(msg.field271) ---print(msg.field15.field15) ---msg.field15.field15 = "my override" ---print(msg.field15.field15) --- print(msg.field1) --- print(msg.field1) --- msg.field1 = "YEAH BABY!" --- print(msg.field1) --- print(msg.field129) --- msg.field129 = 5 --- print(msg.field129) ---]] diff --git a/lang_ext/lua/upb.c b/lang_ext/lua/upb.c deleted file mode 100644 index fe523e7..0000000 --- a/lang_ext/lua/upb.c +++ /dev/null @@ -1,1012 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2009 Google Inc. See LICENSE for details. - * Author: Josh Haberman - * - * A Lua extension for upb. - */ - -#include -#include -#include -#include "lauxlib.h" -#include "upb/def.h" -#include "upb/msg.h" -#include "upb/pb/glue.h" - -#if LUA_VERSION_NUM == 501 -#define lua_rawlen lua_objlen -#endif - -static bool streql(const char *a, const char *b) { return strcmp(a, b) == 0; } - -static bool lupb_isint(double n) { return (double)(int)n == n; } - -static uint8_t lupb_touint8(lua_State *L, int narg, const char *name) { - lua_Number n = lua_tonumber(L, narg); - if (n > UINT8_MAX || n < 0 || rint(n) != n) - luaL_error(L, "Invalid %s", name); - return n; -} - -static uint32_t lupb_touint32(lua_State *L, int narg, const char *name) { - lua_Number n = lua_tonumber(L, narg); - if (n > UINT32_MAX || n < 0 || rint(n) != n) - luaL_error(L, "Invalid %s", name); - return n; -} - -static void lupb_pushstring(lua_State *L, upb_strref *ref) { - if (ref->ptr) { - lua_pushlstring(L, ref->ptr, ref->len); - } else { - // Lua requires a continguous string; must copy+allocate. - char *str = upb_strref_dup(ref); - lua_pushlstring(L, str, ref->len); - free(str); - } -} - -static void lupb_pushvalue(lua_State *L, upb_value val, upb_fielddef *f) { - switch (f->type) { - case UPB_TYPE(INT32): - case UPB_TYPE(SINT32): - case UPB_TYPE(SFIXED32): - case UPB_TYPE(ENUM): - lua_pushnumber(L, upb_value_getint32(val)); break; - case UPB_TYPE(INT64): - case UPB_TYPE(SINT64): - case UPB_TYPE(SFIXED64): - lua_pushnumber(L, upb_value_getint64(val)); break; - case UPB_TYPE(UINT32): - case UPB_TYPE(FIXED32): - lua_pushnumber(L, upb_value_getuint32(val)); break; - case UPB_TYPE(UINT64): - case UPB_TYPE(FIXED64): - lua_pushnumber(L, upb_value_getuint64(val)); break; - case UPB_TYPE(DOUBLE): - lua_pushnumber(L, upb_value_getdouble(val)); break; - case UPB_TYPE(FLOAT): - lua_pushnumber(L, upb_value_getfloat(val)); break; - case UPB_TYPE(BOOL): - lua_pushboolean(L, upb_value_getbool(val)); break; - default: luaL_error(L, "internal error"); - } -} - -// Returns a scalar value (ie. not a submessage) as a upb_value. -static upb_value lupb_getvalue(lua_State *L, int narg, upb_fielddef *f, - upb_strref *ref) { - assert(!upb_issubmsg(f)); - upb_value val; - 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_value_setbool(&val, lua_toboolean(L, narg)); - } else if (upb_fielddef_type(f) == UPB_TYPE(STRING)) { - size_t len; - ref->ptr = luaL_checklstring(L, narg, &len); - ref->len = len; - upb_value_setstrref(&val, ref); - } else { - // Numeric type. - lua_Number num = 0; - num = luaL_checknumber(L, narg); - switch (upb_fielddef_type(f)) { - case UPB_TYPE(INT32): - case UPB_TYPE(SINT32): - case UPB_TYPE(SFIXED32): - case UPB_TYPE(ENUM): - if (num > INT32_MAX || num < INT32_MIN || num != rint(num)) - luaL_error(L, "Cannot convert %f to 32-bit integer", num); - upb_value_setint32(&val, num); - break; - case UPB_TYPE(INT64): - case UPB_TYPE(SINT64): - case UPB_TYPE(SFIXED64): - if (num > INT64_MAX || num < INT64_MIN || num != rint(num)) - luaL_error(L, "Cannot convert %f to 64-bit integer", num); - upb_value_setint64(&val, num); - break; - case UPB_TYPE(UINT32): - case UPB_TYPE(FIXED32): - if (num > UINT32_MAX || num < 0 || num != rint(num)) - luaL_error(L, "Cannot convert %f to unsigned 32-bit integer", num); - upb_value_setuint32(&val, num); - break; - case UPB_TYPE(UINT64): - case UPB_TYPE(FIXED64): - if (num > UINT64_MAX || num < 0 || num != rint(num)) - luaL_error(L, "Cannot convert %f to unsigned 64-bit integer", num); - upb_value_setuint64(&val, num); - break; - case UPB_TYPE(DOUBLE): - if (num > DBL_MAX || num < -DBL_MAX) { - // This could happen if lua_Number was long double. - luaL_error(L, "Cannot convert %f to double", num); - } - upb_value_setdouble(&val, num); - break; - case UPB_TYPE(FLOAT): - if (num > FLT_MAX || num < -FLT_MAX) - luaL_error(L, "Cannot convert %f to float", num); - upb_value_setfloat(&val, num); - break; - } - } - return val; -} - -static void lupb_typecheck(lua_State *L, int narg, upb_fielddef *f) { - upb_strref ref; - lupb_getvalue(L, narg, f, &ref); -} - -//static void lupb_msg_getorcreate(lua_State *L, upb_msg *msg, upb_msgdef *md); -static void lupb_fielddef_getorcreate(lua_State *L, upb_fielddef *f); -static upb_msgdef *lupb_msgdef_check(lua_State *L, int narg); -static void lupb_msg_pushnew(lua_State *L, void *md); - -void lupb_checkstatus(lua_State *L, upb_status *s) { - if (!upb_ok(s)) { - upb_status_print(s, stderr); - // Need to copy the string to the stack, so we can free it and not leak - // it (since luaL_error() does not return). - char buf[strlen(s->str)+1]; - strcpy(buf, s->str); - upb_status_uninit(s); - luaL_error(L, "%s", buf); - } - upb_status_uninit(s); -} - - -/* object cache ***************************************************************/ - -// We cache all the lua objects (userdata) we vend in a weak table, indexed by -// the C pointer of the object they are caching. - -static void *lupb_cache_getorcreate_size( - lua_State *L, void *cobj, const char *type, size_t size) { - // Lookup our cache in the registry (we don't put our objects in the registry - // directly because we need our cache to be a weak table). - void **obj = NULL; - lua_getfield(L, LUA_REGISTRYINDEX, "upb.objcache"); - assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb. - lua_pushlightuserdata(L, cobj); - lua_rawget(L, -2); - // Stack: objcache, cached value. - if (lua_isnil(L, -1)) { - // Remove bad cached value and push new value. - lua_pop(L, 1); - // We take advantage of the fact that all of our objects are currently a - // single pointer, and thus have the same layout. - obj = lua_newuserdata(L, size); - *obj = cobj; - luaL_getmetatable(L, type); - assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb. - lua_setmetatable(L, -2); - - // Set it in the cache. - lua_pushlightuserdata(L, cobj); - lua_pushvalue(L, -2); - lua_rawset(L, -4); - } - lua_insert(L, -2); - lua_pop(L, 1); - return obj; -} - -// Most types are just 1 pointer and can use this helper. -static bool lupb_cache_getorcreate(lua_State *L, void *cobj, const char *type) { - return lupb_cache_getorcreate_size(L, cobj, type, sizeof(void*)) != NULL; -} - -static void lupb_cache_create(lua_State *L, void *cobj, const char *type) { - bool created = - lupb_cache_getorcreate_size(L, cobj, type, sizeof(void*)) != NULL; - (void)created; // For NDEBUG - assert(created); -} - - -/* lupb_def *******************************************************************/ - -// All the def types share the same C layout, even though they are different Lua -// types with different metatables. -typedef struct { - upb_def *def; -} lupb_def; - -static lupb_def *lupb_def_check(lua_State *L, int narg) { - void *ldef = luaL_checkudata(L, narg, "upb.msgdef"); - if (!ldef) ldef = luaL_checkudata(L, narg, "upb.enumdef"); - if (!ldef) luaL_typerror(L, narg, "upb def"); - return ldef; -} - -static void lupb_def_getorcreate(lua_State *L, upb_def *def, int owned) { - bool created = false; - switch(def->type) { - case UPB_DEF_MSG: - created = lupb_cache_getorcreate(L, def, "upb.msgdef"); - break; - case UPB_DEF_ENUM: - created = lupb_cache_getorcreate(L, def, "upb.enumdef"); - break; - default: - luaL_error(L, "unknown deftype %d", def->type); - } - if (!owned && created) { - upb_def_ref(def); - } else if (owned && !created) { - upb_def_unref(def); - } -} - - -/* lupb_fielddef **************************************************************/ - -typedef struct { - upb_fielddef *field; -} lupb_fielddef; - -static lupb_fielddef *lupb_fielddef_check(lua_State *L, int narg) { - lupb_fielddef *f = luaL_checkudata(L, narg, "upb.fielddef"); - if (!f) luaL_typerror(L, narg, "upb fielddef"); - return f; -} - -static int lupb_fielddef_index(lua_State *L) { - lupb_fielddef *f = lupb_fielddef_check(L, 1); - const char *str = luaL_checkstring(L, 2); - if (streql(str, "name")) { - lua_pushstring(L, upb_fielddef_name(f->field)); - } else if (streql(str, "number")) { - lua_pushinteger(L, upb_fielddef_number(f->field)); - } else if (streql(str, "type")) { - lua_pushinteger(L, upb_fielddef_type(f->field)); - } else if (streql(str, "label")) { - lua_pushinteger(L, upb_fielddef_label(f->field)); - } else if (streql(str, "subdef")) { - lupb_def_getorcreate(L, upb_fielddef_subdef(f->field), false); - } else if (streql(str, "msgdef")) { - lupb_def_getorcreate(L, UPB_UPCAST(upb_fielddef_msgdef(f->field)), false); - } else { - luaL_error(L, "Invalid fielddef member '%s'", str); - } - return 1; -} - -static void lupb_fielddef_set(lua_State *L, upb_fielddef *f, - const char *field, int narg) { - if (!upb_fielddef_ismutable(f)) luaL_error(L, "fielddef is not mutable."); - if (streql(field, "name")) { - const char *name = lua_tostring(L, narg); - if (!name || !upb_fielddef_setname(f, name)) - luaL_error(L, "Invalid name"); - } else if (streql(field, "number")) { - if (!upb_fielddef_setnumber(f, lupb_touint32(L, narg, "number"))) - luaL_error(L, "Invalid number"); - } else if (streql(field, "type")) { - if (!upb_fielddef_settype(f, lupb_touint8(L, narg, "type"))) - luaL_error(L, "Invalid type"); - } else if (streql(field, "label")) { - if (!upb_fielddef_setlabel(f, lupb_touint8(L, narg, "label"))) - luaL_error(L, "Invalid label"); - } else if (streql(field, "type_name")) { - const char *name = lua_tostring(L, narg); - if (!name || !upb_fielddef_settypename(f, name)) - luaL_error(L, "Invalid type_name"); - } else if (streql(field, "default_value")) { - if (!upb_fielddef_type(f)) - luaL_error(L, "Must set type before setting default_value"); - upb_strref ref; - upb_fielddef_setdefault(f, lupb_getvalue(L, narg, f, &ref)); - } else { - luaL_error(L, "Cannot set fielddef member '%s'", field); - } -} - -static int lupb_fielddef_new(lua_State *L) { - upb_fielddef *f = upb_fielddef_new(); - lupb_cache_create(L, f, "upb.fielddef"); - - if (lua_gettop(L) == 0) return 1; - - // User can specify initialization values like so: - // upb.FieldDef{label=upb.LABEL_REQUIRED, name="my_field", number=5, - // type=upb.TYPE_INT32, default_value=12, type_name="Foo"} - luaL_checktype(L, 1, LUA_TTABLE); - // Iterate over table. - lua_pushnil(L); // first key - while (lua_next(L, 1)) { - luaL_checktype(L, -2, LUA_TSTRING); - const char *key = lua_tostring(L, -2); - lupb_fielddef_set(L, f, key, -1); - lua_pop(L, 1); - } - return 1; -} - -static void lupb_fielddef_getorcreate(lua_State *L, upb_fielddef *f) { - bool created = lupb_cache_getorcreate(L, f, "upb.fielddef"); - if (created) upb_fielddef_ref(f); -} - -static int lupb_fielddef_newindex(lua_State *L) { - lupb_fielddef *f = lupb_fielddef_check(L, 1); - lupb_fielddef_set(L, f->field, luaL_checkstring(L, 2), 3); - return 0; -} - -static int lupb_fielddef_gc(lua_State *L) { - lupb_fielddef *lfielddef = lupb_fielddef_check(L, 1); - upb_fielddef_unref(lfielddef->field); - return 0; -} - -static const struct luaL_Reg lupb_fielddef_mm[] = { - {"__gc", lupb_fielddef_gc}, - {"__index", lupb_fielddef_index}, - {"__newindex", lupb_fielddef_newindex}, - {NULL, NULL} -}; - - -/* lupb_msgdef ****************************************************************/ - -static upb_msgdef *lupb_msgdef_check(lua_State *L, int narg) { - lupb_def *ldef = luaL_checkudata(L, narg, "upb.msgdef"); - luaL_argcheck(L, ldef != NULL, narg, "upb msgdef expected"); - return upb_downcast_msgdef(ldef->def); -} - -static int lupb_msgdef_gc(lua_State *L) { - lupb_def *ldef = luaL_checkudata(L, 1, "upb.msgdef"); - upb_def_unref(ldef->def); - return 0; -} - -static int lupb_msgdef_call(lua_State *L) { - upb_msgdef *md = lupb_msgdef_check(L, 1); - lupb_msg_pushnew(L, md); - return 1; -} - -static int lupb_msgdef_new(lua_State *L) { - upb_msgdef *md = upb_msgdef_new(); - lupb_cache_create(L, md, "upb.msgdef"); - - if (lua_gettop(L) == 0) return 1; - - // User can specify initialization values like so: - // upb.MessageDef{fqname="MyMessage", extstart=8000, fields={...}} - luaL_checktype(L, 1, LUA_TTABLE); - // Iterate over table. - lua_pushnil(L); // first key - while (lua_next(L, 1)) { - luaL_checktype(L, -2, LUA_TSTRING); - const char *key = lua_tostring(L, -2); - - if (streql(key, "fqname")) { // fqname="MyMessage" - const char *fqname = lua_tostring(L, -1); - if (!fqname || !upb_def_setfqname(UPB_UPCAST(md), fqname)) - luaL_error(L, "Invalid fqname"); - } else if (streql(key, "fields")) { // fields={...} - // Iterate over the list of fields. - lua_pushnil(L); - luaL_checktype(L, -2, LUA_TTABLE); - while (lua_next(L, -2)) { - lupb_fielddef *f = lupb_fielddef_check(L, -1); - if (!upb_msgdef_addfield(md, f->field)) { - // TODO: more specific error. - luaL_error(L, "Could not add field."); - } - lua_pop(L, 1); - } - } else { - // TODO: extrange= - luaL_error(L, "Unknown initializer key '%s'", key); - } - lua_pop(L, 1); - } - return 1; -} - -static int lupb_msgdef_fqname(lua_State *L) { - upb_msgdef *m = lupb_msgdef_check(L, 1); - lua_pushstring(L, m->base.fqname); - return 1; -} - -static int lupb_msgdef_fieldbyname(lua_State *L) { - upb_msgdef *m = lupb_msgdef_check(L, 1); - upb_fielddef *f = upb_msgdef_ntof(m, luaL_checkstring(L, 2)); - if (f) { - lupb_fielddef_getorcreate(L, f); - } else { - lua_pushnil(L); - } - return 1; -} - -static int lupb_msgdef_fieldbynum(lua_State *L) { - upb_msgdef *m = lupb_msgdef_check(L, 1); - int num = luaL_checkint(L, 2); - upb_fielddef *f = upb_msgdef_itof(m, num); - if (f) { - lupb_fielddef_getorcreate(L, f); - } else { - lua_pushnil(L); - } - return 1; -} - -static const struct luaL_Reg lupb_msgdef_mm[] = { - {"__call", lupb_msgdef_call}, - {"__gc", lupb_msgdef_gc}, - {NULL, NULL} -}; - -static const struct luaL_Reg lupb_msgdef_m[] = { - {"fieldbyname", lupb_msgdef_fieldbyname}, - {"fieldbynum", lupb_msgdef_fieldbynum}, - {"fqname", lupb_msgdef_fqname}, - {NULL, NULL} -}; - - -/* lupb_enumdef ***************************************************************/ - -static upb_enumdef *lupb_enumdef_check(lua_State *L, int narg) { - lupb_def *ldef = luaL_checkudata(L, narg, "upb.enumdef"); - return upb_downcast_enumdef(ldef->def); -} - -static int lupb_enumdef_gc(lua_State *L) { - upb_enumdef *e = lupb_enumdef_check(L, 1); - upb_def_unref(UPB_UPCAST(e)); - return 0; -} - -static int lupb_enumdef_name(lua_State *L) { - upb_enumdef *e = lupb_enumdef_check(L, 1); - lua_pushstring(L, e->base.fqname); - return 1; -} - -static const struct luaL_Reg lupb_enumdef_mm[] = { - {"__gc", lupb_enumdef_gc}, - {NULL, NULL} -}; - -static const struct luaL_Reg lupb_enumdef_m[] = { - {"name", lupb_enumdef_name}, - {NULL, NULL} -}; - - -/* lupb_symtab ****************************************************************/ - -typedef struct { - upb_symtab *symtab; -} lupb_symtab; - -static upb_accessor_vtbl *lupb_accessor(upb_fielddef *f); - -// Inherits a ref on the symtab. -// Checks that narg is a proper lupb_symtab object. If it is, leaves its -// metatable on the stack for cache lookups/updates. -lupb_symtab *lupb_symtab_check(lua_State *L, int narg) { - return luaL_checkudata(L, narg, "upb.symtab"); -} - -// narg is a lua table containing a list of defs to add. -void lupb_symtab_doadd(lua_State *L, upb_symtab *s, int narg) { - luaL_checktype(L, narg, LUA_TTABLE); - // Iterate over table twice. First iteration to count entries and - // check constraints. - int n = 0; - lua_pushnil(L); // first key - while (lua_next(L, narg)) { - lupb_def_check(L, -1); - ++n; - lua_pop(L, 1); - } - - // Second iteration to build deflist and layout. - upb_def **defs = malloc(n * sizeof(*defs)); - n = 0; - lua_pushnil(L); // first key - while (lua_next(L, 1)) { - upb_def *def = lupb_def_check(L, -1)->def; - defs[n++] = def; - upb_msgdef *md = upb_dyncast_msgdef(def); - if (md) { - upb_msg_iter i; - for(i = upb_msg_begin(md); !upb_msg_done(i); i = upb_msg_next(md, i)) { - upb_fielddef *f = upb_msg_iter_field(i); - upb_fielddef_setaccessor(f, lupb_accessor(f)); - } - upb_msgdef_layout(md); - } - lua_pop(L, 1); - } - - upb_status status = UPB_STATUS_INIT; - upb_symtab_add(s, defs, n, &status); - free(defs); - lupb_checkstatus(L, &status); -} - -static int lupb_symtab_new(lua_State *L) { - upb_symtab *s = upb_symtab_new(); - lupb_cache_create(L, s, "upb.symtab"); - if (lua_gettop(L) == 0) return 1; - lupb_symtab_doadd(L, s, 1); - return 1; -} - -static int lupb_symtab_add(lua_State *L) { - lupb_symtab *s = lupb_symtab_check(L, 1); - lupb_symtab_doadd(L, s->symtab, 2); - return 0; -} - -static int lupb_symtab_gc(lua_State *L) { - lupb_symtab *s = lupb_symtab_check(L, 1); - upb_symtab_unref(s->symtab); - return 0; -} - -static int lupb_symtab_lookup(lua_State *L) { - lupb_symtab *s = lupb_symtab_check(L, 1); - for (int i = 2; i <= lua_gettop(L); i++) { - upb_def *def = upb_symtab_lookup(s->symtab, luaL_checkstring(L, i)); - if (def) { - lupb_def_getorcreate(L, def, true); - } else { - lua_pushnil(L); - } - lua_replace(L, i); - } - return lua_gettop(L) - 1; -} - -static int lupb_symtab_getdefs(lua_State *L) { - lupb_symtab *s = lupb_symtab_check(L, 1); - upb_deftype_t type = luaL_checkint(L, 2); - int count; - upb_def **defs = upb_symtab_getdefs(s->symtab, &count, type); - - // Create the table in which we will return the defs. - lua_createtable(L, count, 0); - for (int i = 0; i < count; i++) { - upb_def *def = defs[i]; - lupb_def_getorcreate(L, def, true); - lua_rawseti(L, -2, i + 1); - } - free(defs); - return 1; -} - -static const struct luaL_Reg lupb_symtab_m[] = { - {"add", lupb_symtab_add}, - {"getdefs", lupb_symtab_getdefs}, - {"lookup", lupb_symtab_lookup}, - {NULL, NULL} -}; - -static const struct luaL_Reg lupb_symtab_mm[] = { - {"__gc", lupb_symtab_gc}, - {NULL, NULL} -}; - - -/* lupb_msg********************************************************************/ - -// Messages are userdata. Primitive values (numbers and bools, and their -// hasbits) are stored right in the userdata. Other values are stored using -// integer entries in the environment table and no hasbits are used (since -// "nil" in the environment table can indicate "not present"). -// -// The environment table looks like: -// {msgdef, } - -// Must pass a upb_fielddef as the pointer. -static void lupb_array_pushnew(lua_State *L, void *f); - -static void *lupb_msg_check(lua_State *L, int narg, upb_msgdef **md) { - void *msg = luaL_checkudata(L, narg, "upb.msg"); - luaL_argcheck(L, msg != NULL, narg, "msg expected"); - // If going all the way to the environment table for the msgdef is an - // efficiency issue, we could put the pointer right in the userdata. - lua_getfenv(L, narg); - lua_rawgeti(L, -1, 1); - // Shouldn't have to check msgdef userdata validity, environment table can't - // be accessed from Lua. - lupb_def *lmd = lua_touserdata(L, -1); - *md = upb_downcast_msgdef(lmd->def); - return msg; -} - -static void lupb_msg_pushnew(lua_State *L, void *md) { - void *msg = lua_newuserdata(L, upb_msgdef_size(md)); - luaL_getmetatable(L, "upb.msg"); - assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb. - lua_setmetatable(L, -2); - upb_msg_clear(msg, md); - lua_getfenv(L, -1); - lupb_cache_getorcreate(L, md, "upb.msgdef"); - lua_rawseti(L, -2, 1); - lua_pop(L, 1); // Pop the fenv. -} - -static int lupb_msg_new(lua_State *L) { - upb_msgdef *md = lupb_msgdef_check(L, 1); - lupb_msg_pushnew(L, md); - return 1; -} - -static int lupb_msg_index(lua_State *L) { - upb_msgdef *md; - void *m = lupb_msg_check(L, 1, &md); - upb_fielddef *f = upb_msgdef_ntof(md, luaL_checkstring(L, 2)); - if (!f) luaL_argerror(L, 2, "not a field name"); - if (upb_isprimitivetype(upb_fielddef_type(f))) { - upb_value v = upb_msg_has(m, f) ? upb_msg_get(m, f) : upb_fielddef_default(f); - lupb_pushvalue(L, v, f); - } else { - lua_getfenv(L, 1); - lua_rawgeti(L, -1, f->offset); - if (lua_isnil(L, -1)) { - // Need to lazily create array, string, or submessage. - if (upb_isseq(f)) { - lupb_array_pushnew(L, f); - } else if (upb_isstring(f)) { - // TODO: (need to figure out default string ownership). - } else if (upb_issubmsg(f)) { - lupb_msg_pushnew(L, upb_downcast_msgdef(upb_fielddef_subdef(f))); - } else { - luaL_error(L, "internal error"); - } - lua_rawseti(L, -2, f->offset); - } - } - return 1; -} - -static int lupb_msg_newindex(lua_State *L) { - upb_msgdef *md; - void *m = lupb_msg_check(L, 1, &md); - upb_fielddef *f = upb_msgdef_ntof(md, luaL_checkstring(L, 2)); - if (!f) luaL_error(L, "not a field name"); - if (upb_isprimitivetype(upb_fielddef_type(f))) { - if (lua_isnil(L, 3)) - upb_msg_clearbit(m, f); - else - upb_msg_set(m, f, lupb_getvalue(L, 3, f, NULL)); - } else { - if (!lua_isnil(L, 3)) lupb_typecheck(L, 3, f); - lua_getfenv(L, 1); - lua_pushvalue(L, 3); - lua_rawseti(L, -1, f->offset); - } - return 0; -} - -static const struct luaL_Reg lupb_msg_mm[] = { - {"__index", lupb_msg_index}, - {"__newindex", lupb_msg_newindex}, - {NULL, NULL} -}; - -// Functions that operate on msgdefs but do not live in the msgdef namespace. -static int lupb_clear(lua_State *L) { - upb_msgdef *md; - void *m = lupb_msg_check(L, 1, &md); - upb_msg_clear(m, md); - return 0; -} - -static int lupb_has(lua_State *L) { - upb_msgdef *md; - void *m = lupb_msg_check(L, 1, &md); - upb_fielddef *f = upb_msgdef_ntof(md, luaL_checkstring(L, 2)); - if (!f) luaL_argerror(L, 2, "not a field name"); - lua_pushboolean(L, upb_msg_has(m, f)); - return 1; -} - -static int lupb_msgdef(lua_State *L) { - upb_msgdef *md; - lupb_msg_check(L, 1, &md); - lupb_def_getorcreate(L, UPB_UPCAST(md), false); - return 1; -} - -// Accessors for arrays, strings, and submessages need access to the current -// userdata's environment table, which can only be stored in Lua space. -// Options for storing it are: -// -// - put the env tables for all messages and arrays in the registry, keyed by -// userdata pointer (light userdata), or by a reference using luaL_ref(). -// Then we can just let upb's parse stack track the stack of env tables. -// Easy but requires all messages and arrays to be in the registry, which -// seems too heavyweight. -// -// - store the stack of env tables in the Lua stack. Convenient, but requires -// special code to handle resumable decoders. -// -// There is also the question of how to obtain the lua_State* pointer. -// The main options for this are: -// -// - make our closure point to a struct: -// struct { void *msg; lua_State *L; } -// But then we can't use standard accessors, which expect the closure -// to point to the data itself. Using the standard accessors for -// primitive values is both a simplicity and a performance win. -// -// - store a lua_State* pointer inside each userdata. Convenient and -// efficient, but makes every message sizeof(void*) larger. -// Currently we take this route. -// -// - use thread-local storage. Convenient and efficient, but not portable. - -typedef void createfunc_t(lua_State *L, void *param); - -static upb_sflow_t lupb_msg_start(void *m, upb_fielddef *f, bool array, - createfunc_t *pushnew, void *param) { - lua_State *L = *(lua_State**)m; - int offset = array ? lua_rawlen(L, -1) : f->offset; - if (!lua_checkstack(L, 3)) luaL_error(L, "stack full"); - lua_rawgeti(L, -1, offset); - if (lua_isnil(L, -1)) { - lua_pop(L, 1); - pushnew(L, param); - lua_pushvalue(L, -1); - lua_rawseti(L, -3, offset); - } - void *subval = lua_touserdata(L, -1); - lua_getfenv(L, -1); - lua_replace(L, -2); // Replace subval userdata with fenv. - return UPB_CONTINUE_WITH(subval); -} - -static upb_flow_t lupb_msg_string(void *m, upb_value fval, upb_value val, - bool array) { - // Could add lazy materialization of strings here. - upb_fielddef *f = upb_value_getfielddef(fval); - lua_State *L = *(lua_State**)m; - int offset = array ? lua_rawlen(L, -1) : f->offset; - if (!lua_checkstack(L, 1)) luaL_error(L, "stack full"); - lupb_pushstring(L, upb_value_getstrref(val)); - lua_rawseti(L, -2, offset); - return UPB_CONTINUE; -} - -static upb_sflow_t lupb_msg_startseq(void *m, upb_value fval) { - upb_fielddef *f = upb_value_getfielddef(fval); - return lupb_msg_start(m, f, false, lupb_array_pushnew, f); -} - -static upb_sflow_t lupb_msg_startsubmsg(void *m, upb_value fval) { - upb_fielddef *f = upb_value_getfielddef(fval); - return lupb_msg_start(m, f, false, lupb_msg_pushnew, upb_fielddef_subdef(f)); -} - -static upb_sflow_t lupb_msg_startsubmsg_r(void *a, upb_value fval) { - upb_fielddef *f = upb_value_getfielddef(fval); - return lupb_msg_start(a, f, true, lupb_msg_pushnew, upb_fielddef_subdef(f)); -} - -static upb_flow_t lupb_msg_stringval(void *m, upb_value fval, upb_value val) { - return lupb_msg_string(m, fval, val, false); -} - -static upb_flow_t lupb_msg_stringval_r(void *a, upb_value fval, upb_value val) { - return lupb_msg_string(a, fval, val, true); -} - -#define STDMSG(type, size) static upb_accessor_vtbl vtbl = { \ - &lupb_msg_startsubmsg, \ - &upb_stdmsg_set ## type, \ - &lupb_msg_startseq, \ - &lupb_msg_startsubmsg_r, \ - &upb_stdmsg_set ## type ## _r, \ - &upb_stdmsg_has, \ - &upb_stdmsg_getptr, \ - &upb_stdmsg_get ## type, \ - &upb_stdmsg_seqbegin, \ - &upb_stdmsg_ ## size ## byte_seqnext, \ - &upb_stdmsg_seqget ## type}; - -#define RETURN_STDMSG(type, size) { STDMSG(type, size); return &vtbl; } - -static upb_accessor_vtbl *lupb_accessor(upb_fielddef *f) { - switch (f->type) { - case UPB_TYPE(DOUBLE): RETURN_STDMSG(double, 8) - case UPB_TYPE(FLOAT): RETURN_STDMSG(float, 4) - case UPB_TYPE(UINT64): - case UPB_TYPE(FIXED64): RETURN_STDMSG(uint64, 8) - case UPB_TYPE(INT64): - case UPB_TYPE(SFIXED64): - case UPB_TYPE(SINT64): RETURN_STDMSG(int64, 8) - case UPB_TYPE(INT32): - case UPB_TYPE(SINT32): - case UPB_TYPE(ENUM): - case UPB_TYPE(SFIXED32): RETURN_STDMSG(int32, 4) - case UPB_TYPE(UINT32): - case UPB_TYPE(FIXED32): RETURN_STDMSG(uint32, 4) - case UPB_TYPE(BOOL): { STDMSG(bool, 1); return &vtbl; } - case UPB_TYPE(GROUP): - case UPB_TYPE(MESSAGE): RETURN_STDMSG(ptr, 8) // TODO: 32-bit - case UPB_TYPE(STRING): - case UPB_TYPE(BYTES): { - STDMSG(ptr, 8); - vtbl.set = &lupb_msg_stringval; - vtbl.append = &lupb_msg_stringval_r; - return &vtbl; - } - } - return NULL; -} - - -/* lupb_array ****************************************************************/ - -// Array: we store all elements in the environment table. Could optimize by -// storing primitive arrays in our own memory; this would be significantly more -// space efficient. Lua array elements are 16 bytes each; our own array would -// be 1/4 the space for 32-bit integers, or 1/16 the space for booleans. -// -// The first element of the environment table stores our type (which will be -// either an integer from upb.TYPE_* or a upb.msgdef), the remaining elements -// store the elements. We always keep all elements contiguous so we can use -// lua_objlen()/lua_rawlen() (for Lua 5.1/5.2 respectively) to report its len). - -// narg is offset of environment table. -static size_t lupb_array_getlen(lua_State *L, int narg) { - return lua_rawlen(L, narg) - 1; -} - -static void lupb_array_check(lua_State *L, int narg) { - if (!luaL_checkudata(L, narg, "upb.array")) - luaL_typerror(L, narg, "upb array"); -} - -static void lupb_array_pushnew(lua_State *L, void *f) { - (void)L; - (void)f; -} - -static int lupb_array_new(lua_State *L) { - (void)L; - return 0; -} - -static int lupb_array_len(lua_State *L) { - lupb_array_check(L, 1); - lua_getfenv(L, 1); - lua_pushnumber(L, lupb_array_getlen(L, -1)); - return 1; -} - -static int lupb_array_index(lua_State *L) { - assert(lua_gettop(L) == 2); // __index should always be called with 2 args. - lupb_array_check(L, 1); - lua_Number num = luaL_checknumber(L, 2); - if (!lupb_isint(num)) luaL_typerror(L, 2, "integer"); - - lua_getfenv(L, 1); - size_t len = lupb_array_getlen(L, -1); - if (num < 1 || num > len) luaL_error(L, "array bounds check failed"); - lua_rawgeti(L, -1, num + 1); - return 1; -} - -static int lupb_array_newindex(lua_State *L) { - assert(lua_gettop(L) == 3); // __newindex should always be called with 3 args. - lupb_array_check(L, 1); - lua_Number num = luaL_checknumber(L, 2); - if (rint(num) != num) luaL_typerror(L, 2, "integer"); - - lua_getfenv(L, 1); - size_t len = lupb_array_getlen(L, -1); - // We only allow extending the index one beyond the end. - if (num < 1 || num > len + 1) luaL_error(L, "array bounds check failed"); - lua_pushvalue(L, 3); - lua_rawseti(L, -2, num); - return 0; -} - -static const struct luaL_Reg lupb_array_mm[] = { - {"__len", lupb_array_len}, - {"__index", lupb_array_index}, - {"__newindex", lupb_array_newindex}, - {NULL, NULL} -}; - -/* lupb toplevel **************************************************************/ - -static const struct luaL_Reg lupb_toplevel_m[] = { - {"SymbolTable", lupb_symtab_new}, - {"MessageDef", lupb_msgdef_new}, - {"FieldDef", lupb_fielddef_new}, - - {"Message", lupb_msg_new}, - {"Array", lupb_array_new}, - - {"clear", lupb_clear}, - {"msgdef", lupb_msgdef}, - {"has", lupb_has}, - - {NULL, NULL} -}; - -// Register the given type with the given methods and metamethods. -static void lupb_register_type(lua_State *L, const char *name, - const luaL_Reg *m, const luaL_Reg *mm) { - luaL_newmetatable(L, name); - luaL_register(L, NULL, mm); // Register all mm in the metatable. - lua_createtable(L, 0, 0); - if (m) { - // Methods go in the mt's __index method. This implies that you can't - // implement __index and also set methods yourself. - luaL_register(L, NULL, m); - lua_setfield(L, -2, "__index"); - } - lua_pop(L, 1); // The mt. -} - -static void lupb_setfieldi(lua_State *L, const char *field, int i) { - lua_pushnumber(L, i); - lua_setfield(L, -2, field); -} - -int luaopen_upb(lua_State *L) { - lupb_register_type(L, "upb.msgdef", lupb_msgdef_m, lupb_msgdef_mm); - lupb_register_type(L, "upb.enumdef", lupb_enumdef_m, lupb_enumdef_mm); - lupb_register_type(L, "upb.fielddef", NULL, lupb_fielddef_mm); - lupb_register_type(L, "upb.symtab", lupb_symtab_m, lupb_symtab_mm); - - lupb_register_type(L, "upb.msg", NULL, lupb_msg_mm); - lupb_register_type(L, "upb.array", NULL, lupb_msg_mm); - - // Create our object cache. - lua_createtable(L, 0, 0); - lua_createtable(L, 0, 1); // Cache metatable. - lua_pushstring(L, "v"); // Values are weak. - lua_setfield(L, -2, "__mode"); - lua_setfield(L, LUA_REGISTRYINDEX, "upb.objcache"); - - luaL_register(L, "upb", lupb_toplevel_m); - - // Register constants. - lupb_setfieldi(L, "LABEL_OPTIONAL", UPB_LABEL(OPTIONAL)); - lupb_setfieldi(L, "LABEL_REQUIRED", UPB_LABEL(REQUIRED)); - lupb_setfieldi(L, "LABEL_REPEATED", UPB_LABEL(REPEATED)); - - lupb_setfieldi(L, "TYPE_DOUBLE", UPB_TYPE(DOUBLE)); - lupb_setfieldi(L, "TYPE_FLOAT", UPB_TYPE(FLOAT)); - lupb_setfieldi(L, "TYPE_INT64", UPB_TYPE(INT64)); - lupb_setfieldi(L, "TYPE_UINT64", UPB_TYPE(UINT64)); - lupb_setfieldi(L, "TYPE_INT32", UPB_TYPE(INT32)); - lupb_setfieldi(L, "TYPE_FIXED64", UPB_TYPE(FIXED64)); - lupb_setfieldi(L, "TYPE_FIXED32", UPB_TYPE(FIXED32)); - lupb_setfieldi(L, "TYPE_BOOL", UPB_TYPE(BOOL)); - lupb_setfieldi(L, "TYPE_STRING", UPB_TYPE(STRING)); - lupb_setfieldi(L, "TYPE_GROUP", UPB_TYPE(GROUP)); - lupb_setfieldi(L, "TYPE_MESSAGE", UPB_TYPE(MESSAGE)); - lupb_setfieldi(L, "TYPE_BYTES", UPB_TYPE(BYTES)); - lupb_setfieldi(L, "TYPE_UINT32", UPB_TYPE(UINT32)); - lupb_setfieldi(L, "TYPE_ENUM", UPB_TYPE(ENUM)); - lupb_setfieldi(L, "TYPE_SFIXED32", UPB_TYPE(SFIXED32)); - lupb_setfieldi(L, "TYPE_SFIXED64", UPB_TYPE(SFIXED64)); - lupb_setfieldi(L, "TYPE_SINT32", UPB_TYPE(SINT32)); - lupb_setfieldi(L, "TYPE_SINT64", UPB_TYPE(SINT64)); - - return 1; // Return package table. -} diff --git a/lang_ext/python/setup.py b/lang_ext/python/setup.py deleted file mode 100644 index 8abaff8..0000000 --- a/lang_ext/python/setup.py +++ /dev/null @@ -1,14 +0,0 @@ -from distutils.core import setup, Extension - -setup(name='upb', - version='0.1', - ext_modules=[ - Extension('upb.__init__', ['upb.c'], - include_dirs=['../../'], - define_macros=[("UPB_UNALIGNED_READS_OK", 1)], - library_dirs=['../../upb'], - libraries=['upb_pic'], - ), - ], - packages=['upb'] - ) diff --git a/lang_ext/python/test.py b/lang_ext/python/test.py deleted file mode 100644 index 29a6c45..0000000 --- a/lang_ext/python/test.py +++ /dev/null @@ -1,72 +0,0 @@ - -import upb -import unittest - -class TestFieldDef(unittest.TestCase): - def test_construction(self): - fielddef1 = upb.FieldDef() - self.assertTrue(fielddef1.number is None) - self.assertTrue(fielddef1.name is None) - self.assertTrue(fielddef1.type is None) - self.assertEqual(fielddef1.label, upb.LABEL_OPTIONAL) - - fielddef2 = upb.FieldDef(number=5, name="field2", - label=upb.LABEL_REQUIRED, type=upb.TYPE_INT32, - type_name="MyType") - - self.assertTrue(id(fielddef1) != id(fielddef2)) - self.assertEqual(fielddef2.number, 5) - self.assertEqual(fielddef2.name, "field2") - self.assertEqual(fielddef2.label, upb.LABEL_REQUIRED) - self.assertEqual(fielddef2.type, upb.TYPE_INT32) - self.assertEqual(fielddef2.type_name, "MyType") - - fielddef2.number = 8 - self.assertEqual(fielddef2.number, 8) - - fielddef2.name = "xxx" - self.assertEqual(fielddef2.name, "xxx") - - fielddef2.label = upb.LABEL_REPEATED - self.assertEqual(fielddef2.label, upb.LABEL_REPEATED) - - fielddef2.type = upb.TYPE_FLOAT - self.assertEqual(fielddef2.type, upb.TYPE_FLOAT) - - def test_nosubclasses(self): - def create_subclass(): - class MyClass(upb.FieldDef): - pass - - self.assertRaises(TypeError, create_subclass) - - # TODO: test that assigning invalid values is properly prevented. - -class TestMessageDef(unittest.TestCase): - def test_construction(self): - msgdef1 = upb.MessageDef() - self.assertTrue(msgdef1.fqname is None) - self.assertEqual(msgdef1.fields(), []) - - fields = [upb.FieldDef(number=1, name="field1", type=upb.TYPE_INT32)] - msgdef2 = upb.MessageDef(fqname="Message2", fields=fields) - - self.assertEqual(set(msgdef2.fields()), set(fields)) - - f2 = upb.FieldDef(number=2, name="field2", type=upb.TYPE_INT64) - msgdef2.add_field(f2) - - fields.append(f2) - self.assertEqual(set(msgdef2.fields()), set(fields)) - -class TestSymbolTable(unittest.TestCase): - def test_construction(self): - s = upb.SymbolTable() - self.assertEqual(s.defs(), []); - - s.add_def(upb.MessageDef(fqname="A")) - self.assertTrue(s.lookup("A") is not None) - self.assertTrue(s.lookup("A") is s.lookup("A")) - -if __name__ == '__main__': - unittest.main() diff --git a/lang_ext/python/upb.c b/lang_ext/python/upb.c deleted file mode 100644 index ffb3d52..0000000 --- a/lang_ext/python/upb.c +++ /dev/null @@ -1,724 +0,0 @@ -/* - * upb - a minimalist implementation of protocol buffers. - * - * Copyright (c) 2009 Google Inc. See LICENSE for details. - * Author: Josh Haberman - * - * Python extension exposing the core of upb: definitions, handlers, - * and a message type. - */ - -#include -#include -#include "upb/def.h" -#include "upb/msg.h" - -static bool streql(const char *a, const char *b) { return strcmp(a, b) == 0; } - -PyObject *PyUpb_Error(const char *str) { - PyErr_SetString(PyExc_TypeError, str); - return NULL; -} - -int PyUpb_ErrorInt(const char *str) { - PyErr_SetString(PyExc_TypeError, str); - return -1; -} - -#define PyUpb_CheckStatus(status) \ - if (!upb_ok(status)) return PyUpb_Error((status)->str); - -static upb_accessor_vtbl *PyUpb_AccessorForField(upb_fielddef *f); - - -/* Object cache ***************************************************************/ - -// For objects that are just wrappers around a C object pointer, we keep a -// cache mapping C pointer -> wrapper object. This allows us to consistently -// vend the same Python object given the same C object. This prevents us from -// creating too many Python objects unnecessarily. More importantly, it provides -// the expected semantics: -// -// if field.subdef is field.subdef: -// print "Sanity prevails." -// -// If we conjured up a new wrapper object every time, the above would not be -// true. -// -// The cost is having to put all such objects in a table, but since this only -// applies to schema-level objects (defs, handlers, etc) this seems acceptable. -// We do *not* have to put all message objects in this table. -// -// We use weak refs so that the cache does not prevent the wrapper objects from -// being collected. The table is stored as a static variable; to use -// sub-interpreters this would need to change, but I believe that using -// sub-interpreters is exceedingly rare in practice. - -typedef struct { - PyObject_HEAD; - void *obj; - PyObject *weakreflist; -} PyUpb_ObjWrapper; - -static PyObject *obj_cache = NULL; -static PyObject *reverse_cache = NULL; -static PyObject *weakref_callback = NULL; - -// Utility functions for manipulating Python dictionaries keyed by pointer. - -static PyObject *PyUpb_StringForPointer(void *ptr) { - PyObject *o = PyString_FromStringAndSize((const char *)&ptr, sizeof(void*)); - assert(o); - return o; -} - -static PyObject *PyUpb_ObjCacheDeleteCallback(PyObject *self, PyObject *ref) { - // Python very unfortunately clears the weakref before running our callback. - // This prevents us from using the weakref to find the C pointer we need to - // remove from the cache. As a result we are forced to keep a second map - // mapping weakref->C pointer. - PyObject *ptr_str = PyDict_GetItem(reverse_cache, ref); - assert(ptr_str); - int err = PyDict_DelItem(obj_cache, ptr_str); - assert(!err); - err = PyDict_DelItem(reverse_cache, ref); - assert(!err); - return Py_None; -} - -static PyObject *PyUpb_ObjCacheGet(void *obj, PyTypeObject *type) { - PyObject *kv = PyUpb_StringForPointer(obj); - PyObject *ref = PyDict_GetItem(obj_cache, kv); - PyObject *ret; - if (ref) { - ret = PyWeakref_GetObject(ref); - assert(ret != Py_None); - Py_INCREF(ret); - } else { - PyUpb_ObjWrapper *wrapper = (PyUpb_ObjWrapper*)type->tp_alloc(type, 0); - wrapper->obj = obj; - wrapper->weakreflist = NULL; - ret = (PyObject*)wrapper; - ref = PyWeakref_NewRef(ret, weakref_callback); - assert(PyWeakref_GetObject(ref) == ret); - assert(ref); - PyDict_SetItem(obj_cache, kv, ref); - PyDict_SetItem(reverse_cache, ref, kv); - } - assert(ret); - Py_DECREF(kv); - return ret; -} - - -/* PyUpb_Def ******************************************************************/ - -static PyTypeObject *PyUpb_TypeForDef(upb_def *def); - -static void PyUpb_Def_dealloc(PyObject *obj) { - PyUpb_ObjWrapper *wrapper = (void*)obj; - upb_def_unref((upb_def*)wrapper->obj); - obj->ob_type->tp_free(obj); -} - -PyObject *PyUpb_Def_GetOrCreate(upb_def *def) { - return def ? PyUpb_ObjCacheGet(def, PyUpb_TypeForDef(def)) : Py_None; -} - -// Will need to expand once other kinds of defs are supported. -#define Check_Def(o, badret) Check_MessageDef(o, badret) - - -/* PyUpb_FieldDef *************************************************************/ - -static PyTypeObject PyUpb_FieldDefType; -static int PyUpb_FieldDef_setattro(PyObject *o, PyObject *key, PyObject *val); - -#define Check_FieldDef(o, badret) \ - (void*)(((PyUpb_ObjWrapper*)o)->obj); do { \ - if(!PyObject_TypeCheck(o, &PyUpb_FieldDefType)) { \ - PyErr_SetString(PyExc_TypeError, "must be a upb.FieldDef"); \ - return badret; \ - } \ - } while(0) - -static PyObject *PyUpb_FieldDef_GetOrCreate(upb_fielddef *f) { - return PyUpb_ObjCacheGet(f, &PyUpb_FieldDefType); -} - -static PyObject *PyUpb_FieldDef_new(PyTypeObject *subtype, - PyObject *args, PyObject *kwds) { - return PyUpb_ObjCacheGet(upb_fielddef_new(), subtype); -} - -static int PyUpb_FieldDef_init(PyObject *self, PyObject *args, PyObject *kwds) { - if (!kwds) return 0; - PyObject *key, *value; - Py_ssize_t pos = 0; - while (PyDict_Next(kwds, &pos, &key, &value)) - PyUpb_FieldDef_setattro(self, key, value); - return 0; -} - -static void PyUpb_FieldDef_dealloc(PyObject *obj) { - PyUpb_ObjWrapper *wrapper = (void*)obj; - if (wrapper->weakreflist) PyObject_ClearWeakRefs(obj); - upb_fielddef_unref((upb_fielddef*)wrapper->obj); - obj->ob_type->tp_free(obj); -} - -static PyObject *PyUpb_FieldDef_getattro(PyObject *obj, PyObject *attr_name) { - upb_fielddef *f = Check_FieldDef(obj, NULL); - if (!upb_fielddef_ismutable(f)) { - PyErr_SetString(PyExc_TypeError, "fielddef is not mutable."); - return NULL; - } - const char *name = PyString_AsString(attr_name); - if (streql(name, "name")) { - const char *name = upb_fielddef_name(f); - return name == NULL ? Py_None : PyString_FromString(name); - } else if (streql(name, "number")) { - uint32_t num = upb_fielddef_number(f); - return num == 0 ? Py_None : PyInt_FromLong(num); - } else if (streql(name, "type")) { - uint8_t type = upb_fielddef_type(f); - return type == 0 ? Py_None : PyInt_FromLong(type); - } else if (streql(name, "label")) { - return PyInt_FromLong(upb_fielddef_label(f)); - } else if (streql(name, "type_name")) { - const char *name = upb_fielddef_typename(f); - return name == NULL ? Py_None : PyString_FromString(name); - } else if (streql(name, "subdef")) { - // NYI; - return NULL; - } else if (streql(name, "msgdef")) { - // NYI; - return NULL; - } else { - return PyUpb_Error("Invalid fielddef member."); - } -} - -static int PyUpb_FieldDef_setattro(PyObject *o, PyObject *key, PyObject *val) { - upb_fielddef *f = Check_FieldDef(o, -1); - const char *field = PyString_AsString(key); - if (!upb_fielddef_ismutable(f)) - return PyUpb_ErrorInt("fielddef is not mutable."); - if (streql(field, "name")) { - const char *name = PyString_AsString(val); - if (!name || !upb_fielddef_setname(f, name)) - return PyUpb_ErrorInt("Invalid name"); - } else if (streql(field, "number")) { - // TODO: should check truncation. Non-security issue. - // Non-int will return -1, which is already invalid as a field number. - if (!upb_fielddef_setnumber(f, PyInt_AsLong(val))) - return PyUpb_ErrorInt("Invalid number"); - } else if (streql(field, "type")) { - // TODO: should check truncation. Non-security issue. - if (!upb_fielddef_settype(f, PyInt_AsLong(val))) - return PyUpb_ErrorInt("Invalid type"); - } else if (streql(field, "label")) { - // TODO: should check truncation. Non-security issue. - if (!upb_fielddef_setlabel(f, PyInt_AsLong(val))) - return PyUpb_ErrorInt("Invalid label"); - } else if (streql(field, "type_name")) { - const char *name = PyString_AsString(val); - if (!name || !upb_fielddef_settypename(f, name)) - return PyUpb_ErrorInt("Invalid type_name"); - } else if (streql(field, "default_value")) { - // NYI - return -1; - } else { - return PyUpb_ErrorInt("Invalid fielddef member."); - } - return 0; -} - -static PyTypeObject PyUpb_FieldDefType = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - "upb.FieldDef", /* tp_name */ - sizeof(PyUpb_ObjWrapper), /* tp_basicsize */ - 0, /* tp_itemsize */ - &PyUpb_FieldDef_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* TODO */ /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - &PyUpb_FieldDef_getattro, /* tp_getattro */ - &PyUpb_FieldDef_setattro, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(PyUpb_ObjWrapper, weakreflist),/* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - 0, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - &PyUpb_FieldDef_init, /* tp_init */ - 0, /* tp_alloc */ - &PyUpb_FieldDef_new, /* tp_new */ - 0, /* tp_free */ -}; - - -/* PyUpb_MessageDef ***********************************************************/ - -static PyTypeObject PyUpb_MessageDefType; -static int PyUpb_MessageDef_setattro(PyObject *o, PyObject *key, PyObject *val); - -#define Check_MessageDef(o, badret) \ - (void*)(((PyUpb_ObjWrapper*)o)->obj); do { \ - if(!PyObject_TypeCheck(o, &PyUpb_MessageDefType)) { \ - PyErr_SetString(PyExc_TypeError, "must be a upb.MessageDef"); \ - return badret; \ - } \ - } while(0) - -static PyObject *PyUpb_MessageDef_new(PyTypeObject *subtype, - PyObject *args, PyObject *kwds) { - return PyUpb_ObjCacheGet(upb_msgdef_new(), subtype); -} - -static PyObject *PyUpb_MessageDef_add_fields(PyObject *o, PyObject *args); - -static int PyUpb_MessageDef_init(PyObject *self, PyObject *args, PyObject *kwds) { - if (!kwds) return 0; - PyObject *key, *value; - Py_ssize_t pos = 0; - while (PyDict_Next(kwds, &pos, &key, &value)) { - const char *field = PyString_AsString(key); - if (streql(field, "fields")) { - PyUpb_MessageDef_add_fields(self, value); - } else { - PyUpb_MessageDef_setattro(self, key, value); - } - } - return 0; -} - -static PyObject *PyUpb_MessageDef_getattro(PyObject *obj, PyObject *attr_name) { - upb_msgdef *m = Check_MessageDef(obj, NULL); - const char *name = PyString_AsString(attr_name); - if (streql(name, "fqname")) { - const char *fqname = upb_def_fqname(UPB_UPCAST(m)); - return fqname == NULL ? Py_None : PyString_FromString(fqname); - } - return PyObject_GenericGetAttr(obj, attr_name); -} - -static int PyUpb_MessageDef_setattro(PyObject *o, PyObject *key, PyObject *val) { - upb_msgdef *m = Check_MessageDef(o, -1); - if (!upb_def_ismutable(UPB_UPCAST(m))) { - PyErr_SetString(PyExc_TypeError, "MessageDef is not mutable."); - return -1; - } - const char *name = PyString_AsString(key); - if (streql(name, "fqname")) { - const char *fqname = PyString_AsString(val); - if (!fqname || !upb_def_setfqname(UPB_UPCAST(m), fqname)) - return PyUpb_ErrorInt("Invalid fqname"); - } else { - return PyUpb_ErrorInt("Invalid MessageDef member."); - } - return 0; -} - -static PyObject *PyUpb_MessageDef_fields(PyObject *obj, PyObject *args) { - upb_msgdef *m = Check_MessageDef(obj, NULL); - PyObject *ret = PyList_New(0); - upb_msg_iter i; - for(i = upb_msg_begin(m); !upb_msg_done(i); i = upb_msg_next(m, i)) { - upb_fielddef *f = upb_msg_iter_field(i); - PyList_Append(ret, PyUpb_FieldDef_GetOrCreate(f)); - } - return ret; -} - -static PyObject *PyUpb_MessageDef_add_fields(PyObject *o, PyObject *fields) { - upb_msgdef *m = Check_MessageDef(o, NULL); - if (!PySequence_Check(fields)) return PyUpb_Error("Must be a sequence"); - Py_ssize_t len = PySequence_Length(fields); - if (len > UPB_MAX_FIELDS) return PyUpb_Error("Too many fields."); - upb_fielddef *f[len]; - int i; - for (i = 0; i < len; i++) { - PyObject *field = PySequence_GetItem(fields, i); - f[i] = Check_FieldDef(field, NULL); - } - upb_msgdef_addfields(m, f, len); - return Py_None; -} - -static PyObject *PyUpb_MessageDef_add_field(PyObject *o, PyObject *field) { - upb_msgdef *m = Check_MessageDef(o, NULL); - upb_fielddef *f = Check_FieldDef(field, NULL); - upb_msgdef_addfield(m, f); - return Py_None; -} - -static PyMethodDef PyUpb_MessageDef_methods[] = { - {"add_field", &PyUpb_MessageDef_add_field, METH_O, "Adds a list of fields."}, - {"add_fields", &PyUpb_MessageDef_add_fields, METH_O, "Adds a list of fields."}, - {"fields", &PyUpb_MessageDef_fields, METH_NOARGS, "Returns list of fields."}, - {NULL, NULL} -}; - -static PyTypeObject PyUpb_MessageDefType = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - "upb.MessageDef", /* tp_name */ - sizeof(PyUpb_ObjWrapper), /* tp_basicsize */ - 0, /* tp_itemsize */ - &PyUpb_Def_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* TODO */ /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - &PyUpb_MessageDef_getattro, /* tp_getattro */ - &PyUpb_MessageDef_setattro, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(PyUpb_ObjWrapper, weakreflist),/* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - PyUpb_MessageDef_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - &PyUpb_MessageDef_init, /* tp_init */ - 0, /* tp_alloc */ - &PyUpb_MessageDef_new, /* tp_new */ - 0, /* tp_free */ -}; - - -static PyTypeObject *PyUpb_TypeForDef(upb_def *def) { - switch(def->type) { - case UPB_DEF_MSG: return &PyUpb_MessageDefType; - default: return NULL; - } -} - -/* PyUpb_SymbolTable **********************************************************/ - -static PyTypeObject PyUpb_SymbolTableType; - -#define Check_SymbolTable(o, badret) \ - (void*)(((PyUpb_ObjWrapper*)o)->obj); do { \ - if(!PyObject_TypeCheck(o, &PyUpb_SymbolTableType)) { \ - PyErr_SetString(PyExc_TypeError, "must be a upb.MessageDef"); \ - return badret; \ - } \ - } while(0) - -static PyObject *PyUpb_SymbolTable_new(PyTypeObject *subtype, - PyObject *args, PyObject *kwds) { - return PyUpb_ObjCacheGet(upb_symtab_new(), subtype); -} - -static int PyUpb_SymbolTable_init(PyObject *self, PyObject *args, PyObject *kwds) { - return 0; -} - -static void PyUpb_SymbolTable_dealloc(PyObject *obj) { - PyUpb_ObjWrapper *wrapper = (void*)obj; - upb_symtab_unref((upb_symtab*)wrapper->obj); - obj->ob_type->tp_free(obj); -} - -// narg is a lua table containing a list of defs to add. -static PyObject *PyUpb_SymbolTable_add_defs(PyObject *o, PyObject *defs) { - upb_symtab *s = Check_SymbolTable(o, NULL); - if (!PySequence_Check(defs)) return PyUpb_Error("Must be a sequence"); - Py_ssize_t n = PySequence_Length(defs); - - // Prevent stack overflow. - if (n > 2048) return PyUpb_Error("Too many defs"); - upb_def *cdefs[n]; - - int i = 0; - for (i = 0; i < n; i++) { - PyObject *pydef = PySequence_GetItem(defs, i); - upb_def *def = Check_MessageDef(pydef, NULL); - cdefs[i++] = def; - upb_msgdef *md = upb_dyncast_msgdef(def); - if (!md) continue; - upb_msg_iter j; - for(j = upb_msg_begin(md); !upb_msg_done(j); j = upb_msg_next(md, j)) { - upb_fielddef *f = upb_msg_iter_field(j); - upb_fielddef_setaccessor(f, PyUpb_AccessorForField(f)); - } - upb_msgdef_layout(md); - } - - upb_status status = UPB_STATUS_INIT; - upb_symtab_add(s, cdefs, n, &status); - PyUpb_CheckStatus(&status); - return Py_None; -} - -static PyObject *PyUpb_SymbolTable_add_def(PyObject *o, PyObject *def) { - PyObject *defs = PyList_New(1); - PyList_SetItem(defs, 0, def); - return PyUpb_SymbolTable_add_defs(o, defs); -} - -// TODO: update to allow user to choose type of defs. -static PyObject *PyUpb_SymbolTable_defs(PyObject *o, PyObject *none) { - upb_symtab *s = Check_SymbolTable(o, NULL); - int count; - upb_def **defs = upb_symtab_getdefs(s, &count, UPB_DEF_ANY); - PyObject *ret = PyList_New(count); - int i; - for(i = 0; i < count; i++) - PyList_SetItem(ret, i, PyUpb_Def_GetOrCreate(defs[i])); - return ret; -} - -static PyObject *PyUpb_SymbolTable_lookup(PyObject *o, PyObject *arg) { - upb_symtab *s = Check_SymbolTable(o, NULL); - const char *name = PyString_AsString(arg); - upb_def *def = upb_symtab_lookup(s, name); - return PyUpb_Def_GetOrCreate(def); -} - -static PyMethodDef PyUpb_SymbolTable_methods[] = { - {"add_def", &PyUpb_SymbolTable_add_def, METH_O, NULL}, - {"add_defs", &PyUpb_SymbolTable_add_defs, METH_O, NULL}, - {"defs", &PyUpb_SymbolTable_defs, METH_NOARGS, NULL}, - {"lookup", &PyUpb_SymbolTable_lookup, METH_O, NULL}, - {NULL, NULL} -}; - -static PyTypeObject PyUpb_SymbolTableType = { - PyObject_HEAD_INIT(NULL) - 0, /* ob_size */ - "upb.SymbolTable", /* tp_name */ - sizeof(PyUpb_ObjWrapper), /* tp_basicsize */ - 0, /* tp_itemsize */ - &PyUpb_SymbolTable_dealloc, /* tp_dealloc */ - 0, /* tp_print */ - 0, /* tp_getattr */ - 0, /* tp_setattr */ - 0, /* tp_compare */ - 0, /* TODO */ /* tp_repr */ - 0, /* tp_as_number */ - 0, /* tp_as_sequence */ - 0, /* tp_as_mapping */ - 0, /* tp_hash */ - 0, /* tp_call */ - 0, /* tp_str */ - 0, /* tp_getattro */ - 0, /* tp_setattro */ - 0, /* tp_as_buffer */ - Py_TPFLAGS_DEFAULT, /* tp_flags */ - 0, /* tp_doc */ - 0, /* tp_traverse */ - 0, /* tp_clear */ - 0, /* tp_richcompare */ - offsetof(PyUpb_ObjWrapper, weakreflist),/* tp_weaklistoffset */ - 0, /* tp_iter */ - 0, /* tp_iternext */ - PyUpb_SymbolTable_methods, /* tp_methods */ - 0, /* tp_members */ - 0, /* tp_getset */ - 0, /* tp_base */ - 0, /* tp_dict */ - 0, /* tp_descr_get */ - 0, /* tp_descr_set */ - 0, /* tp_dictoffset */ - &PyUpb_SymbolTable_init, /* tp_init */ - 0, /* tp_alloc */ - &PyUpb_SymbolTable_new, /* tp_new */ - 0, /* tp_free */ -}; - - -/* Accessor and PyUpb_Message *************************************************/ - -typedef struct { - PyTypeObject type; - PyTypeObject *alt_type; -} PyUpb_MessageType; - -typedef struct { - PyObject_HEAD; - PyObject *msgdef; - char data[1]; -} PyUpb_Message; - -PyObject **PyUpb_Accessor_GetPtr(PyObject *_m, upb_value fval) { - PyUpb_Message *m = (PyUpb_Message*)_m; - upb_fielddef *f = upb_value_getfielddef(fval); - return (PyObject**)&m->data[f->offset]; -} - -static upb_sflow_t PyUpb_Message_StartSequence(void *m, upb_value fval) { - PyObject **seq = PyUpb_Accessor_GetPtr(m, fval); - PyTypeObject *type = ((PyUpb_MessageType*)Py_TYPE(m))->alt_type; - if (!*seq) *seq = type->tp_alloc(type, 0); - upb_stdmsg_sethas(m, fval); - return UPB_CONTINUE_WITH(*seq); -} - -static upb_sflow_t PyUpb_Message_StartSubmessage(void *m, upb_value fval) { - PyObject **submsg = PyUpb_Accessor_GetPtr(m, fval); - PyTypeObject *type = Py_TYPE(m); - if (!*submsg) *submsg = type->tp_alloc(type, 0); - upb_stdmsg_sethas(m, fval); - return UPB_CONTINUE_WITH(*submsg); -} - -static upb_sflow_t PyUpb_Message_StartRepeatedSubmessage(void *a, upb_value fval) { - (void)fval; - PyObject **elem = upb_stdarray_append(a, sizeof(void*)); - PyTypeObject *type = ((PyUpb_MessageType*)Py_TYPE(a))->alt_type; - if (!*elem) *elem = type->tp_alloc(type, 0); - return UPB_CONTINUE_WITH(*elem); -} - -static upb_flow_t PyUpb_Message_StringValue(void *m, upb_value fval, upb_value val) { - PyObject **str = PyUpb_Accessor_GetPtr(m, fval); - if (*str) Py_DECREF(*str); - *str = PyString_FromStringAndSize(NULL, upb_value_getstrref(val)->len); - upb_strref_read(upb_value_getstrref(val), PyString_AsString(*str)); - upb_stdmsg_sethas(m, fval); - return UPB_CONTINUE; -} - -static upb_flow_t PyUpb_Message_AppendStringValue(void *a, upb_value fval, upb_value val) { - (void)fval; - PyObject **elem = upb_stdarray_append(a, sizeof(void*)); - *elem = PyString_FromStringAndSize(NULL, upb_value_getstrref(val)->len); - upb_strref_read(upb_value_getstrref(val), PyString_AsString(*elem)); - return UPB_CONTINUE; -} - -#define STDMSG(type, size) static upb_accessor_vtbl vtbl = { \ - &PyUpb_Message_StartSubmessage, \ - &upb_stdmsg_set ## type, \ - &PyUpb_Message_StartSequence, \ - &PyUpb_Message_StartRepeatedSubmessage, \ - &upb_stdmsg_set ## type ## _r, \ - &upb_stdmsg_has, \ - &upb_stdmsg_getptr, \ - &upb_stdmsg_get ## type, \ - &upb_stdmsg_seqbegin, \ - &upb_stdmsg_ ## size ## byte_seqnext, \ - &upb_stdmsg_seqget ## type}; - -#define RETURN_STDMSG(type, size) { STDMSG(type, size); return &vtbl; } - -static upb_accessor_vtbl *PyUpb_AccessorForField(upb_fielddef *f) { - switch (f->type) { - case UPB_TYPE(DOUBLE): RETURN_STDMSG(double, 8) - case UPB_TYPE(FLOAT): RETURN_STDMSG(float, 4) - case UPB_TYPE(UINT64): - case UPB_TYPE(FIXED64): RETURN_STDMSG(uint64, 8) - case UPB_TYPE(INT64): - case UPB_TYPE(SFIXED64): - case UPB_TYPE(SINT64): RETURN_STDMSG(int64, 8) - case UPB_TYPE(INT32): - case UPB_TYPE(SINT32): - case UPB_TYPE(ENUM): - case UPB_TYPE(SFIXED32): RETURN_STDMSG(int32, 4) - case UPB_TYPE(UINT32): - case UPB_TYPE(FIXED32): RETURN_STDMSG(uint32, 4) - case UPB_TYPE(BOOL): { STDMSG(bool, 1); return &vtbl; } - case UPB_TYPE(GROUP): - case UPB_TYPE(MESSAGE): RETURN_STDMSG(ptr, 8) // TODO: 32-bit - case UPB_TYPE(STRING): - case UPB_TYPE(BYTES): { - STDMSG(ptr, 8); - vtbl.set = &PyUpb_Message_StringValue; - vtbl.append = &PyUpb_Message_AppendStringValue; - return &vtbl; - } - } - return NULL; -} - - -/* Toplevel *******************************************************************/ - -static PyMethodDef methods[] = { - {NULL, NULL} -}; - -// PyModule_AddObject steals a ref, but our object is statically allocated -// and must not be deleted. -#define PyUpb_AddType(mod, name, type) \ - if (PyType_Ready(type) < 0) return; \ - Py_INCREF(type); \ - PyModule_AddObject(mod, name, (PyObject*)type); - -PyMODINIT_FUNC initupb(void) { - PyObject *mod = Py_InitModule("upb", methods); - - PyUpb_AddType(mod, "FieldDef", &PyUpb_FieldDefType); - PyUpb_AddType(mod, "MessageDef", &PyUpb_MessageDefType); - PyUpb_AddType(mod, "SymbolTable", &PyUpb_SymbolTableType); - - PyModule_AddIntConstant(mod, "LABEL_OPTIONAL", UPB_LABEL(OPTIONAL)); - PyModule_AddIntConstant(mod, "LABEL_REQUIRED", UPB_LABEL(REQUIRED)); - PyModule_AddIntConstant(mod, "LABEL_REPEATED", UPB_LABEL(REPEATED)); - - PyModule_AddIntConstant(mod, "TYPE_DOUBLE", UPB_TYPE(DOUBLE)); - PyModule_AddIntConstant(mod, "TYPE_FLOAT", UPB_TYPE(FLOAT)); - PyModule_AddIntConstant(mod, "TYPE_INT64", UPB_TYPE(INT64)); - PyModule_AddIntConstant(mod, "TYPE_UINT64", UPB_TYPE(UINT64)); - PyModule_AddIntConstant(mod, "TYPE_INT32", UPB_TYPE(INT32)); - PyModule_AddIntConstant(mod, "TYPE_FIXED64", UPB_TYPE(FIXED64)); - PyModule_AddIntConstant(mod, "TYPE_FIXED32", UPB_TYPE(FIXED32)); - PyModule_AddIntConstant(mod, "TYPE_BOOL", UPB_TYPE(BOOL)); - PyModule_AddIntConstant(mod, "TYPE_STRING", UPB_TYPE(STRING)); - PyModule_AddIntConstant(mod, "TYPE_GROUP", UPB_TYPE(GROUP)); - PyModule_AddIntConstant(mod, "TYPE_MESSAGE", UPB_TYPE(MESSAGE)); - PyModule_AddIntConstant(mod, "TYPE_BYTES", UPB_TYPE(BYTES)); - PyModule_AddIntConstant(mod, "TYPE_UINT32", UPB_TYPE(UINT32)); - PyModule_AddIntConstant(mod, "TYPE_ENUM", UPB_TYPE(ENUM)); - PyModule_AddIntConstant(mod, "TYPE_SFIXED32", UPB_TYPE(SFIXED32)); - PyModule_AddIntConstant(mod, "TYPE_SFIXED64", UPB_TYPE(SFIXED64)); - PyModule_AddIntConstant(mod, "TYPE_SINT32", UPB_TYPE(SINT32)); - PyModule_AddIntConstant(mod, "TYPE_SINT64", UPB_TYPE(SINT64)); - - obj_cache = PyDict_New(); - reverse_cache = PyDict_New(); - static PyMethodDef method = { - "WeakRefCallback", &PyUpb_ObjCacheDeleteCallback, METH_O, NULL}; - PyObject *pyname = PyString_FromString(method.ml_name); - weakref_callback = PyCFunction_NewEx(&method, NULL, pyname); - Py_DECREF(pyname); -} diff --git a/lang_ext/python/upb/__init__.py b/lang_ext/python/upb/__init__.py deleted file mode 100644 index e69de29..0000000 diff --git a/upb/descriptor.c b/upb/descriptor.c index fbaef29..49ea5ae 100644 --- a/upb/descriptor.c +++ b/upb/descriptor.c @@ -304,6 +304,7 @@ static bool upb_fielddef_parsedefault(char *str, upb_value *d, int type) { } else if (type == UPB_TYPE(MESSAGE) || type == UPB_TYPE(GROUP)) { // We don't expect to get a default value. free(str); + upb_value_setptr(d, NULL); if (str != NULL) success = false; } else if (type == UPB_TYPE(BOOL)) { if (!str || strcmp(str, "false") == 0) @@ -356,6 +357,7 @@ static bool upb_fielddef_parsedefault(char *str, upb_value *d, int type) { upb_value_setfloat(d, strtof(str, &end)); if (errno == ERANGE || *end) success = false; break; + default: abort(); } free(str); } @@ -377,6 +379,7 @@ static void upb_fielddef_endmsg(void *_r, upb_status *status) { char *dstr = r->default_string; r->default_string = NULL; upb_value val; + upb_value_setptr(&val, NULL); // Silence inaccurate compiler warnings. if (!upb_fielddef_parsedefault(dstr, &val, f->type)) { // We don't worry too much about giving a great error message since the // compiler should have ensured this was correct. -- cgit v1.2.3