2 ** lupb_msg -- Message/Array/Map objects in Lua/C that wrap upb/msg.h
12 #include "upb/bindings/lua/upb.h"
13 #include "upb/handlers.h"
14 #include "upb/legacy_msg_reflection.h"
17 #include "upb/port_def.inc"
20 * Message/Array/Map objects can be constructed in one of two ways:
22 * 1. To point to existing msg/array/map data inside an arena.
23 * 2. To create and uniquely own some brand new data.
25 * Case (1) is for when we've parsed some data into an arena (which is faster
26 * than parsing directly into Lua objects) or when we're pointing at some
27 * read-only data (like custom options in a def).
29 * Case (2) is for when a user creates the object directly in Lua.
31 * We use the userval of container objects (Message/Array/Map) to store
32 * references to sub-objects (Strings/Messages/Arrays/Maps). But we need to
33 * keep the userval in sync with the underlying upb_msg/upb_array/upb_map.
34 * We populate the userval lazily from the underlying data.
36 * This means that no one may remove/replace any String/Message/Array/Map
37 * field/entry in the underlying upb_{msg,array,map} behind our back. It's ok
38 * for entries to be added or for primitives to be modified, but *replacing*
39 * sub-containers is not.
41 * Luckily parse/merge follow this rule. However clear does not, so it's not
42 * safe to clear behind our back.
45 #define LUPB_ARENA "lupb.arena"
47 #define LUPB_MSGCLASS "lupb.msgclass"
48 #define LUPB_MSGFACTORY "lupb.msgfactory"
50 #define LUPB_ARRAY "lupb.array"
51 #define LUPB_MAP "lupb.map"
52 #define LUPB_MSG "lupb.msg"
53 #define LUPB_STRING "lupb.string"
55 static int lupb_msg_pushnew(lua_State *L, int narg);
57 /* Lazily creates the uservalue if it doesn't exist. */
58 static void lupb_getuservalue(lua_State *L, int index) {
59 lua_getuservalue(L, index);
60 if (lua_isnil(L, -1)) {
61 /* Lazily create and set userval. */
62 lua_pop(L, 1); /* nil. */
63 lua_pushvalue(L, index); /* userdata copy. */
65 lua_setuservalue(L, -2);
66 lua_pop(L, 1); /* userdata copy. */
67 lua_getuservalue(L, index);
69 assert(!lua_isnil(L, -1));
72 static void lupb_uservalseti(lua_State *L, int userdata, int index, int val) {
73 lupb_getuservalue(L, userdata);
74 lua_pushvalue(L, val);
75 lua_rawseti(L, -2, index);
76 lua_pop(L, 1); /* Uservalue. */
79 static void lupb_uservalgeti(lua_State *L, int userdata, int index) {
80 lupb_getuservalue(L, userdata);
81 lua_rawgeti(L, -1, index);
83 lua_pop(L, 1); /* Uservalue. */
86 /* Pushes a new userdata with the given metatable. */
87 static void *lupb_newuserdata(lua_State *L, size_t size, const char *type) {
88 void *ret = lua_newuserdata(L, size);
91 luaL_getmetatable(L, type);
92 UPB_ASSERT(!lua_isnil(L, -1)); /* Should have been created by luaopen_upb. */
93 lua_setmetatable(L, -2);
95 /* We don't set a uservalue here -- we lazily create it later if necessary. */
101 /* lupb_arena *****************************************************************/
103 /* lupb_arena only exists to wrap a upb_arena. It is never exposed to users;
104 * it is an internal memory management detail. Other objects refer to this
105 * object from their userdata to keep the arena-owned data alive. */
111 upb_arena *lupb_arena_check(lua_State *L, int narg) {
112 lupb_arena *a = luaL_checkudata(L, narg, LUPB_ARENA);
113 return a ? a->arena : NULL;
116 int lupb_arena_new(lua_State *L) {
117 lupb_arena *a = lupb_newuserdata(L, sizeof(lupb_arena), LUPB_ARENA);
119 /* TODO(haberman): use Lua alloc func as block allocator? Would need to
120 * verify that all cases of upb_malloc in msg/table are longjmp-safe. */
121 a->arena = upb_arena_new();
126 char lupb_arena_cache_key;
128 /* Returns the global lupb_arena func that was created in our luaopen().
129 * Callers can be guaranteed that it will be alive as long as |L| is.
130 * TODO(haberman): we shouldn't use a global arena! We should have
131 * one arena for a parse, or per independently-created message. */
132 upb_arena *lupb_arena_get(lua_State *L) {
135 lua_pushlightuserdata(L, &lupb_arena_cache_key);
136 lua_gettable(L, LUA_REGISTRYINDEX);
137 arena = lua_touserdata(L, -1);
144 static void lupb_arena_initsingleton(lua_State *L) {
145 lua_pushlightuserdata(L, &lupb_arena_cache_key);
147 lua_settable(L, LUA_REGISTRYINDEX);
150 static int lupb_arena_gc(lua_State *L) {
151 upb_arena *a = lupb_arena_check(L, 1);
156 static const struct luaL_Reg lupb_arena_mm[] = {
157 {"__gc", lupb_arena_gc},
162 /* lupb_msgfactory ************************************************************/
164 /* Userval contains a map of:
165 * [1] -> SymbolTable (to keep GC-reachable)
166 * [const upb_msgdef*] -> [lupb_msgclass userdata]
169 #define LUPB_MSGFACTORY_SYMTAB 1
171 typedef struct lupb_msgfactory {
172 upb_msgfactory *factory;
175 static int lupb_msgclass_pushnew(lua_State *L, int factory,
176 const upb_msgdef *md);
178 /* lupb_msgfactory helpers. */
180 static lupb_msgfactory *lupb_msgfactory_check(lua_State *L, int narg) {
181 return luaL_checkudata(L, narg, LUPB_MSGFACTORY);
184 static void lupb_msgfactory_pushmsgclass(lua_State *L, int narg,
185 const upb_msgdef *md) {
186 lupb_getuservalue(L, narg);
187 lua_pushlightuserdata(L, (void*)md);
190 if (lua_isnil(L, -1)) {
192 /* TODO: verify md is in symtab? */
193 lupb_msgclass_pushnew(L, narg, md);
195 /* Set in userval. */
196 lua_pushlightuserdata(L, (void*)md);
197 lua_pushvalue(L, -2);
202 static int lupb_msgfactory_gc(lua_State *L) {
203 lupb_msgfactory *lfactory = lupb_msgfactory_check(L, 1);
205 if (lfactory->factory) {
206 upb_msgfactory_free(lfactory->factory);
207 lfactory->factory = NULL;
213 /* lupb_msgfactory Public API. */
216 * lupb_msgfactory_new()
219 * msgfactory = upb.MessageFactory(symtab)
221 * Creates a new, empty MessageFactory for the given SymbolTable.
222 * Message classes will be created on demand when the user calls
223 * msgfactory.get_message_class().
225 static int lupb_msgfactory_new(lua_State *L) {
226 const upb_symtab *symtab = lupb_symtab_check(L, 1);
228 lupb_msgfactory *lmsgfactory =
229 lupb_newuserdata(L, sizeof(lupb_msgfactory), LUPB_MSGFACTORY);
230 lmsgfactory->factory = upb_msgfactory_new(symtab);
231 lupb_uservalseti(L, -1, LUPB_MSGFACTORY_SYMTAB, 1);
237 * lupb_msgfactory_getmsgclass()
240 * MessageClass = factory.get_message_class(message_name)
242 static int lupb_msgfactory_getmsgclass(lua_State *L) {
243 lupb_msgfactory *lfactory = lupb_msgfactory_check(L, 1);
244 const upb_symtab *symtab = upb_msgfactory_symtab(lfactory->factory);
245 const upb_msgdef *m = upb_symtab_lookupmsg(symtab, luaL_checkstring(L, 2));
248 luaL_error(L, "No such message type: %s\n", lua_tostring(L, 2));
251 lupb_msgfactory_pushmsgclass(L, 1, m);
256 static const struct luaL_Reg lupb_msgfactory_m[] = {
257 {"get_message_class", lupb_msgfactory_getmsgclass},
261 static const struct luaL_Reg lupb_msgfactory_mm[] = {
262 {"__gc", lupb_msgfactory_gc},
267 /* lupb_msgclass **************************************************************/
269 /* Userval contains a map of:
270 * [1] -> MessageFactory (to keep GC-reachable)
271 * [const upb_msgdef*] -> [lupb_msgclass userdata]
274 #define LUPB_MSGCLASS_FACTORY 1
276 struct lupb_msgclass {
277 const upb_msglayout *layout;
278 const upb_msgdef *msgdef;
279 const lupb_msgfactory *lfactory;
282 /* Type-checks for assigning to a message field. */
283 static upb_msgval lupb_array_typecheck(lua_State *L, int narg, int msg,
284 const upb_fielddef *f);
285 static upb_msgval lupb_map_typecheck(lua_State *L, int narg, int msg,
286 const upb_fielddef *f);
287 static const lupb_msgclass *lupb_msg_getsubmsgclass(lua_State *L, int narg,
288 const upb_fielddef *f);
289 static const lupb_msgclass *lupb_msg_msgclassfor(lua_State *L, int narg,
290 const upb_msgdef *md);
292 const lupb_msgclass *lupb_msgclass_check(lua_State *L, int narg) {
293 return luaL_checkudata(L, narg, LUPB_MSGCLASS);
296 const upb_msglayout *lupb_msgclass_getlayout(lua_State *L, int narg) {
297 return lupb_msgclass_check(L, narg)->layout;
300 const upb_msgdef *lupb_msgclass_getmsgdef(const lupb_msgclass *lmsgclass) {
301 return lmsgclass->msgdef;
304 upb_msgfactory *lupb_msgclass_getfactory(const lupb_msgclass *lmsgclass) {
305 return lmsgclass->lfactory->factory;
309 * lupb_msgclass_typecheck()
311 * Verifies that the expected msgclass matches the actual. If not, raises a Lua
314 static void lupb_msgclass_typecheck(lua_State *L, const lupb_msgclass *expected,
315 const lupb_msgclass *actual) {
316 if (expected != actual) {
317 luaL_error(L, "Message had incorrect type, expected '%s', got '%s'",
318 upb_msgdef_fullname(expected->msgdef),
319 upb_msgdef_fullname(actual->msgdef));
323 static const lupb_msgclass *lupb_msgclass_msgclassfor(lua_State *L, int narg,
324 const upb_msgdef *md) {
325 lupb_uservalgeti(L, narg, LUPB_MSGCLASS_FACTORY);
326 lupb_msgfactory_pushmsgclass(L, -1, md);
327 return lupb_msgclass_check(L, -1);
331 * lupb_msgclass_getsubmsgclass()
333 * Given a MessageClass at index |narg| and the submessage field |f|, returns
334 * the message class for this field.
336 * Currently we do a hash table lookup for this. If we wanted we could try to
337 * optimize this by caching these pointers in our msgclass, in an array indexed
338 * by field index. We would still need to fall back to calling msgclassfor(),
339 * unless we wanted to eagerly create message classes for all submessages. But
340 * for big schemas that might be a lot of things to build, and we might end up
341 * not using most of them. */
342 static const lupb_msgclass *lupb_msgclass_getsubmsgclass(lua_State *L, int narg,
343 const upb_fielddef *f) {
344 if (upb_fielddef_type(f) != UPB_TYPE_MESSAGE) {
348 return lupb_msgclass_msgclassfor(L, narg, upb_fielddef_msgsubdef(f));
351 static int lupb_msgclass_pushnew(lua_State *L, int factory,
352 const upb_msgdef *md) {
353 const lupb_msgfactory *lfactory = lupb_msgfactory_check(L, factory);
354 lupb_msgclass *lmc = lupb_newuserdata(L, sizeof(*lmc), LUPB_MSGCLASS);
356 lupb_uservalseti(L, -1, LUPB_MSGCLASS_FACTORY, factory);
357 lmc->layout = upb_msgfactory_getlayout(lfactory->factory, md);
358 lmc->lfactory = lfactory;
364 /* MessageClass Public API. */
367 * lupb_msgclass_call()
370 * msg = MessageClass()
372 * Creates a new message from the given MessageClass.
374 static int lupb_msgclass_call(lua_State *L) {
375 lupb_msg_pushnew(L, 1);
379 static const struct luaL_Reg lupb_msgclass_mm[] = {
380 {"__call", lupb_msgclass_call},
385 /* upb <-> Lua type conversion ************************************************/
387 static bool lupb_istypewrapped(upb_fieldtype_t type) {
388 return type == UPB_TYPE_STRING || type == UPB_TYPE_BYTES ||
389 type == UPB_TYPE_MESSAGE;
392 static upb_msgval lupb_tomsgval(lua_State *L, upb_fieldtype_t type, int narg,
393 const lupb_msgclass *lmsgclass) {
397 return upb_msgval_int32(lupb_checkint32(L, narg));
399 return upb_msgval_int64(lupb_checkint64(L, narg));
400 case UPB_TYPE_UINT32:
401 return upb_msgval_uint32(lupb_checkuint32(L, narg));
402 case UPB_TYPE_UINT64:
403 return upb_msgval_uint64(lupb_checkuint64(L, narg));
404 case UPB_TYPE_DOUBLE:
405 return upb_msgval_double(lupb_checkdouble(L, narg));
407 return upb_msgval_float(lupb_checkfloat(L, narg));
409 return upb_msgval_bool(lupb_checkbool(L, narg));
410 case UPB_TYPE_STRING:
411 case UPB_TYPE_BYTES: {
413 const char *ptr = lupb_checkstring(L, narg, &len);
414 return upb_msgval_makestr(ptr, len);
416 case UPB_TYPE_MESSAGE:
417 UPB_ASSERT(lmsgclass);
418 return upb_msgval_msg(lupb_msg_checkmsg(L, narg, lmsgclass));
423 static void lupb_pushmsgval(lua_State *L, upb_fieldtype_t type,
428 lupb_pushint32(L, upb_msgval_getint32(val));
431 lupb_pushint64(L, upb_msgval_getint64(val));
433 case UPB_TYPE_UINT32:
434 lupb_pushuint32(L, upb_msgval_getuint32(val));
436 case UPB_TYPE_UINT64:
437 lupb_pushuint64(L, upb_msgval_getuint64(val));
439 case UPB_TYPE_DOUBLE:
440 lupb_pushdouble(L, upb_msgval_getdouble(val));
443 lupb_pushfloat(L, upb_msgval_getfloat(val));
446 lua_pushboolean(L, upb_msgval_getbool(val));
448 case UPB_TYPE_STRING:
450 case UPB_TYPE_MESSAGE:
451 break; /* Shouldn't call this function. */
457 /* lupb_array *****************************************************************/
459 /* A strongly typed array. Implemented by wrapping upb_array.
461 * - we only allow integer indices.
462 * - all entries must have the correct type.
463 * - we do not allow "holes" in the array; you can only assign to an existing
464 * index or one past the end (which will grow the array by one).
466 * For string/submessage entries we keep in the userval:
468 * [number index] -> [lupb_string/lupb_msg userdata]
472 /* Only needed for array of message. This wastes space in the non-message
473 * case but simplifies the code. Could optimize away if desired. */
474 const lupb_msgclass *lmsgclass;
476 upb_fieldtype_t type;
479 #define ARRAY_MSGCLASS_INDEX 0
481 static lupb_array *lupb_array_check(lua_State *L, int narg) {
482 return luaL_checkudata(L, narg, LUPB_ARRAY);
486 * lupb_array_typecheck()
488 * Verifies that the lupb_array object at index |narg| can be safely assigned
489 * to the field |f| of the lupb_msg object at index |msg|. If this is safe,
490 * returns a upb_msgval representing the array. Otherwise, throws a Lua error.
492 static upb_msgval lupb_array_typecheck(lua_State *L, int narg, int msg,
493 const upb_fielddef *f) {
494 lupb_array *larray = lupb_array_check(L, narg);
496 if (upb_array_type(larray->arr) != upb_fielddef_type(f) ||
497 lupb_msg_getsubmsgclass(L, msg, f) != larray->lmsgclass) {
498 luaL_error(L, "Array had incorrect type (expected: %d, got: %d)",
499 (int)upb_fielddef_type(f), (int)upb_array_type(larray->arr));
502 if (upb_array_type(larray->arr) == UPB_TYPE_MESSAGE) {
503 lupb_msgclass_typecheck(L, lupb_msg_getsubmsgclass(L, msg, f),
507 return upb_msgval_arr(larray->arr);
511 * lupb_array_checkindex()
513 * Checks the array index at Lua stack index |narg| to verify that it is an
514 * integer between 1 and |max|, inclusively. Also corrects it to be zero-based
517 * We use "int" because of lua_rawseti/lua_rawgeti -- can re-evaluate if we want
518 * arrays bigger than 2^31.
520 static int lupb_array_checkindex(lua_State *L, int narg, uint32_t max) {
521 uint32_t n = lupb_checkuint32(L, narg);
522 if (n == 0 || n > max || n > INT_MAX) {
523 luaL_error(L, "Invalid array index: expected between 1 and %d", (int)max);
525 return n - 1; /* Lua uses 1-based indexing. :( */
528 /* lupb_array Public API */
530 static int lupb_array_new(lua_State *L) {
532 upb_fieldtype_t type;
533 const lupb_msgclass *lmsgclass = NULL;
535 if (lua_type(L, 1) == LUA_TNUMBER) {
536 type = lupb_checkfieldtype(L, 1);
538 type = UPB_TYPE_MESSAGE;
539 lmsgclass = lupb_msgclass_check(L, 1);
540 lupb_uservalseti(L, -1, ARRAY_MSGCLASS_INDEX, 1); /* GC-root lmsgclass. */
543 larray = lupb_newuserdata(L, sizeof(*larray), LUPB_ARRAY);
545 larray->lmsgclass = lmsgclass;
546 larray->arr = upb_array_new(lupb_arena_get(L));
551 static int lupb_array_newindex(lua_State *L) {
552 lupb_array *larray = lupb_array_check(L, 1);
553 upb_fieldtype_t type = upb_array_type(larray->arr);
554 uint32_t n = lupb_array_checkindex(L, 2, upb_array_size(larray->arr) + 1);
555 upb_msgval msgval = lupb_tomsgval(L, type, 3, larray->lmsgclass);
557 upb_array_set(larray->arr, larray->type, n, msgval, lupb_arena_get(L));
559 if (lupb_istypewrapped(type)) {
560 lupb_uservalseti(L, 1, n, 3);
563 return 0; /* 1 for chained assignments? */
566 static int lupb_array_index(lua_State *L) {
567 lupb_array *larray = lupb_array_check(L, 1);
568 upb_array *array = larray->arr;
569 uint32_t n = lupb_array_checkindex(L, 2, upb_array_size(array));
570 upb_fieldtype_t type = upb_array_type(array);
572 if (lupb_istypewrapped(type)) {
573 lupb_uservalgeti(L, 1, n);
575 lupb_pushmsgval(L, upb_array_type(array),
576 upb_array_get(array, larray->type, n));
582 static int lupb_array_len(lua_State *L) {
583 lupb_array *larray = lupb_array_check(L, 1);
584 lua_pushnumber(L, upb_array_size(larray->arr));
588 static const struct luaL_Reg lupb_array_mm[] = {
589 {"__index", lupb_array_index},
590 {"__len", lupb_array_len},
591 {"__newindex", lupb_array_newindex},
596 /* lupb_map *******************************************************************/
598 /* A map object. Implemented by wrapping upb_map.
600 * When the value type is string/bytes/message, the userval consists of:
602 * [Lua number/string] -> [lupb_string/lupb_msg userdata]
604 * For other value types we don't use the userdata.
608 const lupb_msgclass *value_lmsgclass;
612 #define MAP_MSGCLASS_INDEX 0
614 /* lupb_map internal functions */
616 static lupb_map *lupb_map_check(lua_State *L, int narg) {
617 return luaL_checkudata(L, narg, LUPB_ARRAY);
621 * lupb_map_typecheck()
623 * Checks that the lupb_map at index |narg| can be safely assigned to the
624 * field |f| of the message at index |msg|. If so, returns a upb_msgval for
625 * this map. Otherwise, raises a Lua error.
627 static upb_msgval lupb_map_typecheck(lua_State *L, int narg, int msg,
628 const upb_fielddef *f) {
629 lupb_map *lmap = lupb_map_check(L, narg);
630 upb_map *map = lmap->map;
631 const upb_msgdef *entry = upb_fielddef_msgsubdef(f);
632 const upb_fielddef *key_field = upb_msgdef_itof(entry, UPB_MAPENTRY_KEY);
633 const upb_fielddef *value_field = upb_msgdef_itof(entry, UPB_MAPENTRY_VALUE);
635 UPB_ASSERT(entry && key_field && value_field);
637 if (upb_map_keytype(map) != upb_fielddef_type(key_field)) {
638 luaL_error(L, "Map key type invalid");
641 if (upb_map_valuetype(map) != upb_fielddef_type(value_field)) {
642 luaL_error(L, "Map had incorrect value type (expected: %s, got: %s)",
643 upb_fielddef_type(value_field), upb_map_valuetype(map));
646 if (upb_map_valuetype(map) == UPB_TYPE_MESSAGE) {
647 lupb_msgclass_typecheck(
648 L, lupb_msg_msgclassfor(L, msg, upb_fielddef_msgsubdef(value_field)),
649 lmap->value_lmsgclass);
652 return upb_msgval_map(map);
655 /* lupb_map Public API */
661 * new_map = upb.Map(key_type, value_type)
663 static int lupb_map_new(lua_State *L) {
665 upb_fieldtype_t key_type = lupb_checkfieldtype(L, 1);
666 upb_fieldtype_t value_type;
667 const lupb_msgclass *value_lmsgclass = NULL;
669 if (lua_type(L, 2) == LUA_TNUMBER) {
670 value_type = lupb_checkfieldtype(L, 2);
672 value_type = UPB_TYPE_MESSAGE;
675 lmap = lupb_newuserdata(L, sizeof(*lmap), LUPB_MAP);
677 if (value_type == UPB_TYPE_MESSAGE) {
678 value_lmsgclass = lupb_msgclass_check(L, 2);
679 lupb_uservalseti(L, -1, MAP_MSGCLASS_INDEX, 2); /* GC-root lmsgclass. */
682 lmap->value_lmsgclass = value_lmsgclass;
683 lmap->map = upb_map_new(key_type, value_type, lupb_arena_get(L));
694 static int lupb_map_index(lua_State *L) {
695 lupb_map *lmap = lupb_map_check(L, 1);
696 upb_map *map = lmap->map;
697 upb_fieldtype_t valtype = upb_map_valuetype(map);
698 /* We don't always use "key", but this call checks the key type. */
699 upb_msgval key = lupb_tomsgval(L, upb_map_keytype(map), 2, NULL);
701 if (lupb_istypewrapped(valtype)) {
702 /* Userval contains the full map, lookup there by key. */
703 lupb_getuservalue(L, 1);
707 if (lua_isnil(L, -1)) {
708 /* TODO: lazy read from upb_map */
711 /* Lookup in upb_map. */
713 if (upb_map_get(map, key, &val)) {
714 lupb_pushmsgval(L, upb_map_valuetype(map), val);
729 static int lupb_map_len(lua_State *L) {
730 lupb_map *lmap = lupb_map_check(L, 1);
731 lua_pushnumber(L, upb_map_size(lmap->map));
740 * map[key] = nil # to remove from map
742 static int lupb_map_newindex(lua_State *L) {
743 lupb_map *lmap = lupb_map_check(L, 1);
744 upb_map *map = lmap->map;
745 upb_msgval key = lupb_tomsgval(L, upb_map_keytype(map), 2, NULL);
747 if (lua_isnil(L, 3)) {
748 /* Delete from map. */
749 upb_map_del(map, key);
751 if (lupb_istypewrapped(upb_map_valuetype(map))) {
752 /* Delete in userval. */
753 lupb_getuservalue(L, 1);
762 lupb_tomsgval(L, upb_map_valuetype(map), 3, lmap->value_lmsgclass);
764 upb_map_set(map, key, val, NULL);
766 if (lupb_istypewrapped(upb_map_valuetype(map))) {
767 /* Set in userval. */
768 lupb_getuservalue(L, 1);
779 /* upb_mapiter [[[ */
781 static int lupb_mapiter_next(lua_State *L) {
782 upb_mapiter *i = lua_touserdata(L, lua_upvalueindex(1));
783 lupb_map *lmap = lupb_map_check(L, 1);
784 upb_map *map = lmap->map;
786 if (upb_mapiter_done(i)) {
790 lupb_pushmsgval(L, upb_map_keytype(map), upb_mapiter_key(i));
791 lupb_pushmsgval(L, upb_map_valuetype(map), upb_mapiter_value(i));
797 static int lupb_map_pairs(lua_State *L) {
798 lupb_map *lmap = lupb_map_check(L, 1);
800 if (lupb_istypewrapped(upb_map_keytype(lmap->map)) ||
801 lupb_istypewrapped(upb_map_valuetype(lmap->map))) {
802 /* Complex key or value type.
803 * Sync upb_map to userval if necessary, then iterate over userval. */
805 /* TODO: Lua tables don't know how many entries they have, gah!. */
808 /* Simple key and value type, iterate over the upb_map directly. */
809 upb_mapiter *i = lua_newuserdata(L, upb_mapiter_sizeof());
811 upb_mapiter_begin(i, lmap->map);
814 /* Upvalues are [upb_mapiter, lupb_map]. */
815 lua_pushcclosure(L, &lupb_mapiter_next, 2);
821 /* upb_mapiter ]]] */
823 static const struct luaL_Reg lupb_map_mm[] = {
824 {"__index", lupb_map_index},
825 {"__len", lupb_map_len},
826 {"__newindex", lupb_map_newindex},
827 {"__pairs", lupb_map_pairs},
832 /* lupb_msg *******************************************************************/
834 /* A message object. Implemented by wrapping upb_msg.
836 * Our userval contains:
838 * - [0] -> our message class
839 * - [lupb_fieldindex(f)] -> [lupb_{string,array,map,msg} userdata]
841 * Fields with scalar number/bool types don't go in the userval.
844 #define LUPB_MSG_MSGCLASSINDEX 0
845 #define LUPB_MSG_ARENA -1
847 int lupb_fieldindex(const upb_fielddef *f) {
848 return upb_fielddef_index(f) + 1; /* 1-based Lua arrays. */
853 const lupb_msgclass *lmsgclass;
857 /* lupb_msg helpers */
859 static bool in_userval(const upb_fielddef *f) {
860 return lupb_istypewrapped(upb_fielddef_type(f)) || upb_fielddef_isseq(f) ||
861 upb_fielddef_ismap(f);
864 lupb_msg *lupb_msg_check(lua_State *L, int narg) {
865 lupb_msg *msg = luaL_checkudata(L, narg, LUPB_MSG);
866 if (!msg->lmsgclass) luaL_error(L, "called into dead msg");
870 const upb_msg *lupb_msg_checkmsg(lua_State *L, int narg,
871 const lupb_msgclass *lmsgclass) {
872 lupb_msg *lmsg = lupb_msg_check(L, narg);
873 lupb_msgclass_typecheck(L, lmsgclass, lmsg->lmsgclass);
877 upb_msg *lupb_msg_checkmsg2(lua_State *L, int narg,
878 const upb_msglayout **layout) {
879 lupb_msg *lmsg = lupb_msg_check(L, narg);
880 *layout = lmsg->lmsgclass->layout;
884 const upb_msgdef *lupb_msg_checkdef(lua_State *L, int narg) {
885 return lupb_msg_check(L, narg)->lmsgclass->msgdef;
888 static const upb_fielddef *lupb_msg_checkfield(lua_State *L,
892 const char *fieldname = luaL_checklstring(L, fieldarg, &len);
893 const upb_msgdef *msgdef = msg->lmsgclass->msgdef;
894 const upb_fielddef *f = upb_msgdef_ntof(msgdef, fieldname, len);
897 const char *msg = lua_pushfstring(L, "no such field: %s", fieldname);
898 luaL_argerror(L, fieldarg, msg);
899 return NULL; /* Never reached. */
905 static const lupb_msgclass *lupb_msg_msgclassfor(lua_State *L, int narg,
906 const upb_msgdef *md) {
907 lupb_uservalgeti(L, narg, LUPB_MSG_MSGCLASSINDEX);
908 return lupb_msgclass_msgclassfor(L, -1, md);
911 static const lupb_msgclass *lupb_msg_getsubmsgclass(lua_State *L, int narg,
912 const upb_fielddef *f) {
913 lupb_uservalgeti(L, narg, LUPB_MSG_MSGCLASSINDEX);
914 return lupb_msgclass_getsubmsgclass(L, -1, f);
917 int lupb_msg_pushref(lua_State *L, int msgclass, upb_msg *msg) {
918 const lupb_msgclass *lmsgclass = lupb_msgclass_check(L, msgclass);
919 lupb_msg *lmsg = lupb_newuserdata(L, sizeof(lupb_msg), LUPB_MSG);
921 lmsg->lmsgclass = lmsgclass;
924 lupb_uservalseti(L, -1, LUPB_MSG_MSGCLASSINDEX, msgclass);
925 lupb_uservalseti(L, -1, LUPB_MSG_ARENA, -2);
930 /* lupb_msg Public API */
936 * new_msg = MessageClass()
938 static int lupb_msg_pushnew(lua_State *L, int narg) {
939 const lupb_msgclass *lmsgclass = lupb_msgclass_check(L, narg);
940 lupb_msg *lmsg = lupb_newuserdata(L, sizeof(lupb_msg), LUPB_MSG);
942 lmsg->lmsgclass = lmsgclass;
943 lmsg->msg = upb_msg_new(lmsgclass->layout, lupb_arena_get(L));
945 lupb_uservalseti(L, -1, LUPB_MSG_MSGCLASSINDEX, narg);
956 * msg[field_descriptor] # (for extensions) (TODO)
958 static int lupb_msg_index(lua_State *L) {
959 lupb_msg *lmsg = lupb_msg_check(L, 1);
960 const upb_fielddef *f = lupb_msg_checkfield(L, lmsg, 2);
961 const upb_msglayout *l = lmsg->lmsgclass->layout;
962 int field_index = upb_fielddef_index(f);
965 lupb_uservalgeti(L, 1, lupb_fieldindex(f));
967 if (lua_isnil(L, -1)) {
968 /* Check if we need to lazily create wrapper. */
969 if (upb_fielddef_isseq(f)) {
971 } else if (upb_fielddef_issubmsg(f)) {
974 UPB_ASSERT(upb_fielddef_isstring(f));
975 if (upb_msg_has(lmsg->msg, field_index, l)) {
976 upb_msgval val = upb_msg_get(lmsg->msg, field_index, l);
978 lua_pushlstring(L, val.str.data, val.str.size);
979 lupb_uservalseti(L, 1, lupb_fieldindex(f), -1);
984 upb_msgval val = upb_msg_get(lmsg->msg, field_index, l);
985 lupb_pushmsgval(L, upb_fielddef_type(f), val);
992 * lupb_msg_newindex()
997 * msg[field_descriptor] = bar # (for extensions) (TODO)
999 static int lupb_msg_newindex(lua_State *L) {
1000 lupb_msg *lmsg = lupb_msg_check(L, 1);
1001 const upb_fielddef *f = lupb_msg_checkfield(L, lmsg, 2);
1002 upb_fieldtype_t type = upb_fielddef_type(f);
1003 int field_index = upb_fielddef_index(f);
1006 /* Typecheck and get msgval. */
1008 if (upb_fielddef_isseq(f)) {
1009 msgval = lupb_array_typecheck(L, 3, 1, f);
1010 } else if (upb_fielddef_ismap(f)) {
1011 msgval = lupb_map_typecheck(L, 3, 1, f);
1013 const lupb_msgclass *lmsgclass = NULL;
1015 if (type == UPB_TYPE_MESSAGE) {
1016 lmsgclass = lupb_msg_getsubmsgclass(L, 1, f);
1019 msgval = lupb_tomsgval(L, type, 3, lmsgclass);
1022 /* Set in upb_msg and userval (if necessary). */
1024 upb_msg_set(lmsg->msg, field_index, msgval, lmsg->lmsgclass->layout);
1026 if (in_userval(f)) {
1027 lupb_uservalseti(L, 1, lupb_fieldindex(f), 3);
1030 return 0; /* 1 for chained assignments? */
1033 static const struct luaL_Reg lupb_msg_mm[] = {
1034 {"__index", lupb_msg_index},
1035 {"__newindex", lupb_msg_newindex},
1040 /* lupb_msg toplevel **********************************************************/
1042 static const struct luaL_Reg lupb_msg_toplevel_m[] = {
1043 {"Array", lupb_array_new},
1044 {"Map", lupb_map_new},
1045 {"MessageFactory", lupb_msgfactory_new},
1049 void lupb_msg_registertypes(lua_State *L) {
1050 lupb_setfuncs(L, lupb_msg_toplevel_m);
1052 lupb_register_type(L, LUPB_ARENA, NULL, lupb_arena_mm);
1053 lupb_register_type(L, LUPB_MSGCLASS, NULL, lupb_msgclass_mm);
1054 lupb_register_type(L, LUPB_MSGFACTORY, lupb_msgfactory_m, lupb_msgfactory_mm);
1055 lupb_register_type(L, LUPB_ARRAY, NULL, lupb_array_mm);
1056 lupb_register_type(L, LUPB_MAP, NULL, lupb_map_mm);
1057 lupb_register_type(L, LUPB_MSG, NULL, lupb_msg_mm);
1059 lupb_arena_initsingleton(L);