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