/** * lupb_msg_index * * Handles: * msg.foo * msg["foo"] * msg[field_descriptor] # (for extensions) (TODO) */ static int lupb_msg_index(lua_State *L) { lupb_msg *lmsg = lupb_msg_check(L, 1); const upb_fielddef *f = lupb_msg_checkfield(L, lmsg, 2); const upb_msglayout *l = lmsg->lmsgclass->layout; if (in_userval(f)) { lupb_uservalgeti(L, 1, lupb_fieldindex(f)); if (lua_isnil(L, -1)) { /* Check if we need to lazily create wrapper. */ if (upb_fielddef_isseq(f)) { /* TODO(haberman) */ } else if (upb_fielddef_issubmsg(f)) { /* TODO(haberman) */ } else { UPB_ASSERT(upb_fielddef_isstring(f)); if (upb_msg_has(lmsg->msg, f, l)) { upb_msgval val = upb_msg_get(lmsg->msg, f, l); lua_pop(L, 1); lua_pushlstring(L, val.str.ptr, val.str.len); lupb_uservalseti(L, 1, lupb_fieldindex(f), -1); } } } } else { lupb_pushmsgval(L, upb_fielddef_type(f), upb_msg_get(lmsg->msg, f, l)); } return 1; }
/** * lupb_map_typecheck() * * Checks that the lupb_map at index |narg| can be safely assigned to the * field |f| of the message at index |msg|. If so, returns a upb_msgval for * this map. Otherwise, raises a Lua error. */ static upb_msgval lupb_map_typecheck(lua_State *L, int narg, int msg, const upb_fielddef *f) { lupb_map *lmap = lupb_map_check(L, narg); upb_map *map = lmap->map; const upb_msgdef *entry = upb_fielddef_msgsubdef(f); const upb_fielddef *key_field = upb_msgdef_itof(entry, UPB_MAPENTRY_KEY); const upb_fielddef *value_field = upb_msgdef_itof(entry, UPB_MAPENTRY_VALUE); UPB_ASSERT(entry && key_field && value_field); if (upb_map_keytype(map) != upb_fielddef_type(key_field)) { luaL_error(L, "Map key type invalid"); } if (upb_map_valuetype(map) != upb_fielddef_type(value_field)) { luaL_error(L, "Map had incorrect value type (expected: %s, got: %s)", upb_fielddef_type(value_field), upb_map_valuetype(map)); } if (upb_map_valuetype(map) == UPB_TYPE_MESSAGE) { lupb_msgclass_typecheck( L, lupb_msg_msgclassfor(L, msg, upb_fielddef_msgsubdef(value_field)), lmap->value_lmsgclass); } return upb_msgval_map(map); }
bool upb_array_set(upb_array *arr, size_t i, upb_msgval val) { size_t element_size = upb_msgval_sizeof(arr->type); UPB_ASSERT(i <= arr->len); if (i == arr->len) { /* Extending the array. */ if (i == arr->size) { /* Need to reallocate. */ size_t new_size = UPB_MAX(arr->size * 2, 8); size_t new_bytes = new_size * element_size; size_t old_bytes = arr->size * element_size; upb_alloc *alloc = upb_arena_alloc(arr->arena); upb_msgval *new_data = upb_realloc(alloc, arr->data, old_bytes, new_bytes); if (!new_data) { return false; } arr->data = new_data; arr->size = new_size; } arr->len = i + 1; } upb_msgval_write(arr->data, i * element_size, val, element_size); return true; }
static upb_msgval lupb_tomsgval(lua_State *L, upb_fieldtype_t type, int narg, const lupb_msgclass *lmsgclass) { switch (type) { case UPB_TYPE_INT32: case UPB_TYPE_ENUM: return upb_msgval_int32(lupb_checkint32(L, narg)); case UPB_TYPE_INT64: return upb_msgval_int64(lupb_checkint64(L, narg)); case UPB_TYPE_UINT32: return upb_msgval_uint32(lupb_checkuint32(L, narg)); case UPB_TYPE_UINT64: return upb_msgval_uint64(lupb_checkuint64(L, narg)); case UPB_TYPE_DOUBLE: return upb_msgval_double(lupb_checkdouble(L, narg)); case UPB_TYPE_FLOAT: return upb_msgval_float(lupb_checkfloat(L, narg)); case UPB_TYPE_BOOL: return upb_msgval_bool(lupb_checkbool(L, narg)); case UPB_TYPE_STRING: case UPB_TYPE_BYTES: { size_t len; const char *ptr = lupb_checkstring(L, narg, &len); return upb_msgval_str(ptr, len); } case UPB_TYPE_MESSAGE: UPB_ASSERT(lmsgclass); return upb_msgval_msg(lupb_msg_checkmsg(L, narg, lmsgclass)); } UPB_UNREACHABLE(); }
bool putf(upb_textprinter *p, const char *fmt, ...) { va_list args; va_list args_copy; char *str; int written; int len; bool ok; va_start(args, fmt); /* Run once to get the length of the string. */ _upb_va_copy(args_copy, args); len = _upb_vsnprintf(NULL, 0, fmt, args_copy); va_end(args_copy); /* + 1 for NULL terminator (vsprintf() requires it even if we don't). */ str = upb_gmalloc(len + 1); if (!str) return false; written = vsprintf(str, fmt, args); va_end(args); UPB_ASSERT(written == len); ok = upb_bytessink_putbuf(p->output_, p->subc, str, len, NULL); upb_gfree(str); return ok; }
static int lupb_msgclass_pushnew(lua_State *L, int factory, const upb_msglayout *l) { const lupb_msgfactory *lfactory = lupb_msgfactory_check(L, factory); lupb_msgclass *lmc = lupb_newuserdata(L, sizeof(*lmc), LUPB_MSGCLASS); UPB_ASSERT(l); lupb_uservalseti(L, -1, LUPB_MSGCLASS_FACTORY, factory); lmc->layout = l; lmc->lfactory = lfactory; return 1; }
/* Returns the global lupb_alloc func that was created in our luaopen(). * Callers can be guaranteed that it will be alive as long as |L| is. */ static upb_alloc *lupb_alloc_get(lua_State *L) { lupb_alloc *lalloc; lua_pushlightuserdata(L, &lupb_alloc_cache_key); lua_gettable(L, LUA_REGISTRYINDEX); lalloc = lua_touserdata(L, -1); UPB_ASSERT(lalloc); lua_pop(L, 1); return &lalloc->alloc; }
/* Pushes a new userdata with the given metatable. */ static void *lupb_newuserdata(lua_State *L, size_t size, const char *type) { void *ret = lua_newuserdata(L, size); /* Set metatable. */ luaL_getmetatable(L, type); UPB_ASSERT(!lua_isnil(L, -1)); /* Should have been created by luaopen_upb. */ lua_setmetatable(L, -2); /* We don't set a uservalue here -- we lazily create it later if necessary. */ return ret; }
const upb_msglayout *upb_msgfactory_getlayout(upb_msgfactory *f, const upb_msgdef *m) { upb_value v; UPB_ASSERT(upb_symtab_lookupmsg(f->symtab, upb_msgdef_fullname(m)) == m); UPB_ASSERT(!upb_msgdef_mapentry(m)); if (upb_inttable_lookupptr(&f->layouts, m, &v)) { UPB_ASSERT(upb_value_getptr(v)); return upb_value_getptr(v); } else { /* In case of circular dependency, layout has to be inserted first. */ upb_msglayout *l = upb_gmalloc(sizeof(*l)); upb_msgfactory *mutable_f = (void*)f; upb_inttable_insertptr(&mutable_f->layouts, m, upb_value_ptr(l)); UPB_ASSERT(l); if (!upb_msglayout_init(m, l, f)) { upb_msglayout_free(l); } return l; } }
static upb_ctype_t upb_fieldtotabtype(upb_fieldtype_t type) { switch (type) { case UPB_TYPE_FLOAT: return UPB_CTYPE_FLOAT; case UPB_TYPE_DOUBLE: return UPB_CTYPE_DOUBLE; case UPB_TYPE_BOOL: return UPB_CTYPE_BOOL; case UPB_TYPE_BYTES: case UPB_TYPE_MESSAGE: case UPB_TYPE_STRING: return UPB_CTYPE_CONSTPTR; case UPB_TYPE_ENUM: case UPB_TYPE_INT32: return UPB_CTYPE_INT32; case UPB_TYPE_UINT32: return UPB_CTYPE_UINT32; case UPB_TYPE_INT64: return UPB_CTYPE_INT64; case UPB_TYPE_UINT64: return UPB_CTYPE_UINT64; default: UPB_ASSERT(false); return 0; } }
bool upb_msg_has(const upb_msg *msg, int field_index, const upb_msglayout *l) { const upb_msglayout_field *field = upb_msg_checkfield(field_index, l); UPB_ASSERT(field->presence); if (upb_msg_inoneof(field)) { /* Oneofs are set when the oneof number is set to this field. */ return *upb_msg_oneofcase(msg, field_index, l) == field->number; } else { /* Other fields are set when their hasbit is set. */ uint32_t hasbit = field->presence; return DEREF(msg, hasbit / 8, char) | (1 << (hasbit % 8)); } }
upb_map *upb_map_new(upb_fieldtype_t ktype, upb_fieldtype_t vtype, upb_arena *a) { upb_ctype_t vtabtype = upb_fieldtotabtype(vtype); upb_alloc *alloc = upb_arena_alloc(a); upb_map *map = upb_malloc(alloc, sizeof(upb_map)); if (!map) { return NULL; } UPB_ASSERT(upb_fieldtype_mapkeyok(ktype)); map->key_type = ktype; map->val_type = vtype; map->arena = a; if (!upb_strtable_init2(&map->strtab, vtabtype, alloc)) { return NULL; } return map; }
upb_msgval upb_array_get(const upb_array *arr, size_t i) { size_t element_size = upb_msgval_sizeof(arr->type); UPB_ASSERT(i < arr->len); return upb_msgval_read(arr->data, i * element_size, element_size); }
static uint32_t *upb_msg_oneofcase(const upb_msg *msg, int field_index, const upb_msglayout *l) { const upb_msglayout_field *field = upb_msg_checkfield(field_index, l); UPB_ASSERT(upb_msg_inoneof(field)); return PTR_AT(msg, ~field->presence, uint32_t); }
static const upb_msglayout_field *upb_msg_checkfield(int field_index, const upb_msglayout *l) { UPB_ASSERT(field_index >= 0 && field_index < l->field_count); return &l->fields[field_index]; }
/* Align up to the given power of 2. */ static size_t align_up(size_t val, size_t align) { UPB_ASSERT(is_power_of_two(align)); return (val + align - 1) & ~(align - 1); }