Protocol Buffers - Google's data interchange format (grpc依赖)
https://developers.google.com/protocol-buffers/
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
245 lines
8.5 KiB
245 lines
8.5 KiB
/* |
|
** require("lua") -- A Lua extension for upb. |
|
** |
|
** Exposes only the core library |
|
** (sub-libraries are exposed in other extensions). |
|
** |
|
** 64-bit woes: Lua can only represent numbers of type lua_Number (which is |
|
** double unless the user specifically overrides this). Doubles can represent |
|
** the entire range of 64-bit integers, but lose precision once the integers are |
|
** greater than 2^53. |
|
** |
|
** Lua 5.3 is adding support for integers, which will allow for 64-bit |
|
** integers (which can be interpreted as signed or unsigned). |
|
** |
|
** LuaJIT supports 64-bit signed and unsigned boxed representations |
|
** through its "cdata" mechanism, but this is not portable to regular Lua. |
|
** |
|
** Hopefully Lua 5.3 will come soon enough that we can either use Lua 5.3 |
|
** integer support or LuaJIT 64-bit cdata for users that need the entire |
|
** domain of [u]int64 values. |
|
*/ |
|
|
|
#include <float.h> |
|
#include <math.h> |
|
#include <stdlib.h> |
|
#include <string.h> |
|
#include "lauxlib.h" |
|
#include "upb/bindings/lua/upb.h" |
|
#include "upb/handlers.h" |
|
#include "upb/msg.h" |
|
|
|
|
|
/* Lua compatibility code *****************************************************/ |
|
|
|
/* Lua 5.1 and Lua 5.2 have slightly incompatible APIs. A little bit of |
|
* compatibility code can help hide the difference. Not too many people still |
|
* use Lua 5.1 but LuaJIT uses the Lua 5.1 API in some ways. */ |
|
|
|
#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 */ |
|
} |
|
|
|
static void lupb_newlib(lua_State *L, const char *name, const luaL_Reg *funcs) { |
|
luaL_register(L, name, funcs); |
|
} |
|
|
|
#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); |
|
} |
|
|
|
static void lupb_newlib(lua_State *L, const char *name, const luaL_Reg *funcs) { |
|
/* Lua 5.2 modules are not expected to set a global variable, so "name" is |
|
* unused. */ |
|
UPB_UNUSED(name); |
|
|
|
/* Can't use luaL_newlib(), because funcs is not the actual array. |
|
* Could (micro-)optimize this a bit to count funcs for initial table size. */ |
|
lua_createtable(L, 0, 8); |
|
luaL_setfuncs(L, funcs, 0); |
|
} |
|
|
|
#else |
|
#error Only Lua 5.1 and 5.2 are supported |
|
#endif |
|
|
|
/* Shims for upcoming Lua 5.3 functionality. */ |
|
bool lua_isinteger(lua_State *L, int argn) { |
|
UPB_UNUSED(L); |
|
UPB_UNUSED(argn); |
|
return false; |
|
} |
|
|
|
|
|
/* Utility functions **********************************************************/ |
|
|
|
/* We store our module table in the registry, keyed by ptr. |
|
* For more info about the motivation/rationale, see this thread: |
|
* http://thread.gmane.org/gmane.comp.lang.lua.general/110632 */ |
|
bool lupb_openlib(lua_State *L, void *ptr, const char *name, |
|
const luaL_Reg *funcs) { |
|
/* Lookup cached module table. */ |
|
lua_pushlightuserdata(L, ptr); |
|
lua_rawget(L, LUA_REGISTRYINDEX); |
|
if (!lua_isnil(L, -1)) { |
|
return true; |
|
} |
|
|
|
lupb_newlib(L, name, funcs); |
|
|
|
/* Save module table in cache. */ |
|
lua_pushlightuserdata(L, ptr); |
|
lua_pushvalue(L, -2); |
|
lua_rawset(L, LUA_REGISTRYINDEX); |
|
|
|
return false; |
|
} |
|
|
|
void lupb_checkstatus(lua_State *L, upb_status *s) { |
|
if (!upb_ok(s)) { |
|
lua_pushstring(L, upb_status_errmsg(s)); |
|
lua_error(L); |
|
} |
|
} |
|
|
|
/* Scalar type mapping ********************************************************/ |
|
|
|
/* Functions that convert scalar/primitive values (numbers, strings, bool) |
|
* between Lua and C/upb. Handles type/range checking. */ |
|
|
|
bool lupb_checkbool(lua_State *L, int narg) { |
|
if (!lua_isboolean(L, narg)) { |
|
luaL_error(L, "must be true or false"); |
|
} |
|
return lua_toboolean(L, narg); |
|
} |
|
|
|
/* Unlike luaL_checkstring(), this does not allow implicit conversion to |
|
* string. */ |
|
const char *lupb_checkstring(lua_State *L, int narg, size_t *len) { |
|
if (lua_type(L, narg) != LUA_TSTRING) { |
|
luaL_error(L, "Expected string"); |
|
} |
|
|
|
return lua_tolstring(L, narg, len); |
|
} |
|
|
|
/* Unlike luaL_checkinteger, these do not implicitly convert from string or |
|
* round an existing double value. We allow floating-point input, but only if |
|
* the actual value is integral. */ |
|
#define INTCHECK(type, ctype) \ |
|
ctype lupb_check##type(lua_State *L, int narg) { \ |
|
double n; \ |
|
ctype i; \ |
|
if (lua_isinteger(L, narg)) { \ |
|
return lua_tointeger(L, narg); \ |
|
} \ |
|
\ |
|
/* Prevent implicit conversion from string. */ \ |
|
luaL_checktype(L, narg, LUA_TNUMBER); \ |
|
n = lua_tonumber(L, narg); \ |
|
\ |
|
i = (ctype)n; \ |
|
if ((double)i != n) { \ |
|
/* double -> ctype truncated or rounded. */ \ |
|
luaL_error(L, "number %f was not an integer or out of range for " #type, \ |
|
n); \ |
|
} \ |
|
return i; \ |
|
} \ |
|
void lupb_push##type(lua_State *L, ctype val) { \ |
|
/* TODO: push integer for Lua >= 5.3, 64-bit cdata for LuaJIT. */ \ |
|
/* This is lossy for some [u]int64 values, which isn't great, but */ \ |
|
/* crashing when we encounter these values seems worse. */ \ |
|
lua_pushnumber(L, val); \ |
|
} |
|
|
|
INTCHECK(int64, int64_t) |
|
INTCHECK(int32, int32_t) |
|
INTCHECK(uint64, uint64_t) |
|
INTCHECK(uint32, uint32_t) |
|
|
|
double lupb_checkdouble(lua_State *L, int narg) { |
|
/* If we were being really hard-nosed here, we'd check whether the input was |
|
* an integer that has no precise double representation. But doubles aren't |
|
* generally expected to be exact like integers are, and worse this could |
|
* cause data-dependent runtime errors: one run of the program could work fine |
|
* because the integer calculations happened to be exactly representable in |
|
* double, while the next could crash because of subtly different input. */ |
|
|
|
luaL_checktype(L, narg, LUA_TNUMBER); /* lua_tonumber() auto-converts. */ |
|
return lua_tonumber(L, narg); |
|
} |
|
|
|
float lupb_checkfloat(lua_State *L, int narg) { |
|
/* We don't worry about checking whether the input can be exactly converted to |
|
* float -- see above. */ |
|
|
|
luaL_checktype(L, narg, LUA_TNUMBER); /* lua_tonumber() auto-converts. */ |
|
return lua_tonumber(L, narg); |
|
} |
|
|
|
void lupb_pushdouble(lua_State *L, double d) { |
|
lua_pushnumber(L, d); |
|
} |
|
|
|
void lupb_pushfloat(lua_State *L, float d) { |
|
lua_pushnumber(L, d); |
|
} |
|
|
|
|
|
static const struct luaL_Reg lupb_toplevel_m[] = { |
|
{NULL, NULL} |
|
}; |
|
|
|
void lupb_register_type(lua_State *L, const char *name, const luaL_Reg *m, |
|
const luaL_Reg *mm) { |
|
luaL_newmetatable(L, name); |
|
|
|
if (mm) { |
|
lupb_setfuncs(L, mm); |
|
} |
|
|
|
if (m) { |
|
/* Methods go in the mt's __index method. This implies that you can' |
|
* implement __index and also have methods. */ |
|
lua_getfield(L, -1, "__index"); |
|
lupb_assert(L, lua_isnil(L, -1)); |
|
lua_pop(L, 1); |
|
|
|
lua_createtable(L, 0, 0); |
|
lupb_setfuncs(L, m); |
|
lua_setfield(L, -2, "__index"); |
|
} |
|
|
|
lua_pop(L, 1); /* The mt. */ |
|
} |
|
|
|
int luaopen_upb_c(lua_State *L) { |
|
static char module_key; |
|
if (lupb_openlib(L, &module_key, "upb_c", lupb_toplevel_m)) { |
|
return 1; |
|
} |
|
|
|
lupb_def_registertypes(L); |
|
lupb_msg_registertypes(L); |
|
|
|
return 1; /* Return package table. */ |
|
}
|
|
|