• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2 ** lupb_msg -- Message/Array/Map objects in Lua/C that wrap upb/msg.h
3 */
4 
5 #include "upb/msg.h"
6 
7 #include <float.h>
8 #include <math.h>
9 #include <stddef.h>
10 #include <stdlib.h>
11 #include <string.h>
12 
13 #include "lauxlib.h"
14 #include "upb/bindings/lua/upb.h"
15 #include "upb/reflection.h"
16 #include "upb/text_encode.h"
17 
18 #include "upb/port_def.inc"
19 
20 /*
21  * Message/Map/Array objects.  These objects form a directed graph: a message
22  * can contain submessages, arrays, and maps, which can then point to other
23  * messages.  This graph can technically be cyclic, though this is an error and
24  * a cyclic graph cannot be serialized.  So it's better to think of this as a
25  * tree of objects.
26  *
27  * The actual data exists at the upb level (upb_msg, upb_map, upb_array),
28  * independently of Lua.  The upb objects contain all the canonical data and
29  * edges between objects.  Lua wrapper objects expose the upb objects to Lua,
30  * but ultimately they are just wrappers.  They pass through all reads and
31  * writes to the underlying upb objects.
32  *
33  * Each upb object lives in a upb arena.  We have a Lua object to wrap the upb
34  * arena, but arenas are never exposed to the user.  The Lua arena object just
35  * serves to own the upb arena and free it at the proper time, once the Lua GC
36  * has determined that there are no more references to anything that lives in
37  * that arena.  All wrapper objects strongly reference the arena to which they
38  * belong.
39  *
40  * A global object cache stores a mapping of C pointer (upb_msg*, upb_array*,
41  * upb_map*) to a corresponding Lua wrapper.  These references are weak so that
42  * the wrappers can be collected if they are no longer needed.  A new wrapper
43  * object can always be recreated later.
44  *
45  *                          +-----+
46  *            lupb_arena    |cache|-weak-+
47  *                 |  ^     +-----+      |
48  *                 |  |                  V
49  * Lua level       |  +------------lupb_msg
50  * ----------------|-----------------|------------------------------------------
51  * upb level       |                 |
52  *                 |            +----V------------------------------+
53  *                 +->upb_arena | upb_msg  ...(empty arena storage) |
54  *                              +-----------------------------------+
55  *
56  * If the user creates a reference between two objects that have different
57  * arenas, we need to fuse the two arenas together, so that the blocks will
58  * outlive both arenas.
59  *
60  *                 +-------------------------->(fused)<----------------+
61  *                 |                                                   |
62  *                 V                           +-----+                 V
63  *            lupb_arena                +-weak-|cache|-weak-+     lupb_arena
64  *                 |  ^                 |      +-----+      |        ^   |
65  *                 |  |                 V                   V        |   |
66  * Lua level       |  +------------lupb_msg              lupb_msg----+   |
67  * ----------------|-----------------|-------------------------|---------|------
68  * upb level       |                 |                         |         |
69  *                 |            +----V----+               +----V----+    V
70  *                 +->upb_arena | upb_msg |               | upb_msg | upb_arena
71  *                              +------|--+               +--^------+
72  *                                     +---------------------+
73  * Key invariants:
74  *   1. every wrapper references the arena that contains it.
75  *   2. every fused arena includes all arenas that own upb objects reachable
76  *      from that arena.  In other words, when a wrapper references an arena,
77  *      this is sufficient to ensure that any upb object reachable from that
78  *      wrapper will stay alive.
79  *
80  * Additionally, every message object contains a strong reference to the
81  * corresponding Descriptor object.  Likewise, array/map objects reference a
82  * Descriptor object if they are typed to store message values.
83  */
84 
85 #define LUPB_ARENA "lupb.arena"
86 #define LUPB_ARRAY "lupb.array"
87 #define LUPB_MAP "lupb.map"
88 #define LUPB_MSG "lupb.msg"
89 
90 #define LUPB_ARENA_INDEX 1
91 #define LUPB_MSGDEF_INDEX 2  /* For msg, and map/array that store msg */
92 
93 static void lupb_msg_newmsgwrapper(lua_State *L, int narg, upb_msgval val);
94 static upb_msg *lupb_msg_check(lua_State *L, int narg);
95 
lupb_checkfieldtype(lua_State * L,int narg)96 static upb_fieldtype_t lupb_checkfieldtype(lua_State *L, int narg) {
97   uint32_t n = lupb_checkuint32(L, narg);
98   bool ok = n >= UPB_TYPE_BOOL && n <= UPB_TYPE_BYTES;
99   luaL_argcheck(L, ok, narg, "invalid field type");
100   return n;
101 }
102 
103 char cache_key;
104 
105 /* lupb_cacheinit()
106  *
107  * Creates the global cache used by lupb_cacheget() and lupb_cacheset().
108  */
lupb_cacheinit(lua_State * L)109 static void lupb_cacheinit(lua_State *L) {
110   /* Create our object cache. */
111   lua_newtable(L);
112 
113   /* Cache metatable gives the cache weak values */
114   lua_createtable(L, 0, 1);
115   lua_pushstring(L, "v");
116   lua_setfield(L, -2, "__mode");
117   lua_setmetatable(L, -2);
118 
119   /* Set cache in the registry. */
120   lua_rawsetp(L, LUA_REGISTRYINDEX, &cache_key);
121 }
122 
123 /* lupb_cacheget()
124  *
125  * Pushes cache[key] and returns true if this key is present in the cache.
126  * Otherwise returns false and leaves nothing on the stack.
127  */
lupb_cacheget(lua_State * L,const void * key)128 static bool lupb_cacheget(lua_State *L, const void *key) {
129   if (key == NULL) {
130     lua_pushnil(L);
131     return true;
132   }
133 
134   lua_rawgetp(L, LUA_REGISTRYINDEX, &cache_key);
135   lua_rawgetp(L, -1, key);
136   if (lua_isnil(L, -1)) {
137     lua_pop(L, 2);  /* Pop table, nil. */
138     return false;
139   } else {
140     lua_replace(L, -2);  /* Replace cache table. */
141     return true;
142   }
143 }
144 
145 /* lupb_cacheset()
146  *
147  * Sets cache[key] = val, where "val" is the value at the top of the stack.
148  * Does not pop the value.
149  */
lupb_cacheset(lua_State * L,const void * key)150 static void lupb_cacheset(lua_State *L, const void *key) {
151   lua_rawgetp(L, LUA_REGISTRYINDEX, &cache_key);
152   lua_pushvalue(L, -2);
153   lua_rawsetp(L, -2, key);
154   lua_pop(L, 1);  /* Pop table. */
155 }
156 
157 /* lupb_arena *****************************************************************/
158 
159 /* lupb_arena only exists to wrap a upb_arena.  It is never exposed to users; it
160  * is an internal memory management detail.  Other wrapper objects refer to this
161  * object from their userdata to keep the arena-owned data alive.
162  */
163 
164 typedef struct {
165   upb_arena *arena;
166 } lupb_arena;
167 
lupb_arena_check(lua_State * L,int narg)168 static upb_arena *lupb_arena_check(lua_State *L, int narg) {
169   lupb_arena *a = luaL_checkudata(L, narg, LUPB_ARENA);
170   return a->arena;
171 }
172 
lupb_arena_pushnew(lua_State * L)173 upb_arena *lupb_arena_pushnew(lua_State *L) {
174   lupb_arena *a = lupb_newuserdata(L, sizeof(lupb_arena), 1, LUPB_ARENA);
175   a->arena = upb_arena_new();
176   return a->arena;
177 }
178 
179 /**
180  * lupb_arena_fuse()
181  *
182  * Merges |from| into |to| so that there is a single arena group that contains
183  * both, and both arenas will point at this new table. */
lupb_arena_fuse(lua_State * L,int to,int from)184 static void lupb_arena_fuse(lua_State *L, int to, int from) {
185   upb_arena *to_arena = lupb_arena_check(L, to);
186   upb_arena *from_arena = lupb_arena_check(L, from);
187   upb_arena_fuse(to_arena, from_arena);
188 }
189 
lupb_arena_gc(lua_State * L)190 static int lupb_arena_gc(lua_State *L) {
191   upb_arena *a = lupb_arena_check(L, 1);
192   upb_arena_free(a);
193   return 0;
194 }
195 
196 static const struct luaL_Reg lupb_arena_mm[] = {
197   {"__gc", lupb_arena_gc},
198   {NULL, NULL}
199 };
200 
201 /* lupb_arenaget()
202  *
203  * Returns the arena from the given message, array, or map object.
204  */
lupb_arenaget(lua_State * L,int narg)205 static upb_arena *lupb_arenaget(lua_State *L, int narg) {
206   upb_arena *arena;
207   lua_getiuservalue(L, narg, LUPB_ARENA_INDEX);
208   arena = lupb_arena_check(L, -1);
209   lua_pop(L, 1);
210   return arena;
211 }
212 
213 /* upb <-> Lua type conversion ************************************************/
214 
215 /* Whether string data should be copied into the containing arena.  We can
216  * avoid a copy if the string data is only needed temporarily (like for a map
217  * lookup).
218  */
219 typedef enum {
220   LUPB_COPY,  /* Copy string data into the arena. */
221   LUPB_REF    /* Reference the Lua copy of the string data. */
222 } lupb_copy_t;
223 
224 /**
225  * lupb_tomsgval()
226  *
227  * Converts the given Lua value |narg| to a upb_msgval.
228  */
lupb_tomsgval(lua_State * L,upb_fieldtype_t type,int narg,int container,lupb_copy_t copy)229 static upb_msgval lupb_tomsgval(lua_State *L, upb_fieldtype_t type, int narg,
230                                 int container, lupb_copy_t copy) {
231   upb_msgval ret;
232   switch (type) {
233     case UPB_TYPE_INT32:
234     case UPB_TYPE_ENUM:
235       ret.int32_val = lupb_checkint32(L, narg);
236       break;
237     case UPB_TYPE_INT64:
238       ret.int64_val = lupb_checkint64(L, narg);
239       break;
240     case UPB_TYPE_UINT32:
241       ret.uint32_val = lupb_checkuint32(L, narg);
242       break;
243     case UPB_TYPE_UINT64:
244       ret.uint64_val = lupb_checkuint64(L, narg);
245       break;
246     case UPB_TYPE_DOUBLE:
247       ret.double_val = lupb_checkdouble(L, narg);
248       break;
249     case UPB_TYPE_FLOAT:
250       ret.float_val = lupb_checkfloat(L, narg);
251       break;
252     case UPB_TYPE_BOOL:
253       ret.bool_val = lupb_checkbool(L, narg);
254       break;
255     case UPB_TYPE_STRING:
256     case UPB_TYPE_BYTES: {
257       size_t len;
258       const char *ptr = lupb_checkstring(L, narg, &len);
259       switch (copy) {
260         case LUPB_COPY: {
261           upb_arena *arena = lupb_arenaget(L, container);
262           char *data = upb_arena_malloc(arena, len);
263           memcpy(data, ptr, len);
264           ret.str_val = upb_strview_make(data, len);
265           break;
266         }
267         case LUPB_REF:
268           ret.str_val = upb_strview_make(ptr, len);
269           break;
270       }
271       break;
272     }
273     case UPB_TYPE_MESSAGE:
274       ret.msg_val = lupb_msg_check(L, narg);
275       /* Typecheck message. */
276       lua_getiuservalue(L, container, LUPB_MSGDEF_INDEX);
277       lua_getiuservalue(L, narg, LUPB_MSGDEF_INDEX);
278       luaL_argcheck(L, lua_rawequal(L, -1, -2), narg, "message type mismatch");
279       lua_pop(L, 2);
280       break;
281   }
282   return ret;
283 }
284 
lupb_pushmsgval(lua_State * L,int container,upb_fieldtype_t type,upb_msgval val)285 static void lupb_pushmsgval(lua_State *L, int container, upb_fieldtype_t type,
286                             upb_msgval val) {
287   switch (type) {
288     case UPB_TYPE_INT32:
289     case UPB_TYPE_ENUM:
290       lupb_pushint32(L, val.int32_val);
291       return;
292     case UPB_TYPE_INT64:
293       lupb_pushint64(L, val.int64_val);
294       return;
295     case UPB_TYPE_UINT32:
296       lupb_pushuint32(L, val.uint32_val);
297       return;
298     case UPB_TYPE_UINT64:
299       lupb_pushuint64(L, val.uint64_val);
300       return;
301     case UPB_TYPE_DOUBLE:
302       lua_pushnumber(L, val.double_val);
303       return;
304     case UPB_TYPE_FLOAT:
305       lua_pushnumber(L, val.float_val);
306       return;
307     case UPB_TYPE_BOOL:
308       lua_pushboolean(L, val.bool_val);
309       return;
310     case UPB_TYPE_STRING:
311     case UPB_TYPE_BYTES:
312       lua_pushlstring(L, val.str_val.data, val.str_val.size);
313       return;
314     case UPB_TYPE_MESSAGE:
315       assert(container);
316       if (!lupb_cacheget(L, val.msg_val)) {
317         lupb_msg_newmsgwrapper(L, container, val);
318       }
319       return;
320   }
321   LUPB_UNREACHABLE();
322 }
323 
324 
325 /* lupb_array *****************************************************************/
326 
327 typedef struct {
328   upb_array *arr;
329   upb_fieldtype_t type;
330 } lupb_array;
331 
lupb_array_check(lua_State * L,int narg)332 static lupb_array *lupb_array_check(lua_State *L, int narg) {
333   return luaL_checkudata(L, narg, LUPB_ARRAY);
334 }
335 
336 /**
337  * lupb_array_checkindex()
338  *
339  * Checks the array index at Lua stack index |narg| to verify that it is an
340  * integer between 1 and |max|, inclusively.  Also corrects it to be zero-based
341  * for C.
342  */
lupb_array_checkindex(lua_State * L,int narg,uint32_t max)343 static int lupb_array_checkindex(lua_State *L, int narg, uint32_t max) {
344   uint32_t n = lupb_checkuint32(L, narg);
345   luaL_argcheck(L, n != 0 && n <= max, narg, "invalid array index");
346   return n - 1;  /* Lua uses 1-based indexing. */
347 }
348 
349 /* lupb_array Public API */
350 
351 /* lupb_array_new():
352  *
353  * Handles:
354  *   Array(upb.TYPE_INT32)
355  *   Array(message_type)
356  */
lupb_array_new(lua_State * L)357 static int lupb_array_new(lua_State *L) {
358   lupb_array *larray;
359   upb_arena *arena;
360 
361   if (lua_type(L, 1) == LUA_TNUMBER) {
362     upb_fieldtype_t type = lupb_checkfieldtype(L, 1);
363     larray = lupb_newuserdata(L, sizeof(*larray), 1, LUPB_ARRAY);
364     larray->type = type;
365   } else {
366     lupb_msgdef_check(L, 1);
367     larray = lupb_newuserdata(L, sizeof(*larray), 2, LUPB_ARRAY);
368     larray->type = UPB_TYPE_MESSAGE;
369     lua_pushvalue(L, 1);
370     lua_setiuservalue(L, -2, LUPB_MSGDEF_INDEX);
371   }
372 
373   arena = lupb_arena_pushnew(L);
374   lua_setiuservalue(L, -2, LUPB_ARENA_INDEX);
375 
376   larray->arr = upb_array_new(arena, larray->type);
377   lupb_cacheset(L, larray->arr);
378 
379   return 1;
380 }
381 
382 /* lupb_array_newindex():
383  *
384  * Handles:
385  *   array[idx] = val
386  *
387  * idx can be within the array or one past the end to extend.
388  */
lupb_array_newindex(lua_State * L)389 static int lupb_array_newindex(lua_State *L) {
390   lupb_array *larray = lupb_array_check(L, 1);
391   size_t size = upb_array_size(larray->arr);
392   uint32_t n = lupb_array_checkindex(L, 2, size + 1);
393   upb_msgval msgval = lupb_tomsgval(L, larray->type, 3, 1, LUPB_COPY);
394 
395   if (n == size) {
396     upb_array_append(larray->arr, msgval, lupb_arenaget(L, 1));
397   } else {
398     upb_array_set(larray->arr, n, msgval);
399   }
400 
401   return 0;  /* 1 for chained assignments? */
402 }
403 
404 /* lupb_array_index():
405  *
406  * Handles:
407  *   array[idx] -> val
408  *
409  * idx must be within the array.
410  */
lupb_array_index(lua_State * L)411 static int lupb_array_index(lua_State *L) {
412   lupb_array *larray = lupb_array_check(L, 1);
413   size_t size = upb_array_size(larray->arr);
414   uint32_t n = lupb_array_checkindex(L, 2, size);
415   upb_msgval val = upb_array_get(larray->arr, n);
416 
417   lupb_pushmsgval(L, 1, larray->type, val);
418 
419   return 1;
420 }
421 
422 /* lupb_array_len():
423  *
424  * Handles:
425  *   #array -> len
426  */
lupb_array_len(lua_State * L)427 static int lupb_array_len(lua_State *L) {
428   lupb_array *larray = lupb_array_check(L, 1);
429   lua_pushnumber(L, upb_array_size(larray->arr));
430   return 1;
431 }
432 
433 static const struct luaL_Reg lupb_array_mm[] = {
434   {"__index", lupb_array_index},
435   {"__len", lupb_array_len},
436   {"__newindex", lupb_array_newindex},
437   {NULL, NULL}
438 };
439 
440 
441 /* lupb_map *******************************************************************/
442 
443 typedef struct {
444   upb_map *map;
445   upb_fieldtype_t key_type;
446   upb_fieldtype_t value_type;
447 } lupb_map;
448 
449 #define MAP_MSGDEF_INDEX 1
450 
lupb_map_check(lua_State * L,int narg)451 static lupb_map *lupb_map_check(lua_State *L, int narg) {
452   return luaL_checkudata(L, narg, LUPB_MAP);
453 }
454 
455 /* lupb_map Public API */
456 
457 /**
458  * lupb_map_new
459  *
460  * Handles:
461  *   new_map = upb.Map(key_type, value_type)
462  *   new_map = upb.Map(key_type, value_msgdef)
463  */
lupb_map_new(lua_State * L)464 static int lupb_map_new(lua_State *L) {
465   upb_arena *arena;
466   lupb_map *lmap;
467 
468   if (lua_type(L, 2) == LUA_TNUMBER) {
469     lmap = lupb_newuserdata(L, sizeof(*lmap), 1, LUPB_MAP);
470     lmap->value_type = lupb_checkfieldtype(L, 2);
471   } else {
472     lupb_msgdef_check(L, 2);
473     lmap = lupb_newuserdata(L, sizeof(*lmap), 2, LUPB_MAP);
474     lmap->value_type = UPB_TYPE_MESSAGE;
475     lua_pushvalue(L, 2);
476     lua_setiuservalue(L, -2, MAP_MSGDEF_INDEX);
477   }
478 
479   arena = lupb_arena_pushnew(L);
480   lua_setiuservalue(L, -2, LUPB_ARENA_INDEX);
481 
482   lmap->key_type = lupb_checkfieldtype(L, 1);
483   lmap->map = upb_map_new(arena, lmap->key_type, lmap->value_type);
484   lupb_cacheset(L, lmap->map);
485 
486   return 1;
487 }
488 
489 /**
490  * lupb_map_index
491  *
492  * Handles:
493  *   map[key]
494  */
lupb_map_index(lua_State * L)495 static int lupb_map_index(lua_State *L) {
496   lupb_map *lmap = lupb_map_check(L, 1);
497   upb_msgval key = lupb_tomsgval(L, lmap->key_type, 2, 1, LUPB_REF);
498   upb_msgval val;
499 
500   if (upb_map_get(lmap->map, key, &val)) {
501     lupb_pushmsgval(L, 1, lmap->value_type, val);
502   } else {
503     lua_pushnil(L);
504   }
505 
506   return 1;
507 }
508 
509 /**
510  * lupb_map_len
511  *
512  * Handles:
513  *   map_len = #map
514  */
lupb_map_len(lua_State * L)515 static int lupb_map_len(lua_State *L) {
516   lupb_map *lmap = lupb_map_check(L, 1);
517   lua_pushnumber(L, upb_map_size(lmap->map));
518   return 1;
519 }
520 
521 /**
522  * lupb_map_newindex
523  *
524  * Handles:
525  *   map[key] = val
526  *   map[key] = nil  # to remove from map
527  */
lupb_map_newindex(lua_State * L)528 static int lupb_map_newindex(lua_State *L) {
529   lupb_map *lmap = lupb_map_check(L, 1);
530   upb_map *map = lmap->map;
531   upb_msgval key = lupb_tomsgval(L, lmap->key_type, 2, 1, LUPB_REF);
532 
533   if (lua_isnil(L, 3)) {
534     upb_map_delete(map, key);
535   } else {
536     upb_msgval val = lupb_tomsgval(L, lmap->value_type, 3, 1, LUPB_COPY);
537     upb_map_set(map, key, val, lupb_arenaget(L, 1));
538   }
539 
540   return 0;
541 }
542 
lupb_mapiter_next(lua_State * L)543 static int lupb_mapiter_next(lua_State *L) {
544   int map = lua_upvalueindex(2);
545   size_t *iter = lua_touserdata(L, lua_upvalueindex(1));
546   lupb_map *lmap = lupb_map_check(L, map);
547 
548   if (upb_mapiter_next(lmap->map, iter)) {
549     upb_msgval key = upb_mapiter_key(lmap->map, *iter);
550     upb_msgval val = upb_mapiter_value(lmap->map, *iter);
551     lupb_pushmsgval(L, map, lmap->key_type, key);
552     lupb_pushmsgval(L, map, lmap->value_type, val);
553     return 2;
554   } else {
555     return 0;
556   }
557 
558 }
559 
560 /**
561  * lupb_map_pairs()
562  *
563  * Handles:
564  *   pairs(map)
565  */
lupb_map_pairs(lua_State * L)566 static int lupb_map_pairs(lua_State *L) {
567   lupb_map_check(L, 1);
568   size_t *iter = lua_newuserdata(L, sizeof(*iter));
569 
570   *iter = UPB_MAP_BEGIN;
571   lua_pushvalue(L, 1);
572 
573   /* Upvalues are [iter, lupb_map]. */
574   lua_pushcclosure(L, &lupb_mapiter_next, 2);
575 
576   return 1;
577 }
578 
579 /* upb_mapiter ]]] */
580 
581 static const struct luaL_Reg lupb_map_mm[] = {
582   {"__index", lupb_map_index},
583   {"__len", lupb_map_len},
584   {"__newindex", lupb_map_newindex},
585   {"__pairs", lupb_map_pairs},
586   {NULL, NULL}
587 };
588 
589 
590 /* lupb_msg *******************************************************************/
591 
592 typedef struct {
593   upb_msg *msg;
594 } lupb_msg;
595 
596 /* lupb_msg helpers */
597 
lupb_msg_check(lua_State * L,int narg)598 static upb_msg *lupb_msg_check(lua_State *L, int narg) {
599   lupb_msg *msg = luaL_checkudata(L, narg, LUPB_MSG);
600   return msg->msg;
601 }
602 
lupb_msg_checkfield(lua_State * L,int msg,int field)603 static const upb_fielddef *lupb_msg_checkfield(lua_State *L, int msg,
604                                                int field) {
605   size_t len;
606   const char *fieldname = luaL_checklstring(L, field, &len);
607   const upb_msgdef *m;
608   const upb_fielddef *f;
609 
610   lua_getiuservalue(L, msg, LUPB_MSGDEF_INDEX);
611   m = lupb_msgdef_check(L, -1);
612   f = upb_msgdef_ntof(m, fieldname, len);
613   if (f == NULL) {
614     luaL_error(L, "no such field '%s'", fieldname);
615   }
616   lua_pop(L, 1);
617 
618   return f;
619 }
620 
621 /**
622  * lupb_msg_newmsgwrapper()
623  *
624  * Creates a new wrapper for a message, copying the arena and msgdef references
625  * from |narg| (which should be an array or map).
626  */
lupb_msg_newmsgwrapper(lua_State * L,int narg,upb_msgval val)627 static void lupb_msg_newmsgwrapper(lua_State *L, int narg, upb_msgval val) {
628   lupb_msg *lmsg = lupb_newuserdata(L, sizeof(*lmsg), 2, LUPB_MSG);
629   lmsg->msg = (upb_msg*)val.msg_val;  /* XXX: cast isn't great. */
630   lupb_cacheset(L, lmsg->msg);
631 
632   /* Copy both arena and msgdef into the wrapper. */
633   lua_getiuservalue(L, narg, LUPB_ARENA_INDEX);
634   lua_setiuservalue(L, -2, LUPB_ARENA_INDEX);
635   lua_getiuservalue(L, narg, LUPB_MSGDEF_INDEX);
636   lua_setiuservalue(L, -2, LUPB_MSGDEF_INDEX);
637 }
638 
639 /**
640  * lupb_msg_newud()
641  *
642  * Creates the Lua userdata for a new wrapper object, adding a reference to
643  * the msgdef if necessary.
644  */
lupb_msg_newud(lua_State * L,int narg,size_t size,const char * type,const upb_fielddef * f)645 static void *lupb_msg_newud(lua_State *L, int narg, size_t size,
646                             const char *type, const upb_fielddef *f) {
647   if (upb_fielddef_type(f) == UPB_TYPE_MESSAGE) {
648     /* Wrapper needs a reference to the msgdef. */
649     void* ud = lupb_newuserdata(L, size, 2, type);
650     lua_getiuservalue(L, narg, LUPB_MSGDEF_INDEX);
651     lupb_msgdef_pushsubmsgdef(L, f);
652     lua_setiuservalue(L, -2, LUPB_MSGDEF_INDEX);
653     return ud;
654   } else {
655     return lupb_newuserdata(L, size, 1, type);
656   }
657 }
658 
659 /**
660  * lupb_msg_newwrapper()
661  *
662  * Creates a new Lua wrapper object to wrap the given array, map, or message.
663  */
lupb_msg_newwrapper(lua_State * L,int narg,const upb_fielddef * f,upb_mutmsgval val)664 static void lupb_msg_newwrapper(lua_State *L, int narg, const upb_fielddef *f,
665                                 upb_mutmsgval val) {
666   if (upb_fielddef_ismap(f)) {
667     const upb_msgdef *entry = upb_fielddef_msgsubdef(f);
668     const upb_fielddef *key_f = upb_msgdef_itof(entry, UPB_MAPENTRY_KEY);
669     const upb_fielddef *val_f = upb_msgdef_itof(entry, UPB_MAPENTRY_VALUE);
670     lupb_map *lmap = lupb_msg_newud(L, narg, sizeof(*lmap), LUPB_MAP, val_f);
671     lmap->key_type = upb_fielddef_type(key_f);
672     lmap->value_type = upb_fielddef_type(val_f);
673     lmap->map = val.map;
674   } else if (upb_fielddef_isseq(f)) {
675     lupb_array *larr = lupb_msg_newud(L, narg, sizeof(*larr), LUPB_ARRAY, f);
676     larr->type = upb_fielddef_type(f);
677     larr->arr = val.array;
678   } else {
679     lupb_msg *lmsg = lupb_msg_newud(L, narg, sizeof(*lmsg), LUPB_MSG, f);
680     lmsg->msg = val.msg;
681   }
682 
683   /* Copy arena ref to new wrapper.  This may be a different arena than the
684    * underlying data was originally constructed from, but if so both arenas
685    * must be in the same group. */
686   lua_getiuservalue(L, narg, LUPB_ARENA_INDEX);
687   lua_setiuservalue(L, -2, LUPB_ARENA_INDEX);
688 
689   lupb_cacheset(L, val.msg);
690 }
691 
692 /**
693  * lupb_msg_typechecksubmsg()
694  *
695  * Typechecks the given array, map, or msg against this upb_fielddef.
696  */
lupb_msg_typechecksubmsg(lua_State * L,int narg,int msgarg,const upb_fielddef * f)697 static void lupb_msg_typechecksubmsg(lua_State *L, int narg, int msgarg,
698                                      const upb_fielddef *f) {
699   /* Typecheck this map's msgdef against this message field. */
700   lua_getiuservalue(L, narg, LUPB_MSGDEF_INDEX);
701   lua_getiuservalue(L, msgarg, LUPB_MSGDEF_INDEX);
702   lupb_msgdef_pushsubmsgdef(L, f);
703   luaL_argcheck(L, lua_rawequal(L, -1, -2), narg, "message type mismatch");
704   lua_pop(L, 2);
705 }
706 
707 /* lupb_msg Public API */
708 
709 /**
710  * lupb_msg_pushnew
711  *
712  * Handles:
713  *   new_msg = MessageClass()
714  *   new_msg = MessageClass{foo = "bar", baz = 3, quux = {foo = 3}}
715  */
lupb_msg_pushnew(lua_State * L)716 int lupb_msg_pushnew(lua_State *L) {
717   int argcount = lua_gettop(L);
718   const upb_msgdef *m = lupb_msgdef_check(L, 1);
719   lupb_msg *lmsg = lupb_newuserdata(L, sizeof(lupb_msg), 2, LUPB_MSG);
720   upb_arena *arena = lupb_arena_pushnew(L);
721 
722   lua_setiuservalue(L, -2, LUPB_ARENA_INDEX);
723   lua_pushvalue(L, 1);
724   lua_setiuservalue(L, -2, LUPB_MSGDEF_INDEX);
725 
726   lmsg->msg = upb_msg_new(m, arena);
727   lupb_cacheset(L, lmsg->msg);
728 
729   if (argcount > 1) {
730     /* Set initial fields from table. */
731     int msg = lua_gettop(L);
732     lua_pushnil(L);
733     while (lua_next(L, 2) != 0) {
734       lua_pushvalue(L, -2);  /* now stack is key, val, key */
735       lua_insert(L, -3);  /* now stack is key, key, val */
736       lua_settable(L, msg);
737     }
738   }
739 
740   return 1;
741 }
742 
743 /**
744  * lupb_msg_index
745  *
746  * Handles:
747  *   msg.foo
748  *   msg["foo"]
749  *   msg[field_descriptor]  # (for extensions) (TODO)
750  */
lupb_msg_index(lua_State * L)751 static int lupb_msg_index(lua_State *L) {
752   upb_msg *msg = lupb_msg_check(L, 1);
753   const upb_fielddef *f = lupb_msg_checkfield(L, 1, 2);
754 
755   if (upb_fielddef_isseq(f) || upb_fielddef_issubmsg(f)) {
756     /* Wrapped type; get or create wrapper. */
757     upb_arena *arena = upb_fielddef_isseq(f) ? lupb_arenaget(L, 1) : NULL;
758     upb_mutmsgval val = upb_msg_mutable(msg, f, arena);
759     if (!lupb_cacheget(L, val.msg)) {
760       lupb_msg_newwrapper(L, 1, f, val);
761     }
762   } else {
763     /* Value type, just push value and return .*/
764     upb_msgval val = upb_msg_get(msg, f);
765     lupb_pushmsgval(L, 0, upb_fielddef_type(f), val);
766   }
767 
768   return 1;
769 }
770 
771 /**
772  * lupb_msg_newindex()
773  *
774  * Handles:
775  *   msg.foo = bar
776  *   msg["foo"] = bar
777  *   msg[field_descriptor] = bar  # (for extensions) (TODO)
778  */
lupb_msg_newindex(lua_State * L)779 static int lupb_msg_newindex(lua_State *L) {
780   upb_msg *msg = lupb_msg_check(L, 1);
781   const upb_fielddef *f = lupb_msg_checkfield(L, 1, 2);
782   upb_msgval msgval;
783   bool merge_arenas = true;
784 
785   if (upb_fielddef_ismap(f)) {
786     lupb_map *lmap = lupb_map_check(L, 3);
787     const upb_msgdef *entry = upb_fielddef_msgsubdef(f);
788     const upb_fielddef *key_f = upb_msgdef_itof(entry, UPB_MAPENTRY_KEY);
789     const upb_fielddef *val_f = upb_msgdef_itof(entry, UPB_MAPENTRY_VALUE);
790     upb_fieldtype_t key_type = upb_fielddef_type(key_f);
791     upb_fieldtype_t value_type = upb_fielddef_type(val_f);
792     luaL_argcheck(L, lmap->key_type == key_type, 3, "key type mismatch");
793     luaL_argcheck(L, lmap->value_type == value_type, 3, "value type mismatch");
794     if (value_type == UPB_TYPE_MESSAGE) {
795       lupb_msg_typechecksubmsg(L, 3, 1, val_f);
796     }
797     msgval.map_val = lmap->map;
798   } else if (upb_fielddef_isseq(f)) {
799     lupb_array *larr = lupb_array_check(L, 3);
800     upb_fieldtype_t type = upb_fielddef_type(f);
801     luaL_argcheck(L, larr->type == type, 3, "array type mismatch");
802     if (type == UPB_TYPE_MESSAGE) {
803       lupb_msg_typechecksubmsg(L, 3, 1, f);
804     }
805     msgval.array_val = larr->arr;
806   } else if (upb_fielddef_issubmsg(f)) {
807     upb_msg *msg = lupb_msg_check(L, 3);
808     lupb_msg_typechecksubmsg(L, 3, 1, f);
809     msgval.msg_val = msg;
810   } else {
811     msgval = lupb_tomsgval(L, upb_fielddef_type(f), 3, 1, LUPB_COPY);
812     merge_arenas = false;
813   }
814 
815   if (merge_arenas) {
816     lua_getiuservalue(L, 1, LUPB_ARENA_INDEX);
817     lua_getiuservalue(L, 3, LUPB_ARENA_INDEX);
818     lupb_arena_fuse(L, lua_absindex(L, -2), lua_absindex(L, -1));
819     lua_pop(L, 2);
820   }
821 
822   upb_msg_set(msg, f, msgval, lupb_arenaget(L, 1));
823 
824   /* Return the new value for chained assignments. */
825   lua_pushvalue(L, 3);
826   return 1;
827 }
828 
829 /**
830  * lupb_msg_tostring()
831  *
832  * Handles:
833  *   tostring(msg)
834  *   print(msg)
835  *   etc.
836  */
lupb_msg_tostring(lua_State * L)837 static int lupb_msg_tostring(lua_State *L) {
838   upb_msg *msg = lupb_msg_check(L, 1);
839   const upb_msgdef *m;
840   char buf[1024];
841   size_t size;
842 
843   lua_getiuservalue(L, 1, LUPB_MSGDEF_INDEX);
844   m = lupb_msgdef_check(L, -1);
845 
846   size = upb_text_encode(msg, m, NULL, 0, buf, sizeof(buf));
847 
848   if (size < sizeof(buf)) {
849     lua_pushlstring(L, buf, size);
850   } else {
851     char *ptr = malloc(size + 1);
852     upb_text_encode(msg, m, NULL, 0, ptr, size + 1);
853     lua_pushlstring(L, ptr, size);
854     free(ptr);
855   }
856 
857   return 1;
858 }
859 
860 static const struct luaL_Reg lupb_msg_mm[] = {
861   {"__index", lupb_msg_index},
862   {"__newindex", lupb_msg_newindex},
863   {"__tostring", lupb_msg_tostring},
864   {NULL, NULL}
865 };
866 
867 
868 /* lupb_msg toplevel **********************************************************/
869 
870 /**
871  * lupb_decode()
872  *
873  * Handles:
874  *   msg = upb.decode(MessageClass, bin_string)
875  */
lupb_decode(lua_State * L)876 static int lupb_decode(lua_State *L) {
877   size_t len;
878   const upb_msgdef *m = lupb_msgdef_check(L, 1);
879   const char *pb = lua_tolstring(L, 2, &len);
880   const upb_msglayout *layout = upb_msgdef_layout(m);
881   char *buf;
882   upb_msg *msg;
883   upb_arena *arena;
884   bool ok;
885 
886   /* Create message. */
887   lua_pushcfunction(L, &lupb_msg_pushnew);
888   lua_pushvalue(L, 1);
889   lua_call(L, 1, 1);
890   msg = lupb_msg_check(L, -1);
891 
892   lua_getiuservalue(L, -1, LUPB_ARENA_INDEX);
893   arena = lupb_arena_check(L, -1);
894   lua_pop(L, 1);
895 
896   /* Copy input data to arena, message will reference it. */
897   buf = upb_arena_malloc(arena, len);
898   memcpy(buf, pb, len);
899 
900   ok = upb_decode(buf, len, msg, layout, arena);
901 
902   if (!ok) {
903     lua_pushstring(L, "Error decoding protobuf.");
904     return lua_error(L);
905   }
906 
907   return 1;
908 }
909 
910 /**
911  * lupb_encode()
912  *
913  * Handles:
914  *   bin_string = upb.encode(msg)
915  */
lupb_encode(lua_State * L)916 static int lupb_encode(lua_State *L) {
917   const upb_msg *msg = lupb_msg_check(L, 1);
918   const upb_msglayout *layout;
919   upb_arena *arena = lupb_arena_pushnew(L);
920   size_t size;
921   char *result;
922 
923   lua_getiuservalue(L, 1, LUPB_MSGDEF_INDEX);
924   layout = upb_msgdef_layout(lupb_msgdef_check(L, -1));
925   lua_pop(L, 1);
926 
927   result = upb_encode(msg, (const void*)layout, arena, &size);
928 
929   if (!result) {
930     lua_pushstring(L, "Error encoding protobuf.");
931     return lua_error(L);
932   }
933 
934   lua_pushlstring(L, result, size);
935 
936   return 1;
937 }
938 
939 static const struct luaL_Reg lupb_msg_toplevel_m[] = {
940   {"Array", lupb_array_new},
941   {"Map", lupb_map_new},
942   {"decode", lupb_decode},
943   {"encode", lupb_encode},
944   {NULL, NULL}
945 };
946 
lupb_msg_registertypes(lua_State * L)947 void lupb_msg_registertypes(lua_State *L) {
948   lupb_setfuncs(L, lupb_msg_toplevel_m);
949 
950   lupb_register_type(L, LUPB_ARENA, NULL, lupb_arena_mm);
951   lupb_register_type(L, LUPB_ARRAY, NULL, lupb_array_mm);
952   lupb_register_type(L, LUPB_MAP,   NULL, lupb_map_mm);
953   lupb_register_type(L, LUPB_MSG,   NULL, lupb_msg_mm);
954 
955   lupb_cacheinit(L);
956 }
957