From 0fd2f830882402979a83010e89650e7245960d39 Mon Sep 17 00:00:00 2001 From: Josh Haberman Date: Tue, 21 Jan 2014 18:38:49 -0800 Subject: Sync to internal Google development. --- upb/bindings/lua/upb.c | 1208 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 1208 insertions(+) create mode 100644 upb/bindings/lua/upb.c (limited to 'upb/bindings/lua/upb.c') diff --git a/upb/bindings/lua/upb.c b/upb/bindings/lua/upb.c new file mode 100644 index 0000000..1e7540a --- /dev/null +++ b/upb/bindings/lua/upb.c @@ -0,0 +1,1208 @@ +/* + * upb - a minimalist implementation of protocol buffers. + * + * Copyright (c) 2009 Google Inc. See LICENSE for details. + * Author: Josh Haberman + * + * A Lua extension for upb. Exposes only the core library + * (sub-libraries are exposed in other extensions). + */ + +#include +#include +#include +#include +#include "lauxlib.h" +#include "upb/bindings/lua/upb.h" +#include "upb/handlers.h" +#include "upb/pb/glue.h" + +// Lua metatable types. +#define LUPB_MSGDEF "lupb.msgdef" +#define LUPB_ENUMDEF "lupb.enumdef" +#define LUPB_FIELDDEF "lupb.fielddef" +#define LUPB_SYMTAB "lupb.symtab" + +// Other table constants. +#define LUPB_OBJCACHE "lupb.objcache" + +#if LUA_VERSION_NUM == 501 + +// Taken from Lua 5.2's source. +void *luaL_testudata(lua_State *L, int ud, const char *tname) { + void *p = lua_touserdata(L, ud); + if (p != NULL) { /* value is a userdata? */ + if (lua_getmetatable(L, ud)) { /* does it have a metatable? */ + luaL_getmetatable(L, tname); /* get correct metatable */ + if (!lua_rawequal(L, -1, -2)) /* not the same? */ + p = NULL; /* value is a userdata with wrong metatable */ + lua_pop(L, 2); /* remove both metatables */ + return p; + } + } + return NULL; /* value is not a userdata with a metatable */ +} + +#elif LUA_VERSION_NUM == 502 + +int luaL_typerror(lua_State *L, int narg, const char *tname) { + const char *msg = lua_pushfstring(L, "%s expected, got %s", + tname, luaL_typename(L, narg)); + return luaL_argerror(L, narg, msg); +} + +#else +#error Only Lua 5.1 and 5.2 are supported +#endif + +static const char *chkname(lua_State *L, int narg) { + size_t len; + const char *name = luaL_checklstring(L, narg, &len); + if (strlen(name) != len) + luaL_error(L, "names cannot have embedded NULLs"); + return name; +} + +static bool chkbool(lua_State *L, int narg, const char *type) { + if (!lua_isboolean(L, narg)) { + luaL_error(L, "%s must be true or false", type); + } + return lua_toboolean(L, narg); +} + +static bool streql(const char *a, const char *b) { return strcmp(a, b) == 0; } + +static uint32_t chkint32(lua_State *L, int narg, const char *name) { + lua_Number n = lua_tonumber(L, narg); + if (n > INT32_MAX || n < INT32_MIN || rint(n) != n) + luaL_error(L, "Invalid %s", name); + return n; +} + +// Sets a fielddef default from the given Lua value. +static void lupb_setdefault(lua_State *L, int narg, upb_fielddef *f) { + if (upb_fielddef_type(f) == UPB_TYPE_BOOL) { + upb_fielddef_setdefaultbool(f, chkbool(L, narg, "bool default")); + } else { + // Numeric type. + lua_Number num = luaL_checknumber(L, narg); + switch (upb_fielddef_type(f)) { + case UPB_TYPE_INT32: + case UPB_TYPE_ENUM: + if (num > INT32_MAX || num < INT32_MIN || num != rint(num)) + luaL_error(L, "Cannot convert %f to 32-bit integer", num); + upb_fielddef_setdefaultint32(f, num); + break; + case UPB_TYPE_INT64: + if (num > INT64_MAX || num < INT64_MIN || num != rint(num)) + luaL_error(L, "Cannot convert %f to 64-bit integer", num); + upb_fielddef_setdefaultint64(f, num); + break; + case UPB_TYPE_UINT32: + if (num > UINT32_MAX || num < 0 || num != rint(num)) + luaL_error(L, "Cannot convert %f to unsigned 32-bit integer", num); + upb_fielddef_setdefaultuint32(f, num); + break; + case UPB_TYPE_UINT64: + if (num > UINT64_MAX || num < 0 || num != rint(num)) + luaL_error(L, "Cannot convert %f to unsigned 64-bit integer", num); + upb_fielddef_setdefaultuint64(f, num); + break; + case UPB_TYPE_DOUBLE: + if (num > DBL_MAX || num < -DBL_MAX) { + // This could happen if lua_Number was long double. + luaL_error(L, "Cannot convert %f to double", num); + } + upb_fielddef_setdefaultdouble(f, num); + break; + case UPB_TYPE_FLOAT: + if (num > FLT_MAX || num < -FLT_MAX) + luaL_error(L, "Cannot convert %f to float", num); + upb_fielddef_setdefaultfloat(f, num); + break; + default: luaL_error(L, "invalid type"); + } + } +} + +void lupb_checkstatus(lua_State *L, upb_status *s) { + if (!upb_ok(s)) { + lua_pushstring(L, upb_status_errmsg(s)); + lua_error(L); + } +} + +#define CHK(pred) do { \ + upb_status status = UPB_STATUS_INIT; \ + pred; \ + lupb_checkstatus(L, &status); \ + } while (0) + + +/* refcounted *****************************************************************/ + +// All upb objects that use upb_refcounted share a common Lua userdata +// representation and a common scheme for caching Lua wrapper object. They do +// however have different metatables. Objects are cached in a weak table +// indexed by the C pointer of the object they are caching. + +typedef union { + const upb_refcounted *refcounted; + const upb_def *def; + upb_symtab *symtab; +} lupb_refcounted; + +static bool lupb_refcounted_pushwrapper(lua_State *L, const upb_refcounted *obj, + const char *type, const void *owner) { + if (obj == NULL) { + lua_pushnil(L); + return false; + } + + // Lookup our cache in the registry (we don't put our objects in the registry + // directly because we need our cache to be a weak table). + lupb_refcounted *ud = NULL; + lua_getfield(L, LUA_REGISTRYINDEX, LUPB_OBJCACHE); + assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb. + lua_pushlightuserdata(L, (void*)obj); + lua_rawget(L, -2); + // Stack: objcache, cached value. + bool create = lua_isnil(L, -1) || + // A corner case: it is possible for the value to be GC'd + // already, in which case we should evict this entry and create + // a new one. + ((lupb_refcounted*)lua_touserdata(L, -1))->refcounted == NULL; + if (create) { + // Remove bad cached value and push new value. + lua_pop(L, 1); + + // We take advantage of the fact that all of our objects are currently a + // single pointer, and thus have the same layout. + // TODO: this probably violates aliasing. + ud = lua_newuserdata(L, sizeof(lupb_refcounted)); + ud->refcounted = obj; + upb_refcounted_donateref(obj, owner, ud); + + luaL_getmetatable(L, type); + assert(!lua_isnil(L, -1)); // Should have been created by luaopen_upb. + lua_setmetatable(L, -2); + + // Set it in the cache. + lua_pushlightuserdata(L, (void*)obj); + lua_pushvalue(L, -2); + lua_rawset(L, -4); + } else { + // Existing wrapper obj already has a ref. + ud = lua_touserdata(L, -1); + upb_refcounted_checkref(obj, ud); + if (owner) + upb_refcounted_unref(obj, owner); + } + lua_insert(L, -2); + lua_pop(L, 1); + return create; +} + +static void lupb_refcounted_pushnewrapper(lua_State *L, upb_refcounted *obj, + const char *type, const void *owner) { + bool created = lupb_refcounted_pushwrapper(L, obj, type, owner); + UPB_ASSERT_VAR(created, created == true); +} + + +/* lupb_def *******************************************************************/ + +static const upb_def *lupb_def_check(lua_State *L, int narg) { + lupb_refcounted *r = luaL_testudata(L, narg, LUPB_MSGDEF); + if (!r) r = luaL_testudata(L, narg, LUPB_ENUMDEF); + if (!r) r = luaL_testudata(L, narg, LUPB_FIELDDEF); + if (!r) luaL_typerror(L, narg, "upb def"); + if (!r->refcounted) luaL_error(L, "called into dead def"); + return r->def; +} + +static upb_def *lupb_def_checkmutable(lua_State *L, int narg) { + const upb_def *def = lupb_def_check(L, narg); + if (upb_def_isfrozen(def)) + luaL_typerror(L, narg, "not allowed on frozen value"); + return (upb_def*)def; +} + +bool lupb_def_pushwrapper(lua_State *L, const upb_def *def, const void *owner) { + if (def == NULL) { + lua_pushnil(L); + return false; + } + + const char *type = NULL; + switch (def->type) { + case UPB_DEF_MSG: type = LUPB_MSGDEF; break; + case UPB_DEF_ENUM: type = LUPB_ENUMDEF; break; + case UPB_DEF_FIELD: type = LUPB_FIELDDEF; break; + default: luaL_error(L, "unknown deftype %d", def->type); + } + return lupb_refcounted_pushwrapper(L, UPB_UPCAST(def), type, owner); +} + +void lupb_def_pushnewrapper(lua_State *L, const upb_def *def, + const void *owner) { + bool created = lupb_def_pushwrapper(L, def, owner); + UPB_ASSERT_VAR(created, created == true); +} + +static int lupb_def_type(lua_State *L) { + const upb_def *def = lupb_def_check(L, 1); + lua_pushnumber(L, upb_def_type(def)); + return 1; +} + +static int lupb_def_isfrozen(lua_State *L) { + const upb_def *def = lupb_def_check(L, 1); + lua_pushboolean(L, upb_def_isfrozen(def)); + return 1; +} + +static int lupb_def_fullname(lua_State *L) { + const upb_def *def = lupb_def_check(L, 1); + lua_pushstring(L, upb_def_fullname(def)); + return 1; +} + +static int lupb_def_setfullname(lua_State *L) { + CHK(upb_def_setfullname(lupb_def_checkmutable(L, 1), chkname(L, 2), &status)); + return 0; +} + +#define LUPB_COMMON_DEF_METHODS \ + {"def_type", lupb_def_type}, \ + {"full_name", lupb_def_fullname}, \ + {"is_frozen", lupb_def_isfrozen}, \ + {"set_full_name", lupb_def_setfullname}, \ + + +/* lupb_fielddef **************************************************************/ + +static const upb_fielddef *lupb_fielddef_check(lua_State *L, int narg) { + lupb_refcounted *r = luaL_checkudata(L, narg, LUPB_FIELDDEF); + if (!r) luaL_typerror(L, narg, "upb fielddef"); + if (!r->refcounted) luaL_error(L, "called into dead fielddef"); + return upb_downcast_fielddef(r->def); +} + +static upb_fielddef *lupb_fielddef_checkmutable(lua_State *L, int narg) { + const upb_fielddef *f = lupb_fielddef_check(L, narg); + if (upb_fielddef_isfrozen(f)) + luaL_typerror(L, narg, "not allowed on frozen value"); + return (upb_fielddef*)f; +} + +// Setter functions; these are called by both the constructor and the individual +// setter API calls like field:set_type(). + +static void lupb_fielddef_dosetdefault(lua_State *L, upb_fielddef *f, + int narg) { + int type = lua_type(L, narg); + upb_fieldtype_t upbtype = upb_fielddef_type(f); + if (type == LUA_TSTRING) { + if (!upb_fielddef_isstring(f) && upbtype != UPB_TYPE_ENUM) + luaL_argerror(L, narg, "field does not expect a string default"); + size_t len; + const char *str = lua_tolstring(L, narg, &len); + CHK(upb_fielddef_setdefaultstr(f, str, len, &status)); + } else { + lupb_setdefault(L, narg, f); + } +} + +static void lupb_fielddef_dosetisextension(lua_State *L, upb_fielddef *f, + int narg) { + CHK(upb_fielddef_setisextension(f, chkbool(L, narg, "is_extension"))); +} + +static void lupb_fielddef_dosetlabel(lua_State *L, upb_fielddef *f, int narg) { + int label = luaL_checkint(L, narg); + if (!upb_fielddef_checklabel(label)) + luaL_argerror(L, narg, "invalid field label"); + upb_fielddef_setlabel(f, label); +} + +static void lupb_fielddef_dosetname(lua_State *L, upb_fielddef *f, int narg) { + CHK(upb_fielddef_setname(f, chkname(L, narg), &status)); +} + +static void lupb_fielddef_dosetnumber(lua_State *L, upb_fielddef *f, int narg) { + CHK(upb_fielddef_setnumber(f, luaL_checkint(L, narg), &status)); +} + +static void lupb_fielddef_dosetsubdef(lua_State *L, upb_fielddef *f, int narg) { + const upb_def *def = NULL; + if (!lua_isnil(L, narg)) + def = lupb_def_check(L, narg); + CHK(upb_fielddef_setsubdef(f, def, &status)); +} + +static void lupb_fielddef_dosetsubdefname(lua_State *L, upb_fielddef *f, + int narg) { + const char *name = NULL; + if (!lua_isnil(L, narg)) + name = chkname(L, narg); + CHK(upb_fielddef_setsubdefname(f, name, &status)); +} + +static void lupb_fielddef_dosetcontainingtypename(lua_State *L, upb_fielddef *f, + int narg) { + const char *name = NULL; + if (!lua_isnil(L, narg)) + name = chkname(L, narg); + CHK(upb_fielddef_setcontainingtypename(f, name, &status)); +} + +static void lupb_fielddef_dosettype(lua_State *L, upb_fielddef *f, int narg) { + int type = luaL_checkint(L, narg); + if (!upb_fielddef_checktype(type)) + luaL_argerror(L, narg, "invalid field type"); + upb_fielddef_settype(f, type); +} + +static void lupb_fielddef_dosetintfmt(lua_State *L, upb_fielddef *f, int narg) { + int32_t intfmt = luaL_checknumber(L, narg); + if (!upb_fielddef_checkintfmt(intfmt)) + luaL_argerror(L, narg, "invalid intfmt"); + upb_fielddef_setintfmt(f, intfmt); +} + +static void lupb_fielddef_dosettagdelim(lua_State *L, upb_fielddef *f, + int narg) { + CHK(upb_fielddef_settagdelim(f, chkbool(L, narg, "tagdelim"))); +} + +// Setter API calls. These use the setter functions above. + +static int lupb_fielddef_setcontainingtypename(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetcontainingtypename(L, f, 2); + return 0; +} + +static int lupb_fielddef_setdefault(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetdefault(L, f, 2); + return 0; +} + +static int lupb_fielddef_setisextension(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetisextension(L, f, 2); + return 0; +} + +static int lupb_fielddef_setlabel(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetlabel(L, f, 2); + return 0; +} + +static int lupb_fielddef_setname(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetname(L, f, 2); + return 0; +} + +static int lupb_fielddef_setnumber(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetnumber(L, f, 2); + return 0; +} + +static int lupb_fielddef_setsubdef(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetsubdef(L, f, 2); + return 0; +} + +static int lupb_fielddef_setsubdefname(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetsubdefname(L, f, 2); + return 0; +} + +static int lupb_fielddef_settype(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosettype(L, f, 2); + return 0; +} + +static int lupb_fielddef_setintfmt(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosetintfmt(L, f, 2); + return 0; +} + +static int lupb_fielddef_settagdelim(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lupb_fielddef_dosettagdelim(L, f, 2); + return 0; +} + +// Constructor and other methods. + +static int lupb_fielddef_new(lua_State *L) { + upb_fielddef *f = upb_fielddef_new(&f); + int narg = lua_gettop(L); + + lupb_def_pushnewrapper(L, UPB_UPCAST(f), &f); + + if (narg == 0) return 1; + + // User can specify initialization values like so: + // upb.FieldDef{label=upb.LABEL_REQUIRED, name="my_field", number=5, + // type=upb.TYPE_INT32, default_value=12, type_name="Foo"} + luaL_checktype(L, 1, LUA_TTABLE); + for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) { + luaL_checktype(L, -2, LUA_TSTRING); + const char *key = lua_tostring(L, -2); + int v = -1; + if (streql(key, "name")) lupb_fielddef_dosetname(L, f, v); + else if (streql(key, "number")) lupb_fielddef_dosetnumber(L, f, v); + else if (streql(key, "type")) lupb_fielddef_dosettype(L, f, v); + else if (streql(key, "label")) lupb_fielddef_dosetlabel(L, f, v); + else if (streql(key, "is_extension")) + lupb_fielddef_dosetisextension(L, f, v); + else if (streql(key, "containing_type_name")) + lupb_fielddef_dosetcontainingtypename(L, f, v); + else if (streql(key, "default_value")) ; // Defer to second pass. + else if (streql(key, "subdef")) ; // Defer to second pass. + else if (streql(key, "subdef_name")) ; // Defer to second pass. + else luaL_error(L, "Cannot set fielddef member '%s'", key); + } + + // Have to do these in a second pass because these depend on the type, so we + // have to make sure the type is set if the user specified one. + for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) { + const char *key = lua_tostring(L, -2); + int v = -1; + if (streql(key, "default_value")) lupb_fielddef_dosetdefault(L, f, v); + else if (streql(key, "subdef")) lupb_fielddef_dosetsubdef(L, f, v); + else if (streql(key, "subdef_name")) lupb_fielddef_dosetsubdefname(L, f, v); + } + + return 1; +} + +static int lupb_fielddef_default(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + switch (upb_fielddef_type(f)) { + case UPB_TYPE_INT32: + int32: + lua_pushnumber(L, upb_fielddef_defaultint32(f)); break; + case UPB_TYPE_INT64: + lua_pushnumber(L, upb_fielddef_defaultint64(f)); break; + case UPB_TYPE_UINT32: + lua_pushnumber(L, upb_fielddef_defaultuint32(f)); break; + case UPB_TYPE_UINT64: + lua_pushnumber(L, upb_fielddef_defaultuint64(f)); break; + case UPB_TYPE_DOUBLE: + lua_pushnumber(L, upb_fielddef_defaultdouble(f)); break; + case UPB_TYPE_FLOAT: + lua_pushnumber(L, upb_fielddef_defaultfloat(f)); break; + case UPB_TYPE_BOOL: + lua_pushboolean(L, upb_fielddef_defaultbool(f)); break; + case UPB_TYPE_ENUM: + if (!upb_fielddef_default_is_symbolic(f)) + goto int32; + // Fallthrough. + case UPB_TYPE_STRING: + case UPB_TYPE_BYTES: { + size_t len; + const char *data = upb_fielddef_defaultstr(f, &len); + lua_pushlstring(L, data, len); + break; + } + case UPB_TYPE_MESSAGE: + return luaL_error(L, "Message fields do not have explicit defaults."); + } + return 1; +} + +static int lupb_fielddef_getsel(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + upb_selector_t sel; + if (upb_handlers_getselector(f, luaL_checknumber(L, 2), &sel)) { + lua_pushnumber(L, sel); + return 1; + } else { + return 0; + } +} + +static int lupb_fielddef_label(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + lua_pushnumber(L, upb_fielddef_label(f)); + return 1; +} + +static int lupb_fielddef_name(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + lua_pushstring(L, upb_fielddef_name(f)); + return 1; +} + +static int lupb_fielddef_number(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + int32_t num = upb_fielddef_number(f); + if (num) + lua_pushnumber(L, num); + else + lua_pushnil(L); + return 1; +} + +static int lupb_fielddef_selectorbase(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + if (!upb_fielddef_isfrozen(f)) + luaL_error(L, "_selectorbase is only defined for frozen fielddefs"); + lua_pushnumber(L, f->selector_base); + return 1; +} + +static int lupb_fielddef_hassubdef(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + lua_pushboolean(L, upb_fielddef_hassubdef(f)); + return 1; +} + +static int lupb_fielddef_containingtype(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + lupb_def_pushwrapper(L, UPB_UPCAST(upb_fielddef_containingtype(f)), NULL); + return 1; +} + +static int lupb_fielddef_containingtypename(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + lua_pushstring(L, upb_fielddef_containingtypename(f)); + return 1; +} + +static int lupb_fielddef_subdef(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + if (!upb_fielddef_hassubdef(f)) + luaL_error(L, "Tried to get subdef of non-message field"); + const upb_def *def = upb_fielddef_subdef(f); + lupb_def_pushwrapper(L, def, NULL); + return 1; +} + +static int lupb_fielddef_subdefname(lua_State *L) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, 1); + if (!upb_fielddef_hassubdef(f)) + luaL_error(L, "Tried to get subdef name of non-message field"); + lua_pushstring(L, upb_fielddef_subdefname(f)); + return 1; +} + +static int lupb_fielddef_type(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + if (upb_fielddef_typeisset(f)) + lua_pushnumber(L, upb_fielddef_type(f)); + else + lua_pushnil(L); + return 1; +} + +static int lupb_fielddef_index(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + lua_pushnumber(L, upb_fielddef_index(f)); + return 1; +} + +static int lupb_fielddef_intfmt(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + lua_pushnumber(L, upb_fielddef_intfmt(f)); + return 1; +} + +static int lupb_fielddef_isextension(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + lua_pushboolean(L, upb_fielddef_isextension(f)); + return 1; +} + +static int lupb_fielddef_istagdelim(lua_State *L) { + const upb_fielddef *f = lupb_fielddef_check(L, 1); + lua_pushboolean(L, upb_fielddef_istagdelim(f)); + return 1; +} + +static int lupb_fielddef_gc(lua_State *L) { + lupb_refcounted *r = luaL_checkudata(L, 1, LUPB_FIELDDEF); + upb_def_unref(r->def, r); + r->refcounted = NULL; + return 0; +} + +static const struct luaL_Reg lupb_fielddef_m[] = { + LUPB_COMMON_DEF_METHODS + + {"containing_type", lupb_fielddef_containingtype}, + {"containing_type_name", lupb_fielddef_containingtypename}, + {"default", lupb_fielddef_default}, + {"getsel", lupb_fielddef_getsel}, + {"has_subdef", lupb_fielddef_hassubdef}, + {"index", lupb_fielddef_index}, + {"intfmt", lupb_fielddef_intfmt}, + {"is_extension", lupb_fielddef_isextension}, + {"istagdelim", lupb_fielddef_istagdelim}, + {"label", lupb_fielddef_label}, + {"name", lupb_fielddef_name}, + {"number", lupb_fielddef_number}, + {"subdef", lupb_fielddef_subdef}, + {"subdef_name", lupb_fielddef_subdefname}, + {"type", lupb_fielddef_type}, + + {"set_containing_type_name", lupb_fielddef_setcontainingtypename}, + {"set_default", lupb_fielddef_setdefault}, + {"set_is_extension", lupb_fielddef_setisextension}, + {"set_label", lupb_fielddef_setlabel}, + {"set_name", lupb_fielddef_setname}, + {"set_number", lupb_fielddef_setnumber}, + {"set_subdef", lupb_fielddef_setsubdef}, + {"set_subdef_name", lupb_fielddef_setsubdefname}, + {"set_type", lupb_fielddef_settype}, + {"set_intfmt", lupb_fielddef_setintfmt}, + {"set_tagdelim", lupb_fielddef_settagdelim}, + + // Internal-only. + {"_selector_base", lupb_fielddef_selectorbase}, + + {NULL, NULL} +}; + +static const struct luaL_Reg lupb_fielddef_mm[] = { + {"__gc", lupb_fielddef_gc}, + {NULL, NULL} +}; + + +/* lupb_msgdef ****************************************************************/ + +const upb_msgdef *lupb_msgdef_check(lua_State *L, int narg) { + lupb_refcounted *r = luaL_checkudata(L, narg, LUPB_MSGDEF); + if (!r) luaL_typerror(L, narg, LUPB_MSGDEF); + if (!r->refcounted) luaL_error(L, "called into dead msgdef"); + return upb_downcast_msgdef(r->def); +} + +static upb_msgdef *lupb_msgdef_checkmutable(lua_State *L, int narg) { + const upb_msgdef *m = lupb_msgdef_check(L, narg); + if (upb_msgdef_isfrozen(m)) + luaL_typerror(L, narg, "not allowed on frozen value"); + return (upb_msgdef*)m; +} + +static int lupb_msgdef_gc(lua_State *L) { + lupb_refcounted *r = luaL_checkudata(L, 1, LUPB_MSGDEF); + upb_def_unref(r->def, r); + r->refcounted = NULL; + return 0; +} + +static int lupb_msgdef_new(lua_State *L) { + int narg = lua_gettop(L); + upb_msgdef *md = upb_msgdef_new(&md); + lupb_def_pushnewrapper(L, UPB_UPCAST(md), &md); + + if (narg == 0) return 1; + + // User can specify initialization values like so: + // upb.MessageDef{full_name="MyMessage", extstart=8000, fields={...}} + luaL_checktype(L, 1, LUA_TTABLE); + for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) { + luaL_checktype(L, -2, LUA_TSTRING); + const char *key = lua_tostring(L, -2); + + if (streql(key, "full_name")) { // full_name="MyMessage" + CHK(upb_def_setfullname(UPB_UPCAST(md), chkname(L, -1), &status)); + } else if (streql(key, "fields")) { // fields={...} + // Iterate over the list of fields. + luaL_checktype(L, -1, LUA_TTABLE); + for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { + upb_fielddef *f = lupb_fielddef_checkmutable(L, -1); + CHK(upb_msgdef_addfield(md, f, NULL, &status)); + } + } else { + // TODO: extrange= + luaL_error(L, "Unknown initializer key '%s'", key); + } + } + return 1; +} + +static int lupb_msgdef_add(lua_State *L) { + upb_msgdef *m = lupb_msgdef_checkmutable(L, 1); + luaL_checktype(L, 2, LUA_TTABLE); + int n = lua_rawlen(L, 2); + // TODO: add upb interface that lets us avoid this malloc/free. + upb_fielddef **fields = malloc(n * sizeof(upb_fielddef*)); + for (int i = 0; i < n; i++) { + lua_rawgeti(L, -1, i + 1); + fields[i] = lupb_fielddef_checkmutable(L, -1); + lua_pop(L, 1); + } + + upb_status status = UPB_STATUS_INIT; + upb_msgdef_addfields(m, fields, n, NULL, &status); + free(fields); + lupb_checkstatus(L, &status); + return 0; +} + +static int lupb_msgdef_len(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + lua_pushinteger(L, upb_msgdef_numfields(m)); + return 1; +} + +static int lupb_msgdef_selectorcount(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + lua_pushinteger(L, m->selector_count); + return 1; +} + +static int lupb_msgdef_submsgfieldcount(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + lua_pushinteger(L, m->submsg_field_count); + return 1; +} + +static int lupb_msgdef_field(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + int type = lua_type(L, 2); + const upb_fielddef *f; + if (type == LUA_TNUMBER) { + f = upb_msgdef_itof(m, lua_tointeger(L, 2)); + } else if (type == LUA_TSTRING) { + f = upb_msgdef_ntof(m, lua_tostring(L, 2)); + } else { + const char *msg = lua_pushfstring(L, "number or string expected, got %s", + luaL_typename(L, 2)); + return luaL_argerror(L, 2, msg); + } + + lupb_def_pushwrapper(L, UPB_UPCAST(f), NULL); + return 1; +} + +static int lupb_msgiter_next(lua_State *L) { + upb_msg_iter *i = lua_touserdata(L, lua_upvalueindex(1)); + if (upb_msg_done(i)) return 0; + lupb_def_pushwrapper(L, UPB_UPCAST(upb_msg_iter_field(i)), NULL); + upb_msg_next(i); + return 1; +} + +static int lupb_msgdef_fields(lua_State *L) { + const upb_msgdef *m = lupb_msgdef_check(L, 1); + upb_msg_iter *i = lua_newuserdata(L, sizeof(upb_msg_iter)); + upb_msg_begin(i, m); + lua_pushcclosure(L, &lupb_msgiter_next, 1); + return 1; +} + +static const struct luaL_Reg lupb_msgdef_mm[] = { + {"__gc", lupb_msgdef_gc}, + {"__len", lupb_msgdef_len}, + {NULL, NULL} +}; + +static const struct luaL_Reg lupb_msgdef_m[] = { + LUPB_COMMON_DEF_METHODS + {"add", lupb_msgdef_add}, + {"field", lupb_msgdef_field}, + {"fields", lupb_msgdef_fields}, + + // Internal-only. + {"_selector_count", lupb_msgdef_selectorcount}, + {"_submsg_field_count", lupb_msgdef_submsgfieldcount}, + + {NULL, NULL} +}; + + +/* lupb_enumdef ***************************************************************/ + +const upb_enumdef *lupb_enumdef_check(lua_State *L, int narg) { + lupb_refcounted *r = luaL_checkudata(L, narg, LUPB_ENUMDEF); + if (!r) luaL_typerror(L, narg, LUPB_ENUMDEF); + if (!r->refcounted) luaL_error(L, "called into dead enumdef"); + return upb_downcast_enumdef(r->def); +} + +static upb_enumdef *lupb_enumdef_checkmutable(lua_State *L, int narg) { + const upb_enumdef *f = lupb_enumdef_check(L, narg); + if (upb_enumdef_isfrozen(f)) + luaL_typerror(L, narg, "not allowed on frozen value"); + return (upb_enumdef*)f; +} + +static int lupb_enumdef_gc(lua_State *L) { + lupb_refcounted *r = luaL_checkudata(L, 1, LUPB_ENUMDEF); + upb_def_unref(r->def, r); + r->refcounted = NULL; + return 0; +} + +static int lupb_enumdef_new(lua_State *L) { + int narg = lua_gettop(L); + upb_enumdef *e = upb_enumdef_new(&e); + lupb_def_pushnewrapper(L, UPB_UPCAST(e), &e); + + if (narg == 0) return 1; + + // User can specify initialization values like so: + // upb.EnumDef{full_name="MyEnum", + // values={ + // {"FOO_VALUE_1", 1}, + // {"FOO_VALUE_2", 2} + // } + // } + luaL_checktype(L, 1, LUA_TTABLE); + for (lua_pushnil(L); lua_next(L, 1); lua_pop(L, 1)) { + luaL_checktype(L, -2, LUA_TSTRING); + const char *key = lua_tostring(L, -2); + if (streql(key, "values")) { + for (lua_pushnil(L); lua_next(L, -2); lua_pop(L, 1)) { + lua_rawgeti(L, -1, 1); + luaL_checktype(L, -1, LUA_TSTRING); + const char *name = lua_tostring(L, -1); + lua_rawgeti(L, -2, 2); + CHK(upb_enumdef_addval(e, name, chkint32(L, -1, "value"), &status)); + lua_pop(L, 2); // The key/val we got from lua_rawgeti() + } + } else if (streql(key, "full_name")) { + CHK(upb_def_setfullname(UPB_UPCAST(e), chkname(L, -1), &status)); + } else { + luaL_error(L, "Unknown initializer key '%s'", key); + } + } + return 1; +} + +static int lupb_enumdef_add(lua_State *L) { + upb_enumdef *e = lupb_enumdef_checkmutable(L, 1); + CHK(upb_enumdef_addval(e, chkname(L, 2), chkint32(L, 3, "value"), &status)); + return 0; +} + +static int lupb_enumdef_len(lua_State *L) { + const upb_enumdef *e = lupb_enumdef_check(L, 1); + lua_pushinteger(L, upb_enumdef_numvals(e)); + return 1; +} + +static int lupb_enumdef_value(lua_State *L) { + const upb_enumdef *e = lupb_enumdef_check(L, 1); + int type = lua_type(L, 2); + if (type == LUA_TNUMBER) { + // Pushes "nil" for a NULL pointer. + lua_pushstring(L, upb_enumdef_iton(e, chkint32(L, 2, "value"))); + } else if (type == LUA_TSTRING) { + int32_t num; + if (upb_enumdef_ntoi(e, lua_tostring(L, 2), &num)) { + lua_pushnumber(L, num); + } else { + lua_pushnil(L); + } + } else { + const char *msg = lua_pushfstring(L, "number or string expected, got %s", + luaL_typename(L, 2)); + return luaL_argerror(L, 2, msg); + } + return 1; +} + +static int lupb_enumiter_next(lua_State *L) { + upb_enum_iter *i = lua_touserdata(L, lua_upvalueindex(1)); + if (upb_enum_done(i)) return 0; + lua_pushstring(L, upb_enum_iter_name(i)); + lua_pushnumber(L, upb_enum_iter_number(i)); + upb_enum_next(i); + return 2; +} + +static int lupb_enumdef_values(lua_State *L) { + const upb_enumdef *e = lupb_enumdef_check(L, 1); + upb_enum_iter *i = lua_newuserdata(L, sizeof(upb_enum_iter)); + upb_enum_begin(i, e); + lua_pushcclosure(L, &lupb_enumiter_next, 1); + return 1; +} + +static const struct luaL_Reg lupb_enumdef_mm[] = { + {"__gc", lupb_enumdef_gc}, + {"__len", lupb_enumdef_len}, + {NULL, NULL} +}; + +static const struct luaL_Reg lupb_enumdef_m[] = { + LUPB_COMMON_DEF_METHODS + {"add", lupb_enumdef_add}, + {"value", lupb_enumdef_value}, + {"values", lupb_enumdef_values}, + {NULL, NULL} +}; + + +/* lupb_symtab ****************************************************************/ + +// Inherits a ref on the symtab. +// Checks that narg is a proper lupb_symtab object. If it is, leaves its +// metatable on the stack for cache lookups/updates. +upb_symtab *lupb_symtab_check(lua_State *L, int narg) { + lupb_refcounted *r = luaL_checkudata(L, narg, LUPB_SYMTAB); + if (!r) luaL_typerror(L, narg, LUPB_SYMTAB); + if (!r->refcounted) luaL_error(L, "called into dead symtab"); + return r->symtab; +} + +// narg is a lua table containing a list of defs to add. +void lupb_symtab_doadd(lua_State *L, upb_symtab *s, int narg) { + luaL_checktype(L, narg, LUA_TTABLE); + // Iterate over table twice. First iteration to count entries and + // check constraints. + int n = 0; + for (lua_pushnil(L); lua_next(L, narg); lua_pop(L, 1)) { + lupb_def_check(L, -1); + ++n; + } + + // Second iteration to build deflist and layout. + upb_def **defs = malloc(n * sizeof(*defs)); + n = 0; + for (lua_pushnil(L); lua_next(L, narg); lua_pop(L, 1)) { + upb_def *def = lupb_def_checkmutable(L, -1); + defs[n++] = def; + } + + upb_status status = UPB_STATUS_INIT; + upb_symtab_add(s, defs, n, NULL, &status); + free(defs); + lupb_checkstatus(L, &status); +} + +static int lupb_symtab_new(lua_State *L) { + int narg = lua_gettop(L); + upb_symtab *s = upb_symtab_new(&s); + lupb_refcounted_pushnewrapper(L, UPB_UPCAST(s), LUPB_SYMTAB, &s); + if (narg > 0) lupb_symtab_doadd(L, s, 1); + return 1; +} + +static int lupb_symtab_add(lua_State *L) { + lupb_symtab_doadd(L, lupb_symtab_check(L, 1), 2); + return 0; +} + +static int lupb_symtab_gc(lua_State *L) { + lupb_refcounted *r = luaL_checkudata(L, 1, LUPB_SYMTAB); + upb_symtab_unref(r->symtab, r); + r->refcounted = NULL; + return 0; +} + +static int lupb_symtab_lookup(lua_State *L) { + upb_symtab *s = lupb_symtab_check(L, 1); + for (int i = 2; i <= lua_gettop(L); i++) { + const upb_def *def = + upb_symtab_lookup(s, luaL_checkstring(L, i), &def); + lupb_def_pushwrapper(L, def, &def); + lua_replace(L, i); + } + return lua_gettop(L) - 1; +} + +static int lupb_symtab_getdefs(lua_State *L) { + upb_symtab *s = lupb_symtab_check(L, 1); + upb_deftype_t type = luaL_checkint(L, 2); + int count; + const upb_def **defs = upb_symtab_getdefs(s, type, &defs, &count); + + // Create the table in which we will return the defs. + lua_createtable(L, count, 0); + for (int i = 0; i < count; i++) { + const upb_def *def = defs[i]; + lupb_def_pushwrapper(L, def, &defs); + lua_rawseti(L, -2, i + 1); + } + free(defs); + return 1; +} + +// This is a *temporary* API that will be removed once pending refactorings are +// complete (it does not belong here in core because it depends on both +// the descriptor.proto schema and the protobuf binary format. +static int lupb_symtab_load_descriptor(lua_State *L) { + size_t len; + upb_symtab *s = lupb_symtab_check(L, 1); + const char *str = luaL_checklstring(L, 2, &len); + CHK(upb_load_descriptor_into_symtab(s, str, len, &status)); + return 0; +} + +static const struct luaL_Reg lupb_symtab_m[] = { + {"add", lupb_symtab_add}, + {"getdefs", lupb_symtab_getdefs}, + {"lookup", lupb_symtab_lookup}, + {"load_descriptor", lupb_symtab_load_descriptor}, + {NULL, NULL} +}; + +static const struct luaL_Reg lupb_symtab_mm[] = { + {"__gc", lupb_symtab_gc}, + {NULL, NULL} +}; + + +/* lupb toplevel **************************************************************/ + +static int lupb_def_freeze(lua_State *L) { + int n = lua_gettop(L); + upb_def **defs = malloc(n * sizeof(upb_def*)); + for (int i = 0; i < n; i++) { + // Could allow an array of defs here also. + defs[i] = lupb_def_checkmutable(L, i + 1); + } + upb_status s = UPB_STATUS_INIT; + upb_def_freeze(defs, n, &s); + free(defs); + lupb_checkstatus(L, &s); + return 0; +} + +static const struct luaL_Reg lupb_toplevel_m[] = { + {"EnumDef", lupb_enumdef_new}, + {"FieldDef", lupb_fielddef_new}, + {"MessageDef", lupb_msgdef_new}, + {"SymbolTable", lupb_symtab_new}, + {"freeze", lupb_def_freeze}, + + {NULL, NULL} +}; + +// Register the given type with the given methods and metamethods. +static void lupb_register_type(lua_State *L, const char *name, + const luaL_Reg *m, const luaL_Reg *mm) { + luaL_newmetatable(L, name); + lupb_setfuncs(L, mm); // Register all mm in the metatable. + lua_createtable(L, 0, 0); + // Methods go in the mt's __index method. This implies that you can't + // implement __index. + lupb_setfuncs(L, m); + lua_setfield(L, -2, "__index"); + lua_pop(L, 1); // The mt. +} + +static void lupb_setfieldi(lua_State *L, const char *field, int i) { + lua_pushnumber(L, i); + lua_setfield(L, -2, field); +} + +int luaopen_upb(lua_State *L) { + lupb_register_type(L, LUPB_MSGDEF, lupb_msgdef_m, lupb_msgdef_mm); + lupb_register_type(L, LUPB_ENUMDEF, lupb_enumdef_m, lupb_enumdef_mm); + lupb_register_type(L, LUPB_FIELDDEF, lupb_fielddef_m, lupb_fielddef_mm); + lupb_register_type(L, LUPB_SYMTAB, lupb_symtab_m, lupb_symtab_mm); + + // Create our object cache. + lua_newtable(L); + lua_createtable(L, 0, 1); // Cache metatable. + lua_pushstring(L, "v"); // Values are weak. + lua_setfield(L, -2, "__mode"); + lua_setmetatable(L, -2); + lua_setfield(L, LUA_REGISTRYINDEX, LUPB_OBJCACHE); + + lupb_newlib(L, "upb", lupb_toplevel_m); + + // Define a couple functions as Lua source (kept here instead of a separate + // Lua file so that upb.so is self-contained) + const char *lua_source = + "return function(upb)\n" + " upb.build_defs = function(defs)\n" + " local symtab = upb.SymbolTable(defs)\n" + " return symtab:getdefs(upb.DEF_ANY)\n" + " end\n" + "end"; + + if (luaL_dostring(L, lua_source) != 0) + lua_error(L); + + // Call the chunk that will define the extra functions on upb, passing our + // package dictionary as the argument. + lua_pushvalue(L, -2); + lua_call(L, 1, 0); + + // Register constants. + lupb_setfieldi(L, "LABEL_OPTIONAL", UPB_LABEL_OPTIONAL); + lupb_setfieldi(L, "LABEL_REQUIRED", UPB_LABEL_REQUIRED); + lupb_setfieldi(L, "LABEL_REPEATED", UPB_LABEL_REPEATED); + + lupb_setfieldi(L, "TYPE_DOUBLE", UPB_TYPE_DOUBLE); + lupb_setfieldi(L, "TYPE_FLOAT", UPB_TYPE_FLOAT); + lupb_setfieldi(L, "TYPE_INT64", UPB_TYPE_INT64); + lupb_setfieldi(L, "TYPE_UINT64", UPB_TYPE_UINT64); + lupb_setfieldi(L, "TYPE_INT32", UPB_TYPE_INT32); + lupb_setfieldi(L, "TYPE_BOOL", UPB_TYPE_BOOL); + lupb_setfieldi(L, "TYPE_STRING", UPB_TYPE_STRING); + lupb_setfieldi(L, "TYPE_MESSAGE", UPB_TYPE_MESSAGE); + lupb_setfieldi(L, "TYPE_BYTES", UPB_TYPE_BYTES); + lupb_setfieldi(L, "TYPE_UINT32", UPB_TYPE_UINT32); + lupb_setfieldi(L, "TYPE_ENUM", UPB_TYPE_ENUM); + + lupb_setfieldi(L, "INTFMT_VARIABLE", UPB_INTFMT_VARIABLE); + lupb_setfieldi(L, "INTFMT_FIXED", UPB_INTFMT_FIXED); + lupb_setfieldi(L, "INTFMT_ZIGZAG", UPB_INTFMT_ZIGZAG); + + lupb_setfieldi(L, "DESCRIPTOR_TYPE_DOUBLE", UPB_DESCRIPTOR_TYPE_DOUBLE); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_FLOAT", UPB_DESCRIPTOR_TYPE_FLOAT); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_INT64", UPB_DESCRIPTOR_TYPE_INT64); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_UINT64", UPB_DESCRIPTOR_TYPE_UINT64); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_INT32", UPB_DESCRIPTOR_TYPE_INT32); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_FIXED64", UPB_DESCRIPTOR_TYPE_FIXED64); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_FIXED32", UPB_DESCRIPTOR_TYPE_FIXED32); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_BOOL", UPB_DESCRIPTOR_TYPE_BOOL); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_STRING", UPB_DESCRIPTOR_TYPE_STRING); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_GROUP", UPB_DESCRIPTOR_TYPE_GROUP); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_MESSAGE", UPB_DESCRIPTOR_TYPE_MESSAGE); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_BYTES", UPB_DESCRIPTOR_TYPE_BYTES); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_UINT32", UPB_DESCRIPTOR_TYPE_UINT32); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_ENUM", UPB_DESCRIPTOR_TYPE_ENUM); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_SFIXED32", UPB_DESCRIPTOR_TYPE_SFIXED32); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_SFIXED64", UPB_DESCRIPTOR_TYPE_SFIXED64); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_SINT32", UPB_DESCRIPTOR_TYPE_SINT32); + lupb_setfieldi(L, "DESCRIPTOR_TYPE_SINT64", UPB_DESCRIPTOR_TYPE_SINT64); + + lupb_setfieldi(L, "DEF_MSG", UPB_DEF_MSG); + lupb_setfieldi(L, "DEF_FIELD", UPB_DEF_FIELD); + lupb_setfieldi(L, "DEF_ENUM", UPB_DEF_ENUM); + lupb_setfieldi(L, "DEF_SERVICE", UPB_DEF_SERVICE); + lupb_setfieldi(L, "DEF_ANY", UPB_DEF_ANY); + + lupb_setfieldi(L, "HANDLER_INT32", UPB_HANDLER_INT32); + lupb_setfieldi(L, "HANDLER_INT64", UPB_HANDLER_INT64); + lupb_setfieldi(L, "HANDLER_UINT32", UPB_HANDLER_UINT32); + lupb_setfieldi(L, "HANDLER_UINT64", UPB_HANDLER_UINT64); + lupb_setfieldi(L, "HANDLER_FLOAT", UPB_HANDLER_FLOAT); + lupb_setfieldi(L, "HANDLER_DOUBLE", UPB_HANDLER_DOUBLE); + lupb_setfieldi(L, "HANDLER_BOOL", UPB_HANDLER_BOOL); + lupb_setfieldi(L, "HANDLER_STARTSTR", UPB_HANDLER_STARTSTR); + lupb_setfieldi(L, "HANDLER_STRING", UPB_HANDLER_STRING); + lupb_setfieldi(L, "HANDLER_ENDSTR", UPB_HANDLER_ENDSTR); + lupb_setfieldi(L, "HANDLER_STARTSUBMSG", UPB_HANDLER_STARTSUBMSG); + lupb_setfieldi(L, "HANDLER_ENDSUBMSG", UPB_HANDLER_ENDSUBMSG); + lupb_setfieldi(L, "HANDLER_STARTSEQ", UPB_HANDLER_STARTSEQ); + lupb_setfieldi(L, "HANDLER_ENDSEQ", UPB_HANDLER_ENDSEQ); + + return 1; // Return package table. +} + +// Alternate names so that the library can be loaded as upb5_1 etc. +int LUPB_OPENFUNC(upb)(lua_State *L) { return luaopen_upb(L); } -- cgit v1.2.3