Built motion from commit 6a09e18b.|2.6.11
[motion2.git] / legacy-libs / grpc / deps / grpc / third_party / upb / upb / bindings / lua / upb.c
1 /*
2 ** require("lua") -- A Lua extension for upb.
3 **
4 ** Exposes only the core library
5 ** (sub-libraries are exposed in other extensions).
6 **
7 ** 64-bit woes: Lua can only represent numbers of type lua_Number (which is
8 ** double unless the user specifically overrides this).  Doubles can represent
9 ** the entire range of 64-bit integers, but lose precision once the integers are
10 ** greater than 2^53.
11 **
12 ** Lua 5.3 is adding support for integers, which will allow for 64-bit
13 ** integers (which can be interpreted as signed or unsigned).
14 **
15 ** LuaJIT supports 64-bit signed and unsigned boxed representations
16 ** through its "cdata" mechanism, but this is not portable to regular Lua.
17 **
18 ** Hopefully Lua 5.3 will come soon enough that we can either use Lua 5.3
19 ** integer support or LuaJIT 64-bit cdata for users that need the entire
20 ** domain of [u]int64 values.
21 */
22
23 #include <float.h>
24 #include <math.h>
25 #include <stdlib.h>
26 #include <string.h>
27 #include "lauxlib.h"
28 #include "upb/bindings/lua/upb.h"
29 #include "upb/handlers.h"
30 #include "upb/msg.h"
31
32
33 /* Lua compatibility code *****************************************************/
34
35 /* Lua 5.1 and Lua 5.2 have slightly incompatible APIs.  A little bit of
36  * compatibility code can help hide the difference.  Not too many people still
37  * use Lua 5.1 but LuaJIT uses the Lua 5.1 API in some ways. */
38
39 #if LUA_VERSION_NUM == 501
40
41 /* taken from lua 5.2's source. */
42 void *luaL_testudata(lua_State *L, int ud, const char *tname) {
43   void *p = lua_touserdata(L, ud);
44   if (p != NULL) {  /* value is a userdata? */
45     if (lua_getmetatable(L, ud)) {  /* does it have a metatable? */
46       luaL_getmetatable(L, tname);  /* get correct metatable */
47       if (!lua_rawequal(L, -1, -2))  /* not the same? */
48         p = NULL;  /* value is a userdata with wrong metatable */
49       lua_pop(L, 2);  /* remove both metatables */
50       return p;
51     }
52   }
53   return NULL;  /* value is not a userdata with a metatable */
54 }
55
56 static void lupb_newlib(lua_State *L, const char *name, const luaL_Reg *funcs) {
57   luaL_register(L, name, funcs);
58 }
59
60 #elif LUA_VERSION_NUM == 502
61
62 int luaL_typerror(lua_State *L, int narg, const char *tname) {
63   const char *msg = lua_pushfstring(L, "%s expected, got %s",
64                                     tname, luaL_typename(L, narg));
65   return luaL_argerror(L, narg, msg);
66 }
67
68 static void lupb_newlib(lua_State *L, const char *name, const luaL_Reg *funcs) {
69   /* Lua 5.2 modules are not expected to set a global variable, so "name" is
70    * unused. */
71   UPB_UNUSED(name);
72
73   /* Can't use luaL_newlib(), because funcs is not the actual array.
74    * Could (micro-)optimize this a bit to count funcs for initial table size. */
75   lua_createtable(L, 0, 8);
76   luaL_setfuncs(L, funcs, 0);
77 }
78
79 #else
80 #error Only Lua 5.1 and 5.2 are supported
81 #endif
82
83 /* Shims for upcoming Lua 5.3 functionality. */
84 bool lua_isinteger(lua_State *L, int argn) {
85   UPB_UNUSED(L);
86   UPB_UNUSED(argn);
87   return false;
88 }
89
90
91 /* Utility functions **********************************************************/
92
93 /* We store our module table in the registry, keyed by ptr.
94  * For more info about the motivation/rationale, see this thread:
95  *   http://thread.gmane.org/gmane.comp.lang.lua.general/110632 */
96 bool lupb_openlib(lua_State *L, void *ptr, const char *name,
97                   const luaL_Reg *funcs) {
98   /* Lookup cached module table. */
99   lua_pushlightuserdata(L, ptr);
100   lua_rawget(L, LUA_REGISTRYINDEX);
101   if (!lua_isnil(L, -1)) {
102     return true;
103   }
104
105   lupb_newlib(L, name, funcs);
106
107   /* Save module table in cache. */
108   lua_pushlightuserdata(L, ptr);
109   lua_pushvalue(L, -2);
110   lua_rawset(L, LUA_REGISTRYINDEX);
111
112   return false;
113 }
114
115 void lupb_checkstatus(lua_State *L, upb_status *s) {
116   if (!upb_ok(s)) {
117     lua_pushstring(L, upb_status_errmsg(s));
118     lua_error(L);
119   }
120 }
121
122 /* Scalar type mapping ********************************************************/
123
124 /* Functions that convert scalar/primitive values (numbers, strings, bool)
125  * between Lua and C/upb.  Handles type/range checking. */
126
127 bool lupb_checkbool(lua_State *L, int narg) {
128   if (!lua_isboolean(L, narg)) {
129     luaL_error(L, "must be true or false");
130   }
131   return lua_toboolean(L, narg);
132 }
133
134 /* Unlike luaL_checkstring(), this does not allow implicit conversion to
135  * string. */
136 const char *lupb_checkstring(lua_State *L, int narg, size_t *len) {
137   if (lua_type(L, narg) != LUA_TSTRING) {
138     luaL_error(L, "Expected string");
139   }
140
141   return lua_tolstring(L, narg, len);
142 }
143
144 /* Unlike luaL_checkinteger, these do not implicitly convert from string or
145  * round an existing double value.  We allow floating-point input, but only if
146  * the actual value is integral. */
147 #define INTCHECK(type, ctype)                                                  \
148   ctype lupb_check##type(lua_State *L, int narg) {                             \
149     double n;                                                                  \
150     ctype i;                                                                   \
151     if (lua_isinteger(L, narg)) {                                              \
152       return lua_tointeger(L, narg);                                           \
153     }                                                                          \
154                                                                                \
155     /* Prevent implicit conversion from string. */                             \
156     luaL_checktype(L, narg, LUA_TNUMBER);                                      \
157     n = lua_tonumber(L, narg);                                                 \
158                                                                                \
159     i = (ctype)n;                                                              \
160     if ((double)i != n) {                                                      \
161       /* double -> ctype truncated or rounded. */                              \
162       luaL_error(L, "number %f was not an integer or out of range for " #type, \
163                  n);                                                           \
164     }                                                                          \
165     return i;                                                                  \
166   }                                                                            \
167   void lupb_push##type(lua_State *L, ctype val) {                              \
168     /* TODO: push integer for Lua >= 5.3, 64-bit cdata for LuaJIT. */          \
169     /* This is lossy for some [u]int64 values, which isn't great, but */       \
170     /* crashing when we encounter these values seems worse. */                 \
171     lua_pushnumber(L, val);                                                    \
172   }
173
174 INTCHECK(int64,  int64_t)
175 INTCHECK(int32,  int32_t)
176 INTCHECK(uint64, uint64_t)
177 INTCHECK(uint32, uint32_t)
178
179 double lupb_checkdouble(lua_State *L, int narg) {
180   /* If we were being really hard-nosed here, we'd check whether the input was
181    * an integer that has no precise double representation.  But doubles aren't
182    * generally expected to be exact like integers are, and worse this could
183    * cause data-dependent runtime errors: one run of the program could work fine
184    * because the integer calculations happened to be exactly representable in
185    * double, while the next could crash because of subtly different input. */
186
187   luaL_checktype(L, narg, LUA_TNUMBER);  /* lua_tonumber() auto-converts. */
188   return lua_tonumber(L, narg);
189 }
190
191 float lupb_checkfloat(lua_State *L, int narg) {
192   /* We don't worry about checking whether the input can be exactly converted to
193    * float -- see above. */
194
195   luaL_checktype(L, narg, LUA_TNUMBER);  /* lua_tonumber() auto-converts. */
196   return lua_tonumber(L, narg);
197 }
198
199 void lupb_pushdouble(lua_State *L, double d) {
200   lua_pushnumber(L, d);
201 }
202
203 void lupb_pushfloat(lua_State *L, float d) {
204   lua_pushnumber(L, d);
205 }
206
207
208 static const struct luaL_Reg lupb_toplevel_m[] = {
209   {NULL, NULL}
210 };
211
212 void lupb_register_type(lua_State *L, const char *name, const luaL_Reg *m,
213                         const luaL_Reg *mm) {
214   luaL_newmetatable(L, name);
215
216   if (mm) {
217     lupb_setfuncs(L, mm);
218   }
219
220   if (m) {
221     /* Methods go in the mt's __index method.  This implies that you can'
222      * implement __index and also have methods. */
223     lua_getfield(L, -1, "__index");
224     lupb_assert(L, lua_isnil(L, -1));
225     lua_pop(L, 1);
226
227     lua_createtable(L, 0, 0);
228     lupb_setfuncs(L, m);
229     lua_setfield(L, -2, "__index");
230   }
231
232   lua_pop(L, 1);  /* The mt. */
233 }
234
235 int luaopen_upb_c(lua_State *L) {
236   static char module_key;
237   if (lupb_openlib(L, &module_key, "upb_c", lupb_toplevel_m)) {
238     return 1;
239   }
240
241   lupb_def_registertypes(L);
242   lupb_msg_registertypes(L);
243
244   return 1;  /* Return package table. */
245 }