1 /*
2 * Copyright (c) 2009-2021, Google LLC
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 * * Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * * Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
12 * * Neither the name of Google LLC nor the
13 * names of its contributors may be used to endorse or promote products
14 * derived from this software without specific prior written permission.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
17 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL Google LLC BE LIABLE FOR ANY DIRECT,
20 * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28 /*
29 * lupb_Message -- Message/Array/Map objects in Lua/C that wrap upb/msg.h
30 */
31
32 #include "upb/msg.h"
33
34 #include <float.h>
35 #include <math.h>
36 #include <stddef.h>
37 #include <stdlib.h>
38 #include <string.h>
39
40 #include "lauxlib.h"
41 #include "lua/upb.h"
42 #include "upb/collections/map.h"
43 #include "upb/json/decode.h"
44 #include "upb/json/encode.h"
45 #include "upb/port/def.inc"
46 #include "upb/reflection/message.h"
47 #include "upb/text/encode.h"
48
49 /*
50 * Message/Map/Array objects. These objects form a directed graph: a message
51 * can contain submessages, arrays, and maps, which can then point to other
52 * messages. This graph can technically be cyclic, though this is an error and
53 * a cyclic graph cannot be serialized. So it's better to think of this as a
54 * tree of objects.
55 *
56 * The actual data exists at the upb level (upb_Message, upb_Map, upb_Array),
57 * independently of Lua. The upb objects contain all the canonical data and
58 * edges between objects. Lua wrapper objects expose the upb objects to Lua,
59 * but ultimately they are just wrappers. They pass through all reads and
60 * writes to the underlying upb objects.
61 *
62 * Each upb object lives in a upb arena. We have a Lua object to wrap the upb
63 * arena, but arenas are never exposed to the user. The Lua arena object just
64 * serves to own the upb arena and free it at the proper time, once the Lua GC
65 * has determined that there are no more references to anything that lives in
66 * that arena. All wrapper objects strongly reference the arena to which they
67 * belong.
68 *
69 * A global object cache stores a mapping of C pointer (upb_Message*,
70 * upb_Array*, upb_Map*) to a corresponding Lua wrapper. These references are
71 * weak so that the wrappers can be collected if they are no longer needed. A
72 * new wrapper object can always be recreated later.
73 *
74 * +-----+
75 * lupb_Arena |cache|-weak-+
76 * | ^ +-----+ |
77 * | | V
78 * Lua level | +------------lupb_Message
79 * ----------------|-----------------|------------------------------------------
80 * upb level | |
81 * | +----V----------------------------------+
82 * +->upb_Arena | upb_Message ...(empty arena storage) |
83 * +---------------------------------------+
84 *
85 * If the user creates a reference between two objects that have different
86 * arenas, we need to fuse the two arenas together, so that the blocks will
87 * outlive both arenas.
88 *
89 * +-------------------------->(fused)<----------------+
90 * | |
91 * V +-----+ V
92 * lupb_Arena +-weak-|cache|-weak-+ lupb_Arena
93 * | ^ | +-----+ | ^ |
94 * | | V V | |
95 * Lua level | +------------lupb_Message lupb_Message--+ |
96 * ----------------|-----------------|----------------------|-----------|------
97 * upb level | | | |
98 * | +----V--------+ +----V--------+ V
99 * +->upb_Arena | upb_Message | | upb_Message | upb_Arena
100 * +------|------+ +--^----------+
101 * +------------------+
102 * Key invariants:
103 * 1. every wrapper references the arena that contains it.
104 * 2. every fused arena includes all arenas that own upb objects reachable
105 * from that arena. In other words, when a wrapper references an arena,
106 * this is sufficient to ensure that any upb object reachable from that
107 * wrapper will stay alive.
108 *
109 * Additionally, every message object contains a strong reference to the
110 * corresponding Descriptor object. Likewise, array/map objects reference a
111 * Descriptor object if they are typed to store message values.
112 */
113
114 #define LUPB_ARENA "lupb.arena"
115 #define LUPB_ARRAY "lupb.array"
116 #define LUPB_MAP "lupb.map"
117 #define LUPB_MSG "lupb.msg"
118
119 #define LUPB_ARENA_INDEX 1
120 #define LUPB_MSGDEF_INDEX 2 /* For msg, and map/array that store msg */
121
122 static void lupb_Message_Newmsgwrapper(lua_State* L, int narg,
123 upb_MessageValue val);
124 static upb_Message* lupb_msg_check(lua_State* L, int narg);
125
lupb_checkfieldtype(lua_State * L,int narg)126 static upb_CType lupb_checkfieldtype(lua_State* L, int narg) {
127 uint32_t n = lupb_checkuint32(L, narg);
128 bool ok = n >= kUpb_CType_Bool && n <= kUpb_CType_Bytes;
129 luaL_argcheck(L, ok, narg, "invalid field type");
130 return n;
131 }
132
133 char cache_key;
134
135 /* lupb_cacheinit()
136 *
137 * Creates the global cache used by lupb_cacheget() and lupb_cacheset().
138 */
lupb_cacheinit(lua_State * L)139 static void lupb_cacheinit(lua_State* L) {
140 /* Create our object cache. */
141 lua_newtable(L);
142
143 /* Cache metatable gives the cache weak values */
144 lua_createtable(L, 0, 1);
145 lua_pushstring(L, "v");
146 lua_setfield(L, -2, "__mode");
147 lua_setmetatable(L, -2);
148
149 /* Set cache in the registry. */
150 lua_rawsetp(L, LUA_REGISTRYINDEX, &cache_key);
151 }
152
153 /* lupb_cacheget()
154 *
155 * Pushes cache[key] and returns true if this key is present in the cache.
156 * Otherwise returns false and leaves nothing on the stack.
157 */
lupb_cacheget(lua_State * L,const void * key)158 static bool lupb_cacheget(lua_State* L, const void* key) {
159 if (key == NULL) {
160 lua_pushnil(L);
161 return true;
162 }
163
164 lua_rawgetp(L, LUA_REGISTRYINDEX, &cache_key);
165 lua_rawgetp(L, -1, key);
166 if (lua_isnil(L, -1)) {
167 lua_pop(L, 2); /* Pop table, nil. */
168 return false;
169 } else {
170 lua_replace(L, -2); /* Replace cache table. */
171 return true;
172 }
173 }
174
175 /* lupb_cacheset()
176 *
177 * Sets cache[key] = val, where "val" is the value at the top of the stack.
178 * Does not pop the value.
179 */
lupb_cacheset(lua_State * L,const void * key)180 static void lupb_cacheset(lua_State* L, const void* key) {
181 lua_rawgetp(L, LUA_REGISTRYINDEX, &cache_key);
182 lua_pushvalue(L, -2);
183 lua_rawsetp(L, -2, key);
184 lua_pop(L, 1); /* Pop table. */
185 }
186
187 /* lupb_Arena *****************************************************************/
188
189 /* lupb_Arena only exists to wrap a upb_Arena. It is never exposed to users; it
190 * is an internal memory management detail. Other wrapper objects refer to this
191 * object from their userdata to keep the arena-owned data alive.
192 */
193
194 typedef struct {
195 upb_Arena* arena;
196 } lupb_Arena;
197
lupb_Arena_check(lua_State * L,int narg)198 static upb_Arena* lupb_Arena_check(lua_State* L, int narg) {
199 lupb_Arena* a = luaL_checkudata(L, narg, LUPB_ARENA);
200 return a->arena;
201 }
202
lupb_Arena_pushnew(lua_State * L)203 upb_Arena* lupb_Arena_pushnew(lua_State* L) {
204 lupb_Arena* a = lupb_newuserdata(L, sizeof(lupb_Arena), 1, LUPB_ARENA);
205 a->arena = upb_Arena_New();
206 return a->arena;
207 }
208
209 /**
210 * lupb_Arena_Fuse()
211 *
212 * Merges |from| into |to| so that there is a single arena group that contains
213 * both, and both arenas will point at this new table. */
lupb_Arena_Fuse(lua_State * L,int to,int from)214 static void lupb_Arena_Fuse(lua_State* L, int to, int from) {
215 upb_Arena* to_arena = lupb_Arena_check(L, to);
216 upb_Arena* from_arena = lupb_Arena_check(L, from);
217 upb_Arena_Fuse(to_arena, from_arena);
218 }
219
lupb_Arena_Fuseobjs(lua_State * L,int to,int from)220 static void lupb_Arena_Fuseobjs(lua_State* L, int to, int from) {
221 lua_getiuservalue(L, to, LUPB_ARENA_INDEX);
222 lua_getiuservalue(L, from, LUPB_ARENA_INDEX);
223 lupb_Arena_Fuse(L, lua_absindex(L, -2), lua_absindex(L, -1));
224 lua_pop(L, 2);
225 }
226
lupb_Arena_gc(lua_State * L)227 static int lupb_Arena_gc(lua_State* L) {
228 upb_Arena* a = lupb_Arena_check(L, 1);
229 upb_Arena_Free(a);
230 return 0;
231 }
232
233 static const struct luaL_Reg lupb_Arena_mm[] = {{"__gc", lupb_Arena_gc},
234 {NULL, NULL}};
235
236 /* lupb_Arenaget()
237 *
238 * Returns the arena from the given message, array, or map object.
239 */
lupb_Arenaget(lua_State * L,int narg)240 static upb_Arena* lupb_Arenaget(lua_State* L, int narg) {
241 upb_Arena* arena;
242 lua_getiuservalue(L, narg, LUPB_ARENA_INDEX);
243 arena = lupb_Arena_check(L, -1);
244 lua_pop(L, 1);
245 return arena;
246 }
247
248 /* upb <-> Lua type conversion ************************************************/
249
250 /* Whether string data should be copied into the containing arena. We can
251 * avoid a copy if the string data is only needed temporarily (like for a map
252 * lookup).
253 */
254 typedef enum {
255 LUPB_COPY, /* Copy string data into the arena. */
256 LUPB_REF /* Reference the Lua copy of the string data. */
257 } lupb_copy_t;
258
259 /**
260 * lupb_tomsgval()
261 *
262 * Converts the given Lua value |narg| to a upb_MessageValue.
263 */
lupb_tomsgval(lua_State * L,upb_CType type,int narg,int container,lupb_copy_t copy)264 static upb_MessageValue lupb_tomsgval(lua_State* L, upb_CType type, int narg,
265 int container, lupb_copy_t copy) {
266 upb_MessageValue ret;
267 switch (type) {
268 case kUpb_CType_Int32:
269 case kUpb_CType_Enum:
270 ret.int32_val = lupb_checkint32(L, narg);
271 break;
272 case kUpb_CType_Int64:
273 ret.int64_val = lupb_checkint64(L, narg);
274 break;
275 case kUpb_CType_UInt32:
276 ret.uint32_val = lupb_checkuint32(L, narg);
277 break;
278 case kUpb_CType_UInt64:
279 ret.uint64_val = lupb_checkuint64(L, narg);
280 break;
281 case kUpb_CType_Double:
282 ret.double_val = lupb_checkdouble(L, narg);
283 break;
284 case kUpb_CType_Float:
285 ret.float_val = lupb_checkfloat(L, narg);
286 break;
287 case kUpb_CType_Bool:
288 ret.bool_val = lupb_checkbool(L, narg);
289 break;
290 case kUpb_CType_String:
291 case kUpb_CType_Bytes: {
292 size_t len;
293 const char* ptr = lupb_checkstring(L, narg, &len);
294 switch (copy) {
295 case LUPB_COPY: {
296 upb_Arena* arena = lupb_Arenaget(L, container);
297 char* data = upb_Arena_Malloc(arena, len);
298 memcpy(data, ptr, len);
299 ret.str_val = upb_StringView_FromDataAndSize(data, len);
300 break;
301 }
302 case LUPB_REF:
303 ret.str_val = upb_StringView_FromDataAndSize(ptr, len);
304 break;
305 }
306 break;
307 }
308 case kUpb_CType_Message:
309 ret.msg_val = lupb_msg_check(L, narg);
310 /* Typecheck message. */
311 lua_getiuservalue(L, container, LUPB_MSGDEF_INDEX);
312 lua_getiuservalue(L, narg, LUPB_MSGDEF_INDEX);
313 luaL_argcheck(L, lua_rawequal(L, -1, -2), narg, "message type mismatch");
314 lua_pop(L, 2);
315 break;
316 }
317 return ret;
318 }
319
lupb_pushmsgval(lua_State * L,int container,upb_CType type,upb_MessageValue val)320 void lupb_pushmsgval(lua_State* L, int container, upb_CType type,
321 upb_MessageValue val) {
322 switch (type) {
323 case kUpb_CType_Int32:
324 case kUpb_CType_Enum:
325 lupb_pushint32(L, val.int32_val);
326 return;
327 case kUpb_CType_Int64:
328 lupb_pushint64(L, val.int64_val);
329 return;
330 case kUpb_CType_UInt32:
331 lupb_pushuint32(L, val.uint32_val);
332 return;
333 case kUpb_CType_UInt64:
334 lupb_pushuint64(L, val.uint64_val);
335 return;
336 case kUpb_CType_Double:
337 lua_pushnumber(L, val.double_val);
338 return;
339 case kUpb_CType_Float:
340 lua_pushnumber(L, val.float_val);
341 return;
342 case kUpb_CType_Bool:
343 lua_pushboolean(L, val.bool_val);
344 return;
345 case kUpb_CType_String:
346 case kUpb_CType_Bytes:
347 lua_pushlstring(L, val.str_val.data, val.str_val.size);
348 return;
349 case kUpb_CType_Message:
350 assert(container);
351 if (!lupb_cacheget(L, val.msg_val)) {
352 lupb_Message_Newmsgwrapper(L, container, val);
353 }
354 return;
355 }
356 LUPB_UNREACHABLE();
357 }
358
359 /* lupb_array *****************************************************************/
360
361 typedef struct {
362 upb_Array* arr;
363 upb_CType type;
364 } lupb_array;
365
lupb_array_check(lua_State * L,int narg)366 static lupb_array* lupb_array_check(lua_State* L, int narg) {
367 return luaL_checkudata(L, narg, LUPB_ARRAY);
368 }
369
370 /**
371 * lupb_array_checkindex()
372 *
373 * Checks the array index at Lua stack index |narg| to verify that it is an
374 * integer between 1 and |max|, inclusively. Also corrects it to be zero-based
375 * for C.
376 */
lupb_array_checkindex(lua_State * L,int narg,uint32_t max)377 static int lupb_array_checkindex(lua_State* L, int narg, uint32_t max) {
378 uint32_t n = lupb_checkuint32(L, narg);
379 luaL_argcheck(L, n != 0 && n <= max, narg, "invalid array index");
380 return n - 1; /* Lua uses 1-based indexing. */
381 }
382
383 /* lupb_array Public API */
384
385 /* lupb_Array_New():
386 *
387 * Handles:
388 * Array(upb.TYPE_INT32)
389 * Array(message_type)
390 */
lupb_Array_New(lua_State * L)391 static int lupb_Array_New(lua_State* L) {
392 int arg_count = lua_gettop(L);
393 lupb_array* larray;
394 upb_Arena* arena;
395
396 if (lua_type(L, 1) == LUA_TNUMBER) {
397 upb_CType type = lupb_checkfieldtype(L, 1);
398 larray = lupb_newuserdata(L, sizeof(*larray), 1, LUPB_ARRAY);
399 larray->type = type;
400 } else {
401 lupb_MessageDef_check(L, 1);
402 larray = lupb_newuserdata(L, sizeof(*larray), 2, LUPB_ARRAY);
403 larray->type = kUpb_CType_Message;
404 lua_pushvalue(L, 1);
405 lua_setiuservalue(L, -2, LUPB_MSGDEF_INDEX);
406 }
407
408 arena = lupb_Arena_pushnew(L);
409 lua_setiuservalue(L, -2, LUPB_ARENA_INDEX);
410
411 larray->arr = upb_Array_New(arena, larray->type);
412 lupb_cacheset(L, larray->arr);
413
414 if (arg_count > 1) {
415 /* Set initial fields from table. */
416 int msg = arg_count + 1;
417 lua_pushnil(L);
418 while (lua_next(L, 2) != 0) {
419 lua_pushvalue(L, -2); /* now stack is key, val, key */
420 lua_insert(L, -3); /* now stack is key, key, val */
421 lua_settable(L, msg);
422 }
423 }
424
425 return 1;
426 }
427
428 /* lupb_Array_Newindex():
429 *
430 * Handles:
431 * array[idx] = val
432 *
433 * idx can be within the array or one past the end to extend.
434 */
lupb_Array_Newindex(lua_State * L)435 static int lupb_Array_Newindex(lua_State* L) {
436 lupb_array* larray = lupb_array_check(L, 1);
437 size_t size = upb_Array_Size(larray->arr);
438 uint32_t n = lupb_array_checkindex(L, 2, size + 1);
439 upb_MessageValue msgval = lupb_tomsgval(L, larray->type, 3, 1, LUPB_COPY);
440
441 if (n == size) {
442 upb_Array_Append(larray->arr, msgval, lupb_Arenaget(L, 1));
443 } else {
444 upb_Array_Set(larray->arr, n, msgval);
445 }
446
447 if (larray->type == kUpb_CType_Message) {
448 lupb_Arena_Fuseobjs(L, 1, 3);
449 }
450
451 return 0; /* 1 for chained assignments? */
452 }
453
454 /* lupb_array_index():
455 *
456 * Handles:
457 * array[idx] -> val
458 *
459 * idx must be within the array.
460 */
lupb_array_index(lua_State * L)461 static int lupb_array_index(lua_State* L) {
462 lupb_array* larray = lupb_array_check(L, 1);
463 size_t size = upb_Array_Size(larray->arr);
464 uint32_t n = lupb_array_checkindex(L, 2, size);
465 upb_MessageValue val = upb_Array_Get(larray->arr, n);
466
467 lupb_pushmsgval(L, 1, larray->type, val);
468
469 return 1;
470 }
471
472 /* lupb_array_len():
473 *
474 * Handles:
475 * #array -> len
476 */
lupb_array_len(lua_State * L)477 static int lupb_array_len(lua_State* L) {
478 lupb_array* larray = lupb_array_check(L, 1);
479 lua_pushnumber(L, upb_Array_Size(larray->arr));
480 return 1;
481 }
482
483 static const struct luaL_Reg lupb_array_mm[] = {
484 {"__index", lupb_array_index},
485 {"__len", lupb_array_len},
486 {"__newindex", lupb_Array_Newindex},
487 {NULL, NULL}};
488
489 /* lupb_map *******************************************************************/
490
491 typedef struct {
492 upb_Map* map;
493 upb_CType key_type;
494 upb_CType value_type;
495 } lupb_map;
496
497 #define MAP_MSGDEF_INDEX 1
498
lupb_map_check(lua_State * L,int narg)499 static lupb_map* lupb_map_check(lua_State* L, int narg) {
500 return luaL_checkudata(L, narg, LUPB_MAP);
501 }
502
503 /* lupb_map Public API */
504
505 /**
506 * lupb_Map_New
507 *
508 * Handles:
509 * new_map = upb.Map(key_type, value_type)
510 * new_map = upb.Map(key_type, value_msgdef)
511 */
lupb_Map_New(lua_State * L)512 static int lupb_Map_New(lua_State* L) {
513 upb_Arena* arena;
514 lupb_map* lmap;
515
516 if (lua_type(L, 2) == LUA_TNUMBER) {
517 lmap = lupb_newuserdata(L, sizeof(*lmap), 1, LUPB_MAP);
518 lmap->value_type = lupb_checkfieldtype(L, 2);
519 } else {
520 lupb_MessageDef_check(L, 2);
521 lmap = lupb_newuserdata(L, sizeof(*lmap), 2, LUPB_MAP);
522 lmap->value_type = kUpb_CType_Message;
523 lua_pushvalue(L, 2);
524 lua_setiuservalue(L, -2, MAP_MSGDEF_INDEX);
525 }
526
527 arena = lupb_Arena_pushnew(L);
528 lua_setiuservalue(L, -2, LUPB_ARENA_INDEX);
529
530 lmap->key_type = lupb_checkfieldtype(L, 1);
531 lmap->map = upb_Map_New(arena, lmap->key_type, lmap->value_type);
532 lupb_cacheset(L, lmap->map);
533
534 return 1;
535 }
536
537 /**
538 * lupb_map_index
539 *
540 * Handles:
541 * map[key]
542 */
lupb_map_index(lua_State * L)543 static int lupb_map_index(lua_State* L) {
544 lupb_map* lmap = lupb_map_check(L, 1);
545 upb_MessageValue key = lupb_tomsgval(L, lmap->key_type, 2, 1, LUPB_REF);
546 upb_MessageValue val;
547
548 if (upb_Map_Get(lmap->map, key, &val)) {
549 lupb_pushmsgval(L, 1, lmap->value_type, val);
550 } else {
551 lua_pushnil(L);
552 }
553
554 return 1;
555 }
556
557 /**
558 * lupb_map_len
559 *
560 * Handles:
561 * map_len = #map
562 */
lupb_map_len(lua_State * L)563 static int lupb_map_len(lua_State* L) {
564 lupb_map* lmap = lupb_map_check(L, 1);
565 lua_pushnumber(L, upb_Map_Size(lmap->map));
566 return 1;
567 }
568
569 /**
570 * lupb_Map_Newindex
571 *
572 * Handles:
573 * map[key] = val
574 * map[key] = nil # to remove from map
575 */
lupb_Map_Newindex(lua_State * L)576 static int lupb_Map_Newindex(lua_State* L) {
577 lupb_map* lmap = lupb_map_check(L, 1);
578 upb_Map* map = lmap->map;
579 upb_MessageValue key = lupb_tomsgval(L, lmap->key_type, 2, 1, LUPB_REF);
580
581 if (lua_isnil(L, 3)) {
582 upb_Map_Delete(map, key, NULL);
583 } else {
584 upb_MessageValue val = lupb_tomsgval(L, lmap->value_type, 3, 1, LUPB_COPY);
585 upb_Map_Set(map, key, val, lupb_Arenaget(L, 1));
586 if (lmap->value_type == kUpb_CType_Message) {
587 lupb_Arena_Fuseobjs(L, 1, 3);
588 }
589 }
590
591 return 0;
592 }
593
lupb_MapIterator_Next(lua_State * L)594 static int lupb_MapIterator_Next(lua_State* L) {
595 int map = lua_upvalueindex(2);
596 size_t* iter = lua_touserdata(L, lua_upvalueindex(1));
597 lupb_map* lmap = lupb_map_check(L, map);
598
599 upb_MessageValue key, val;
600 if (upb_Map_Next(lmap->map, &key, &val, iter)) {
601 lupb_pushmsgval(L, map, lmap->key_type, key);
602 lupb_pushmsgval(L, map, lmap->value_type, val);
603 return 2;
604 } else {
605 return 0;
606 }
607 }
608
609 /**
610 * lupb_map_pairs()
611 *
612 * Handles:
613 * pairs(map)
614 */
lupb_map_pairs(lua_State * L)615 static int lupb_map_pairs(lua_State* L) {
616 size_t* iter = lua_newuserdata(L, sizeof(*iter));
617 lupb_map_check(L, 1);
618
619 *iter = kUpb_Map_Begin;
620 lua_pushvalue(L, 1);
621
622 /* Upvalues are [iter, lupb_map]. */
623 lua_pushcclosure(L, &lupb_MapIterator_Next, 2);
624
625 return 1;
626 }
627
628 /* upb_mapiter ]]] */
629
630 static const struct luaL_Reg lupb_map_mm[] = {{"__index", lupb_map_index},
631 {"__len", lupb_map_len},
632 {"__newindex", lupb_Map_Newindex},
633 {"__pairs", lupb_map_pairs},
634 {NULL, NULL}};
635
636 /* lupb_Message
637 * *******************************************************************/
638
639 typedef struct {
640 upb_Message* msg;
641 } lupb_Message;
642
643 /* lupb_Message helpers */
644
lupb_msg_check(lua_State * L,int narg)645 static upb_Message* lupb_msg_check(lua_State* L, int narg) {
646 lupb_Message* msg = luaL_checkudata(L, narg, LUPB_MSG);
647 return msg->msg;
648 }
649
lupb_Message_Getmsgdef(lua_State * L,int msg)650 static const upb_MessageDef* lupb_Message_Getmsgdef(lua_State* L, int msg) {
651 lua_getiuservalue(L, msg, LUPB_MSGDEF_INDEX);
652 const upb_MessageDef* m = lupb_MessageDef_check(L, -1);
653 lua_pop(L, 1);
654 return m;
655 }
656
lupb_msg_tofield(lua_State * L,int msg,int field)657 static const upb_FieldDef* lupb_msg_tofield(lua_State* L, int msg, int field) {
658 size_t len;
659 const char* fieldname = luaL_checklstring(L, field, &len);
660 const upb_MessageDef* m = lupb_Message_Getmsgdef(L, msg);
661 return upb_MessageDef_FindFieldByNameWithSize(m, fieldname, len);
662 }
663
lupb_msg_checkfield(lua_State * L,int msg,int field)664 static const upb_FieldDef* lupb_msg_checkfield(lua_State* L, int msg,
665 int field) {
666 const upb_FieldDef* f = lupb_msg_tofield(L, msg, field);
667 if (f == NULL) {
668 luaL_error(L, "no such field '%s'", lua_tostring(L, field));
669 }
670 return f;
671 }
672
lupb_msg_pushnew(lua_State * L,int narg)673 upb_Message* lupb_msg_pushnew(lua_State* L, int narg) {
674 const upb_MessageDef* m = lupb_MessageDef_check(L, narg);
675 lupb_Message* lmsg = lupb_newuserdata(L, sizeof(lupb_Message), 2, LUPB_MSG);
676 upb_Arena* arena = lupb_Arena_pushnew(L);
677
678 lua_setiuservalue(L, -2, LUPB_ARENA_INDEX);
679 lua_pushvalue(L, 1);
680 lua_setiuservalue(L, -2, LUPB_MSGDEF_INDEX);
681
682 lmsg->msg = upb_Message_New(upb_MessageDef_MiniTable(m), arena);
683 lupb_cacheset(L, lmsg->msg);
684 return lmsg->msg;
685 }
686
687 /**
688 * lupb_Message_Newmsgwrapper()
689 *
690 * Creates a new wrapper for a message, copying the arena and msgdef references
691 * from |narg| (which should be an array or map).
692 */
lupb_Message_Newmsgwrapper(lua_State * L,int narg,upb_MessageValue val)693 static void lupb_Message_Newmsgwrapper(lua_State* L, int narg,
694 upb_MessageValue val) {
695 lupb_Message* lmsg = lupb_newuserdata(L, sizeof(*lmsg), 2, LUPB_MSG);
696 lmsg->msg = (upb_Message*)val.msg_val; /* XXX: cast isn't great. */
697 lupb_cacheset(L, lmsg->msg);
698
699 /* Copy both arena and msgdef into the wrapper. */
700 lua_getiuservalue(L, narg, LUPB_ARENA_INDEX);
701 lua_setiuservalue(L, -2, LUPB_ARENA_INDEX);
702 lua_getiuservalue(L, narg, LUPB_MSGDEF_INDEX);
703 lua_setiuservalue(L, -2, LUPB_MSGDEF_INDEX);
704 }
705
706 /**
707 * lupb_Message_Newud()
708 *
709 * Creates the Lua userdata for a new wrapper object, adding a reference to
710 * the msgdef if necessary.
711 */
lupb_Message_Newud(lua_State * L,int narg,size_t size,const char * type,const upb_FieldDef * f)712 static void* lupb_Message_Newud(lua_State* L, int narg, size_t size,
713 const char* type, const upb_FieldDef* f) {
714 if (upb_FieldDef_CType(f) == kUpb_CType_Message) {
715 /* Wrapper needs a reference to the msgdef. */
716 void* ud = lupb_newuserdata(L, size, 2, type);
717 lua_getiuservalue(L, narg, LUPB_MSGDEF_INDEX);
718 lupb_MessageDef_pushsubmsgdef(L, f);
719 lua_setiuservalue(L, -2, LUPB_MSGDEF_INDEX);
720 return ud;
721 } else {
722 return lupb_newuserdata(L, size, 1, type);
723 }
724 }
725
726 /**
727 * lupb_Message_Newwrapper()
728 *
729 * Creates a new Lua wrapper object to wrap the given array, map, or message.
730 */
lupb_Message_Newwrapper(lua_State * L,int narg,const upb_FieldDef * f,upb_MutableMessageValue val)731 static void lupb_Message_Newwrapper(lua_State* L, int narg,
732 const upb_FieldDef* f,
733 upb_MutableMessageValue val) {
734 if (upb_FieldDef_IsMap(f)) {
735 const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f);
736 const upb_FieldDef* key_f =
737 upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_KeyFieldNumber);
738 const upb_FieldDef* val_f =
739 upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_ValueFieldNumber);
740 lupb_map* lmap =
741 lupb_Message_Newud(L, narg, sizeof(*lmap), LUPB_MAP, val_f);
742 lmap->key_type = upb_FieldDef_CType(key_f);
743 lmap->value_type = upb_FieldDef_CType(val_f);
744 lmap->map = val.map;
745 } else if (upb_FieldDef_IsRepeated(f)) {
746 lupb_array* larr =
747 lupb_Message_Newud(L, narg, sizeof(*larr), LUPB_ARRAY, f);
748 larr->type = upb_FieldDef_CType(f);
749 larr->arr = val.array;
750 } else {
751 lupb_Message* lmsg =
752 lupb_Message_Newud(L, narg, sizeof(*lmsg), LUPB_MSG, f);
753 lmsg->msg = val.msg;
754 }
755
756 /* Copy arena ref to new wrapper. This may be a different arena than the
757 * underlying data was originally constructed from, but if so both arenas
758 * must be in the same group. */
759 lua_getiuservalue(L, narg, LUPB_ARENA_INDEX);
760 lua_setiuservalue(L, -2, LUPB_ARENA_INDEX);
761
762 lupb_cacheset(L, val.msg);
763 }
764
765 /**
766 * lupb_msg_typechecksubmsg()
767 *
768 * Typechecks the given array, map, or msg against this upb_FieldDef.
769 */
lupb_msg_typechecksubmsg(lua_State * L,int narg,int msgarg,const upb_FieldDef * f)770 static void lupb_msg_typechecksubmsg(lua_State* L, int narg, int msgarg,
771 const upb_FieldDef* f) {
772 /* Typecheck this map's msgdef against this message field. */
773 lua_getiuservalue(L, narg, LUPB_MSGDEF_INDEX);
774 lua_getiuservalue(L, msgarg, LUPB_MSGDEF_INDEX);
775 lupb_MessageDef_pushsubmsgdef(L, f);
776 luaL_argcheck(L, lua_rawequal(L, -1, -2), narg, "message type mismatch");
777 lua_pop(L, 2);
778 }
779
780 /* lupb_Message Public API */
781
782 /**
783 * lupb_MessageDef_call
784 *
785 * Handles:
786 * new_msg = MessageClass()
787 * new_msg = MessageClass{foo = "bar", baz = 3, quux = {foo = 3}}
788 */
lupb_MessageDef_call(lua_State * L)789 int lupb_MessageDef_call(lua_State* L) {
790 int arg_count = lua_gettop(L);
791 lupb_msg_pushnew(L, 1);
792
793 if (arg_count > 1) {
794 /* Set initial fields from table. */
795 int msg = arg_count + 1;
796 lua_pushnil(L);
797 while (lua_next(L, 2) != 0) {
798 lua_pushvalue(L, -2); /* now stack is key, val, key */
799 lua_insert(L, -3); /* now stack is key, key, val */
800 lua_settable(L, msg);
801 }
802 }
803
804 return 1;
805 }
806
807 /**
808 * lupb_msg_index
809 *
810 * Handles:
811 * msg.foo
812 * msg["foo"]
813 * msg[field_descriptor] # (for extensions) (TODO)
814 */
lupb_msg_index(lua_State * L)815 static int lupb_msg_index(lua_State* L) {
816 upb_Message* msg = lupb_msg_check(L, 1);
817 const upb_FieldDef* f = lupb_msg_checkfield(L, 1, 2);
818
819 if (upb_FieldDef_IsRepeated(f) || upb_FieldDef_IsSubMessage(f)) {
820 /* Wrapped type; get or create wrapper. */
821 upb_Arena* arena = upb_FieldDef_IsRepeated(f) ? lupb_Arenaget(L, 1) : NULL;
822 upb_MutableMessageValue val = upb_Message_Mutable(msg, f, arena);
823 if (!lupb_cacheget(L, val.msg)) {
824 lupb_Message_Newwrapper(L, 1, f, val);
825 }
826 } else {
827 /* Value type, just push value and return .*/
828 upb_MessageValue val = upb_Message_GetFieldByDef(msg, f);
829 lupb_pushmsgval(L, 0, upb_FieldDef_CType(f), val);
830 }
831
832 return 1;
833 }
834
835 /**
836 * lupb_Message_Newindex()
837 *
838 * Handles:
839 * msg.foo = bar
840 * msg["foo"] = bar
841 * msg[field_descriptor] = bar # (for extensions) (TODO)
842 */
lupb_Message_Newindex(lua_State * L)843 static int lupb_Message_Newindex(lua_State* L) {
844 upb_Message* msg = lupb_msg_check(L, 1);
845 const upb_FieldDef* f = lupb_msg_checkfield(L, 1, 2);
846 upb_MessageValue msgval;
847 bool merge_arenas = true;
848
849 if (upb_FieldDef_IsMap(f)) {
850 lupb_map* lmap = lupb_map_check(L, 3);
851 const upb_MessageDef* entry = upb_FieldDef_MessageSubDef(f);
852 const upb_FieldDef* key_f =
853 upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_KeyFieldNumber);
854 const upb_FieldDef* val_f =
855 upb_MessageDef_FindFieldByNumber(entry, kUpb_MapEntry_ValueFieldNumber);
856 upb_CType key_type = upb_FieldDef_CType(key_f);
857 upb_CType value_type = upb_FieldDef_CType(val_f);
858 luaL_argcheck(L, lmap->key_type == key_type, 3, "key type mismatch");
859 luaL_argcheck(L, lmap->value_type == value_type, 3, "value type mismatch");
860 if (value_type == kUpb_CType_Message) {
861 lupb_msg_typechecksubmsg(L, 3, 1, val_f);
862 }
863 msgval.map_val = lmap->map;
864 } else if (upb_FieldDef_IsRepeated(f)) {
865 lupb_array* larr = lupb_array_check(L, 3);
866 upb_CType type = upb_FieldDef_CType(f);
867 luaL_argcheck(L, larr->type == type, 3, "array type mismatch");
868 if (type == kUpb_CType_Message) {
869 lupb_msg_typechecksubmsg(L, 3, 1, f);
870 }
871 msgval.array_val = larr->arr;
872 } else if (upb_FieldDef_IsSubMessage(f)) {
873 upb_Message* msg = lupb_msg_check(L, 3);
874 lupb_msg_typechecksubmsg(L, 3, 1, f);
875 msgval.msg_val = msg;
876 } else {
877 msgval = lupb_tomsgval(L, upb_FieldDef_CType(f), 3, 1, LUPB_COPY);
878 merge_arenas = false;
879 }
880
881 if (merge_arenas) {
882 lupb_Arena_Fuseobjs(L, 1, 3);
883 }
884
885 upb_Message_SetFieldByDef(msg, f, msgval, lupb_Arenaget(L, 1));
886
887 /* Return the new value for chained assignments. */
888 lua_pushvalue(L, 3);
889 return 1;
890 }
891
892 /**
893 * lupb_msg_tostring()
894 *
895 * Handles:
896 * tostring(msg)
897 * print(msg)
898 * etc.
899 */
lupb_msg_tostring(lua_State * L)900 static int lupb_msg_tostring(lua_State* L) {
901 upb_Message* msg = lupb_msg_check(L, 1);
902 const upb_MessageDef* m;
903 char buf[1024];
904 size_t size;
905
906 lua_getiuservalue(L, 1, LUPB_MSGDEF_INDEX);
907 m = lupb_MessageDef_check(L, -1);
908
909 size = upb_TextEncode(msg, m, NULL, 0, buf, sizeof(buf));
910
911 if (size < sizeof(buf)) {
912 lua_pushlstring(L, buf, size);
913 } else {
914 char* ptr = malloc(size + 1);
915 upb_TextEncode(msg, m, NULL, 0, ptr, size + 1);
916 lua_pushlstring(L, ptr, size);
917 free(ptr);
918 }
919
920 return 1;
921 }
922
923 static const struct luaL_Reg lupb_msg_mm[] = {
924 {"__index", lupb_msg_index},
925 {"__newindex", lupb_Message_Newindex},
926 {"__tostring", lupb_msg_tostring},
927 {NULL, NULL}};
928
929 /* lupb_Message toplevel
930 * **********************************************************/
931
lupb_getoptions(lua_State * L,int narg)932 static int lupb_getoptions(lua_State* L, int narg) {
933 int options = 0;
934 if (lua_gettop(L) >= narg) {
935 size_t len = lua_rawlen(L, narg);
936 for (size_t i = 1; i <= len; i++) {
937 lua_rawgeti(L, narg, i);
938 options |= lupb_checkuint32(L, -1);
939 lua_pop(L, 1);
940 }
941 }
942 return options;
943 }
944
945 /**
946 * lupb_decode()
947 *
948 * Handles:
949 * msg = upb.decode(MessageClass, bin_string)
950 */
lupb_decode(lua_State * L)951 static int lupb_decode(lua_State* L) {
952 size_t len;
953 const upb_MessageDef* m = lupb_MessageDef_check(L, 1);
954 const char* pb = lua_tolstring(L, 2, &len);
955 const upb_MiniTable* layout = upb_MessageDef_MiniTable(m);
956 upb_Message* msg = lupb_msg_pushnew(L, 1);
957 upb_Arena* arena = lupb_Arenaget(L, -1);
958 char* buf;
959
960 /* Copy input data to arena, message will reference it. */
961 buf = upb_Arena_Malloc(arena, len);
962 memcpy(buf, pb, len);
963
964 upb_DecodeStatus status = upb_Decode(buf, len, msg, layout, NULL,
965 kUpb_DecodeOption_AliasString, arena);
966
967 if (status != kUpb_DecodeStatus_Ok) {
968 lua_pushstring(L, "Error decoding protobuf.");
969 return lua_error(L);
970 }
971
972 return 1;
973 }
974
975 /**
976 * lupb_Encode()
977 *
978 * Handles:
979 * bin_string = upb.encode(msg)
980 */
lupb_Encode(lua_State * L)981 static int lupb_Encode(lua_State* L) {
982 const upb_Message* msg = lupb_msg_check(L, 1);
983 const upb_MessageDef* m = lupb_Message_Getmsgdef(L, 1);
984 const upb_MiniTable* layout = upb_MessageDef_MiniTable(m);
985 int options = lupb_getoptions(L, 2);
986 upb_Arena* arena = lupb_Arena_pushnew(L);
987 char* buf;
988 size_t size;
989 upb_EncodeStatus status =
990 upb_Encode(msg, (const void*)layout, options, arena, &buf, &size);
991 if (status != kUpb_EncodeStatus_Ok) {
992 lua_pushstring(L, "Error encoding protobuf.");
993 return lua_error(L);
994 }
995
996 lua_pushlstring(L, buf, size);
997
998 return 1;
999 }
1000
1001 /**
1002 * lupb_jsondecode()
1003 *
1004 * Handles:
1005 * text_string = upb.json_decode(MessageClass, json_str,
1006 * {upb.JSONDEC_IGNOREUNKNOWN})
1007 */
lupb_jsondecode(lua_State * L)1008 static int lupb_jsondecode(lua_State* L) {
1009 size_t len;
1010 const upb_MessageDef* m = lupb_MessageDef_check(L, 1);
1011 const char* json = lua_tolstring(L, 2, &len);
1012 int options = lupb_getoptions(L, 3);
1013 upb_Message* msg;
1014 upb_Arena* arena;
1015 upb_Status status;
1016
1017 msg = lupb_msg_pushnew(L, 1);
1018 arena = lupb_Arenaget(L, -1);
1019 upb_Status_Clear(&status);
1020 upb_JsonDecode(json, len, msg, m, NULL, options, arena, &status);
1021 lupb_checkstatus(L, &status);
1022
1023 return 1;
1024 }
1025
1026 /**
1027 * lupb_jsonencode()
1028 *
1029 * Handles:
1030 * text_string = upb.json_encode(msg, {upb.JSONENC_EMITDEFAULTS})
1031 */
lupb_jsonencode(lua_State * L)1032 static int lupb_jsonencode(lua_State* L) {
1033 upb_Message* msg = lupb_msg_check(L, 1);
1034 const upb_MessageDef* m = lupb_Message_Getmsgdef(L, 1);
1035 int options = lupb_getoptions(L, 2);
1036 char buf[1024];
1037 size_t size;
1038 upb_Status status;
1039
1040 upb_Status_Clear(&status);
1041 size = upb_JsonEncode(msg, m, NULL, options, buf, sizeof(buf), &status);
1042 lupb_checkstatus(L, &status);
1043
1044 if (size < sizeof(buf)) {
1045 lua_pushlstring(L, buf, size);
1046 } else {
1047 char* ptr = malloc(size + 1);
1048 upb_JsonEncode(msg, m, NULL, options, ptr, size + 1, &status);
1049 lupb_checkstatus(L, &status);
1050 lua_pushlstring(L, ptr, size);
1051 free(ptr);
1052 }
1053
1054 return 1;
1055 }
1056
1057 /**
1058 * lupb_textencode()
1059 *
1060 * Handles:
1061 * text_string = upb.text_encode(msg, {upb.TXTENC_SINGLELINE})
1062 */
lupb_textencode(lua_State * L)1063 static int lupb_textencode(lua_State* L) {
1064 upb_Message* msg = lupb_msg_check(L, 1);
1065 const upb_MessageDef* m = lupb_Message_Getmsgdef(L, 1);
1066 int options = lupb_getoptions(L, 2);
1067 char buf[1024];
1068 size_t size;
1069
1070 size = upb_TextEncode(msg, m, NULL, options, buf, sizeof(buf));
1071
1072 if (size < sizeof(buf)) {
1073 lua_pushlstring(L, buf, size);
1074 } else {
1075 char* ptr = malloc(size + 1);
1076 upb_TextEncode(msg, m, NULL, options, ptr, size + 1);
1077 lua_pushlstring(L, ptr, size);
1078 free(ptr);
1079 }
1080
1081 return 1;
1082 }
1083
lupb_setfieldi(lua_State * L,const char * field,int i)1084 static void lupb_setfieldi(lua_State* L, const char* field, int i) {
1085 lua_pushinteger(L, i);
1086 lua_setfield(L, -2, field);
1087 }
1088
1089 static const struct luaL_Reg lupb_msg_toplevel_m[] = {
1090 {"Array", lupb_Array_New}, {"Map", lupb_Map_New},
1091 {"decode", lupb_decode}, {"encode", lupb_Encode},
1092 {"json_decode", lupb_jsondecode}, {"json_encode", lupb_jsonencode},
1093 {"text_encode", lupb_textencode}, {NULL, NULL}};
1094
lupb_msg_registertypes(lua_State * L)1095 void lupb_msg_registertypes(lua_State* L) {
1096 lupb_setfuncs(L, lupb_msg_toplevel_m);
1097
1098 lupb_register_type(L, LUPB_ARENA, NULL, lupb_Arena_mm);
1099 lupb_register_type(L, LUPB_ARRAY, NULL, lupb_array_mm);
1100 lupb_register_type(L, LUPB_MAP, NULL, lupb_map_mm);
1101 lupb_register_type(L, LUPB_MSG, NULL, lupb_msg_mm);
1102
1103 lupb_setfieldi(L, "TXTENC_SINGLELINE", UPB_TXTENC_SINGLELINE);
1104 lupb_setfieldi(L, "TXTENC_SKIPUNKNOWN", UPB_TXTENC_SKIPUNKNOWN);
1105 lupb_setfieldi(L, "TXTENC_NOSORT", UPB_TXTENC_NOSORT);
1106
1107 lupb_setfieldi(L, "ENCODE_DETERMINISTIC", kUpb_EncodeOption_Deterministic);
1108 lupb_setfieldi(L, "ENCODE_SKIPUNKNOWN", kUpb_EncodeOption_SkipUnknown);
1109
1110 lupb_setfieldi(L, "JSONENC_EMITDEFAULTS", upb_JsonEncode_EmitDefaults);
1111 lupb_setfieldi(L, "JSONENC_PROTONAMES", upb_JsonEncode_UseProtoNames);
1112
1113 lupb_setfieldi(L, "JSONDEC_IGNOREUNKNOWN", upb_JsonDecode_IgnoreUnknown);
1114
1115 lupb_cacheinit(L);
1116 }
1117