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