Implemented upb_enumvaldef, for storing information about enumvals.
diff --git a/tests/bindings/lua/test_upb.lua b/tests/bindings/lua/test_upb.lua
index 9846897..5f1aae8 100644
--- a/tests/bindings/lua/test_upb.lua
+++ b/tests/bindings/lua/test_upb.lua
@@ -91,7 +91,7 @@
-- enum
local e = test_messages_proto3['TestAllTypesProto3.NestedEnum']
assert_true(#e > 3 and #e < 10)
- assert_equal(2, e:value("BAZ"))
+ assert_equal(2, e:value("BAZ"):number())
end
function test_msg_map()
@@ -717,6 +717,30 @@
assert_nil(symtab:lookup_msg("ABC"))
end
+function test_duplicate_enumval()
+ local symtab = upb.SymbolTable()
+ local file_proto = descriptor.FileDescriptorProto {
+ name = "test.proto",
+ message_type = upb.Array(descriptor.DescriptorProto, {
+ descriptor.DescriptorProto{
+ name = "ABC",
+ },
+ }),
+ enum_type = upb.Array(descriptor.EnumDescriptorProto, {
+ descriptor.EnumDescriptorProto{
+ name = "MyEnum",
+ value = upb.Array(descriptor.EnumValueDescriptorProto, {
+ descriptor.EnumValueDescriptorProto{
+ name = "ABC",
+ number = 1,
+ }
+ }),
+ },
+ })
+ }
+ assert_error(function () symtab:add_file(upb.encode(file_proto)) end)
+end
+
function test_duplicate_filename_error()
local symtab = upb.SymbolTable()
local file = descriptor.FileDescriptorProto()
diff --git a/upb/bindings/lua/def.c b/upb/bindings/lua/def.c
index 54923e4..a481e9a 100644
--- a/upb/bindings/lua/def.c
+++ b/upb/bindings/lua/def.c
@@ -34,6 +34,7 @@
#include "upb/def.h"
#define LUPB_ENUMDEF "lupb.enumdef"
+#define LUPB_ENUMVALDEF "lupb.enumvaldef"
#define LUPB_FIELDDEF "lupb.fielddef"
#define LUPB_FILEDEF "lupb.filedef"
#define LUPB_MSGDEF "lupb.msgdef"
@@ -568,29 +569,20 @@
/* lupb_enumdef_value()
*
* Handles:
- * enum.value(number) -> name
- * enum.value(name) -> number
+ * enum.value(number) -> enumval
+ * enum.value(name) -> enumval
*/
static int lupb_enumdef_value(lua_State *L) {
const upb_enumdef *e = lupb_enumdef_check(L, 1);
+ const upb_enumvaldef *ev;
switch (lua_type(L, 2)) {
- case LUA_TNUMBER: {
- int32_t key = lupb_checkint32(L, 2);
- /* Pushes "nil" for a NULL pointer. */
- lua_pushstring(L, upb_enumdef_iton(e, key));
+ case LUA_TNUMBER:
+ ev = upb_enumdef_lookupnum(e, lupb_checkint32(L, 2));
break;
- }
- case LUA_TSTRING: {
- const char *key = lua_tostring(L, 2);
- int32_t num;
- if (upb_enumdef_ntoiz(e, key, &num)) {
- lua_pushinteger(L, num);
- } else {
- lua_pushnil(L);
- }
+ case LUA_TSTRING:
+ ev = upb_enumdef_lookupnamez(e, lua_tostring(L, 2));
break;
- }
default: {
const char *msg = lua_pushfstring(L, "number or string expected, got %s",
luaL_typename(L, 2));
@@ -598,6 +590,7 @@
}
}
+ lupb_wrapper_pushwrapper(L, 1, ev, LUPB_ENUMVALDEF);
return 1;
}
@@ -634,6 +627,45 @@
};
+/* lupb_enumvaldef ************************************************************/
+
+const upb_enumvaldef *lupb_enumvaldef_check(lua_State *L, int narg) {
+ return lupb_wrapper_check(L, narg, LUPB_ENUMVALDEF);
+}
+
+static int lupb_enumvaldef_enum(lua_State *L) {
+ const upb_enumvaldef *ev = lupb_enumvaldef_check(L, 1);
+ const upb_enumdef *e = upb_enumvaldef_enum(ev);
+ lupb_wrapper_pushwrapper(L, 1, e, LUPB_ENUMDEF);
+ return 1;
+}
+
+static int lupb_enumvaldef_fullname(lua_State *L) {
+ const upb_enumvaldef *ev = lupb_enumvaldef_check(L, 1);
+ lua_pushstring(L, upb_enumvaldef_fullname(ev));
+ return 1;
+}
+
+static int lupb_enumvaldef_name(lua_State *L) {
+ const upb_enumvaldef *ev = lupb_enumvaldef_check(L, 1);
+ lua_pushstring(L, upb_enumvaldef_name(ev));
+ return 1;
+}
+
+static int lupb_enumvaldef_number(lua_State *L) {
+ const upb_enumvaldef *ev = lupb_enumvaldef_check(L, 1);
+ lupb_pushint32(L, upb_enumvaldef_number(ev));
+ return 1;
+}
+
+static const struct luaL_Reg lupb_enumvaldef_m[] = {
+ {"enum", lupb_enumvaldef_enum},
+ {"full_name", lupb_enumvaldef_fullname},
+ {"name", lupb_enumvaldef_name},
+ {"number", lupb_enumvaldef_number},
+ {NULL, NULL}
+};
+
/* lupb_filedef ***************************************************************/
const upb_filedef *lupb_filedef_check(lua_State *L, int narg) {
@@ -875,6 +907,13 @@
return 1;
}
+static int lupb_symtab_lookupenumval(lua_State *L) {
+ const upb_symtab *s = lupb_symtab_check(L, 1);
+ const upb_enumvaldef *e = upb_symtab_lookupenumval(s, luaL_checkstring(L, 2));
+ lupb_symtab_pushwrapper(L, 1, e, LUPB_ENUMVALDEF);
+ return 1;
+}
+
static int lupb_symtab_tostring(lua_State *L) {
const upb_symtab *s = lupb_symtab_check(L, 1);
lua_pushfstring(L, "<upb.SymbolTable file_count=%d>",
@@ -887,6 +926,7 @@
{"add_set", lupb_symtab_addset},
{"lookup_msg", lupb_symtab_lookupmsg},
{"lookup_enum", lupb_symtab_lookupenum},
+ {"lookup_enumval", lupb_symtab_lookupenumval},
{NULL, NULL}
};
@@ -913,6 +953,7 @@
/* Register types. */
lupb_register_type(L, LUPB_ENUMDEF, lupb_enumdef_m, lupb_enumdef_mm);
+ lupb_register_type(L, LUPB_ENUMVALDEF, lupb_enumvaldef_m, NULL);
lupb_register_type(L, LUPB_FIELDDEF, lupb_fielddef_m, NULL);
lupb_register_type(L, LUPB_FILEDEF, lupb_filedef_m, NULL);
lupb_register_type(L, LUPB_MSGDEF, lupb_msgdef_m, lupb_msgdef_mm);
diff --git a/upb/bindings/lua/msg.c b/upb/bindings/lua/msg.c
index 6210e39..1b4d9ef 100644
--- a/upb/bindings/lua/msg.c
+++ b/upb/bindings/lua/msg.c
@@ -390,6 +390,7 @@
* Array(message_type)
*/
static int lupb_array_new(lua_State *L) {
+ int arg_count = lua_gettop(L);
lupb_array *larray;
upb_arena *arena;
@@ -411,6 +412,17 @@
larray->arr = upb_array_new(arena, larray->type);
lupb_cacheset(L, larray->arr);
+ if (arg_count > 1) {
+ /* Set initial fields from table. */
+ int msg = arg_count + 1;
+ lua_pushnil(L);
+ while (lua_next(L, 2) != 0) {
+ lua_pushvalue(L, -2); /* now stack is key, val, key */
+ lua_insert(L, -3); /* now stack is key, key, val */
+ lua_settable(L, msg);
+ }
+ }
+
return 1;
}
diff --git a/upb/def.c b/upb/def.c
index 641f1b4..a08a05b 100644
--- a/upb/def.c
+++ b/upb/def.c
@@ -101,9 +101,17 @@
const char *full_name;
upb_strtable ntoi;
upb_inttable iton;
+ const upb_enumvaldef *values;
+ int value_count;
int32_t defaultval;
};
+struct upb_enumvaldef {
+ const upb_enumdef *enum_;
+ const char *full_name;
+ int32_t number;
+};
+
struct upb_oneofdef {
const upb_msgdef *parent;
const char *full_name;
@@ -147,6 +155,7 @@
/* Only inside symtab table. */
UPB_DEFTYPE_MSG = 1,
UPB_DEFTYPE_ENUM = 2,
+ UPB_DEFTYPE_ENUMVAL = 3,
/* Only inside message table. */
UPB_DEFTYPE_ONEOF = 1,
@@ -270,10 +279,31 @@
}
int32_t upb_enumdef_default(const upb_enumdef *e) {
- UPB_ASSERT(upb_enumdef_iton(e, e->defaultval));
+ UPB_ASSERT(upb_enumdef_lookupnum(e, e->defaultval));
return e->defaultval;
}
+const upb_enumvaldef *upb_enumdef_lookupname(const upb_enumdef *def,
+ const char *name, size_t len) {
+ upb_value v;
+ return upb_strtable_lookup2(&def->ntoi, name, len, &v)
+ ? upb_value_getconstptr(v)
+ : NULL;
+}
+
+const upb_enumvaldef *upb_enumdef_lookupnum(const upb_enumdef *def, int32_t num) {
+ upb_value v;
+ return upb_inttable_lookup(&def->iton, num, &v) ? upb_value_getconstptr(v)
+ : NULL;
+}
+
+const upb_enumvaldef *upb_enumdef_value(const upb_enumdef *e, int i) {
+ UPB_ASSERT(i >= 0 && i < e->value_count);
+ return &e->values[i];
+}
+
+// Deprecated functions.
+
int upb_enumdef_numvals(const upb_enumdef *e) {
return (int)upb_strtable_count(&e->ntoi);
}
@@ -286,21 +316,6 @@
void upb_enum_next(upb_enum_iter *iter) { upb_strtable_next(iter); }
bool upb_enum_done(upb_enum_iter *iter) { return upb_strtable_done(iter); }
-bool upb_enumdef_ntoi(const upb_enumdef *def, const char *name,
- size_t len, int32_t *num) {
- upb_value v;
- if (!upb_strtable_lookup2(&def->ntoi, name, len, &v)) {
- return false;
- }
- if (num) *num = upb_value_getint32(v);
- return true;
-}
-
-const char *upb_enumdef_iton(const upb_enumdef *def, int32_t num) {
- upb_value v;
- return upb_inttable_lookup(&def->iton, num, &v) ? upb_value_getcstr(v) : NULL;
-}
-
const char *upb_enum_iter_name(upb_enum_iter *iter) {
return upb_strtable_iter_key(iter).data;
}
@@ -310,6 +325,25 @@
}
+/* upb_enumvaldef *************************************************************/
+
+const upb_enumdef *upb_enumvaldef_enum(const upb_enumvaldef *ev) {
+ return ev->enum_;
+}
+
+const char *upb_enumvaldef_fullname(const upb_enumvaldef *ev) {
+ return ev->full_name;
+}
+
+const char *upb_enumvaldef_name(const upb_enumvaldef *ev) {
+ return shortdefname(ev->full_name);
+}
+
+int32_t upb_enumvaldef_number(const upb_enumvaldef *ev) {
+ return ev->number;
+}
+
+
/* upb_fielddef ***************************************************************/
const char *upb_fielddef_fullname(const upb_fielddef *f) {
@@ -877,6 +911,14 @@
unpack_def(v, UPB_DEFTYPE_ENUM) : NULL;
}
+const upb_enumvaldef *upb_symtab_lookupenumval(const upb_symtab *s,
+ const char *sym) {
+ upb_value v;
+ return upb_strtable_lookup(&s->syms, sym, &v)
+ ? unpack_def(v, UPB_DEFTYPE_ENUMVAL)
+ : NULL;
+}
+
const upb_filedef *upb_symtab_lookupfile(const upb_symtab *s, const char *name) {
upb_value v;
return upb_strtable_lookup(&s->files, name, &v) ? upb_value_getconstptr(v)
@@ -1217,7 +1259,9 @@
}
static char *strviewdup(symtab_addctx *ctx, upb_strview view) {
- return upb_strdup2(view.data, view.size, ctx->arena);
+ char *ret = upb_strdup2(view.data, view.size, ctx->arena);
+ CHK_OOM(ret);
+ return ret;
}
static bool streql2(const char *a, size_t n, const char *b) {
@@ -1325,6 +1369,8 @@
}
static void symtab_add(symtab_addctx *ctx, const char *name, upb_value v) {
+ // TODO: table should support an operation "tryinsert" to avoid the double
+ // lookup.
if (upb_strtable_lookup(&ctx->symtab->syms, name, NULL)) {
symtab_errf(ctx, "duplicate symbol '%s'", name);
}
@@ -1433,11 +1479,11 @@
}
case UPB_TYPE_ENUM: {
const upb_enumdef *e = f->sub.enumdef;
- int32_t val;
- if (!upb_enumdef_ntoi(e, str, len, &val)) {
+ const upb_enumvaldef *ev = upb_enumdef_lookupname(e, str, len);
+ if (!ev) {
goto invalid;
}
- f->defaultval.sint = val;
+ f->defaultval.sint = ev->number;
break;
}
case UPB_TYPE_INT64: {
@@ -1721,6 +1767,8 @@
e->file = ctx->file;
e->defaultval = 0;
+ e->value_count = 0;
+ e->values = symtab_alloc(ctx, sizeof(*e->values) * n);
if (n == 0) {
symtab_errf(ctx, "enums must contain at least one value (%s)",
@@ -1728,27 +1776,26 @@
}
for (i = 0; i < n; i++) {
- const google_protobuf_EnumValueDescriptorProto *value = values[i];
- upb_strview name = google_protobuf_EnumValueDescriptorProto_name(value);
- char *name2 = strviewdup(ctx, name);
- int32_t num = google_protobuf_EnumValueDescriptorProto_number(value);
- upb_value v = upb_value_int32(num);
+ const google_protobuf_EnumValueDescriptorProto *val_proto = values[i];
+ upb_enumvaldef *val = (upb_enumvaldef*)&e->values[e->value_count++];
+ upb_strview name = google_protobuf_EnumValueDescriptorProto_name(val_proto);
+ upb_value v = upb_value_constptr(val);
- if (i == 0 && e->file->syntax == UPB_SYNTAX_PROTO3 && num != 0) {
+ val->enum_ = e;
+ val->full_name = makefullname(ctx, prefix, name);
+ val->number = google_protobuf_EnumValueDescriptorProto_number(val_proto);
+ symtab_add(ctx, val->full_name, pack_def(val, UPB_DEFTYPE_ENUMVAL));
+
+ if (i == 0 && e->file->syntax == UPB_SYNTAX_PROTO3 && val->number != 0) {
symtab_errf(ctx, "for proto3, the first enum value must be zero (%s)",
e->full_name);
}
- if (upb_strtable_lookup(&e->ntoi, name2, NULL)) {
- symtab_errf(ctx, "duplicate enum label '%s'", name2);
- }
+ CHK_OOM(upb_strtable_insert(&e->ntoi, name.data, name.size, v, ctx->arena));
- CHK_OOM(name2)
- CHK_OOM(upb_strtable_insert(&e->ntoi, name2, strlen(name2), v, ctx->arena));
-
- if (!upb_inttable_lookup(&e->iton, num, NULL)) {
- upb_value v = upb_value_cstr(name2);
- CHK_OOM(upb_inttable_insert(&e->iton, num, v, ctx->arena));
+ // Multiple enumerators can have the same number, first one wins.
+ if (!upb_inttable_lookup(&e->iton, val->number, NULL)) {
+ CHK_OOM(upb_inttable_insert(&e->iton, val->number, v, ctx->arena));
}
}
diff --git a/upb/def.h b/upb/def.h
index 24dc8b3..da31120 100644
--- a/upb/def.h
+++ b/upb/def.h
@@ -54,6 +54,8 @@
struct upb_enumdef;
typedef struct upb_enumdef upb_enumdef;
+struct upb_enumvaldef;
+typedef struct upb_enumvaldef upb_enumvaldef;
struct upb_fielddef;
typedef struct upb_fielddef upb_fielddef;
struct upb_filedef;
@@ -264,26 +266,34 @@
const char *upb_enumdef_name(const upb_enumdef *e);
const upb_filedef *upb_enumdef_file(const upb_enumdef *e);
int32_t upb_enumdef_default(const upb_enumdef *e);
+int upb_enumdef_valuecount(const upb_enumdef *e);
+const upb_enumvaldef *upb_enumdef_value(const upb_enumdef *e, int i);
+
+const upb_enumvaldef *upb_enumdef_lookupname(const upb_enumdef *e,
+ const char *name, size_t len);
+const upb_enumvaldef *upb_enumdef_lookupnum(const upb_enumdef *e, int32_t num);
+
+/* DEPRECATED, slated for removal */
int upb_enumdef_numvals(const upb_enumdef *e);
-
-/* Enum lookups:
- * - ntoi: look up a name with specified length.
- * - ntoiz: look up a name provided as a null-terminated string.
- * - iton: look up an integer, returning the name as a null-terminated
- * string. */
-bool upb_enumdef_ntoi(const upb_enumdef *e, const char *name, size_t len,
- int32_t *num);
-UPB_INLINE bool upb_enumdef_ntoiz(const upb_enumdef *e,
- const char *name, int32_t *num) {
- return upb_enumdef_ntoi(e, name, strlen(name), num);
-}
-const char *upb_enumdef_iton(const upb_enumdef *e, int32_t num);
-
void upb_enum_begin(upb_enum_iter *iter, const upb_enumdef *e);
void upb_enum_next(upb_enum_iter *iter);
bool upb_enum_done(upb_enum_iter *iter);
const char *upb_enum_iter_name(upb_enum_iter *iter);
int32_t upb_enum_iter_number(upb_enum_iter *iter);
+/* END DEPRECATED */
+
+// Convenience wrapper.
+UPB_INLINE const upb_enumvaldef *upb_enumdef_lookupnamez(const upb_enumdef *e,
+ const char *name) {
+ return upb_enumdef_lookupname(e, name, strlen(name));
+}
+
+/* upb_enumvaldef *************************************************************/
+
+const char *upb_enumvaldef_fullname(const upb_enumvaldef *e);
+const char *upb_enumvaldef_name(const upb_enumvaldef *e);
+int32_t upb_enumvaldef_number(const upb_enumvaldef *e);
+const upb_enumdef *upb_enumvaldef_enum(const upb_enumvaldef *e);
/* upb_filedef ****************************************************************/
@@ -308,6 +318,8 @@
const upb_msgdef *upb_symtab_lookupmsg2(
const upb_symtab *s, const char *sym, size_t len);
const upb_enumdef *upb_symtab_lookupenum(const upb_symtab *s, const char *sym);
+const upb_enumvaldef *upb_symtab_lookupenumval(const upb_symtab *s,
+ const char *sym);
const upb_filedef *upb_symtab_lookupfile(const upb_symtab *s, const char *name);
const upb_filedef *upb_symtab_lookupfile2(
const upb_symtab *s, const char *name, size_t len);
diff --git a/upb/def.hpp b/upb/def.hpp
index a253879..48cdcad 100644
--- a/upb/def.hpp
+++ b/upb/def.hpp
@@ -312,6 +312,19 @@
const upb_msgdef* ptr_;
};
+class EnumValDefPtr {
+ public:
+ EnumValDefPtr() : ptr_(nullptr) {}
+ explicit EnumValDefPtr(const upb_enumvaldef* ptr) : ptr_(ptr) {}
+
+ int32_t number() const { return upb_enumvaldef_number(ptr_); }
+ const char *full_name() const { return upb_enumvaldef_fullname(ptr_); }
+ const char *name() const { return upb_enumvaldef_name(ptr_); }
+
+ private:
+ const upb_enumvaldef* ptr_;
+};
+
class EnumDefPtr {
public:
EnumDefPtr() : ptr_(nullptr) {}
@@ -335,15 +348,15 @@
int value_count() const { return upb_enumdef_numvals(ptr_); }
// Lookups from name to integer, returning true if found.
- bool FindValueByName(const char* name, int32_t* num) const {
- return upb_enumdef_ntoiz(ptr_, name, num);
+ const EnumValDefPtr FindValueByName(const char* name) const {
+ return EnumValDefPtr(upb_enumdef_lookupnamez(ptr_, name));
}
// Finds the name corresponding to the given number, or NULL if none was
// found. If more than one name corresponds to this number, returns the
// first one that was added.
- const char* FindValueByNumber(int32_t num) const {
- return upb_enumdef_iton(ptr_, num);
+ const EnumValDefPtr FindValueByNumber(int32_t num) const {
+ return EnumValDefPtr(upb_enumdef_lookupnum(ptr_, num));
}
// Iteration over name/value pairs. The order is undefined.
diff --git a/upb/json_decode.c b/upb/json_decode.c
index b574a17..f7d1c5b 100644
--- a/upb/json_decode.c
+++ b/upb/json_decode.c
@@ -814,10 +814,13 @@
static upb_msgval jsondec_enum(jsondec *d, const upb_fielddef *f) {
switch (jsondec_peek(d)) {
case JD_STRING: {
- const upb_enumdef *e = upb_fielddef_enumsubdef(f);
upb_strview str = jsondec_string(d);
+ const upb_enumdef *e = upb_fielddef_enumsubdef(f);
+ const upb_enumvaldef *ev = upb_enumdef_lookupname(e, str.data, str.size);
upb_msgval val;
- if (!upb_enumdef_ntoi(e, str.data, str.size, &val.int32_val)) {
+ if (ev) {
+ val.int32_val = upb_enumvaldef_number(ev);
+ } else {
if (d->options & UPB_JSONDEC_IGNOREUNKNOWN) {
val.int32_val = 0;
} else {
diff --git a/upb/json_encode.c b/upb/json_encode.c
index 31725cf..b7d6fa9 100644
--- a/upb/json_encode.c
+++ b/upb/json_encode.c
@@ -203,10 +203,10 @@
if (strcmp(upb_enumdef_fullname(e_def), "google.protobuf.NullValue") == 0) {
jsonenc_putstr(e, "null");
} else {
- const char *name = upb_enumdef_iton(e_def, val);
+ const upb_enumvaldef *ev = upb_enumdef_lookupnum(e_def, val);
- if (name) {
- jsonenc_printf(e, "\"%s\"", name);
+ if (ev) {
+ jsonenc_printf(e, "\"%s\"", upb_enumvaldef_name(ev));
} else {
jsonenc_printf(e, "%" PRId32, val);
}
diff --git a/upb/text_encode.c b/upb/text_encode.c
index 6ea2527..12840c0 100644
--- a/upb/text_encode.c
+++ b/upb/text_encode.c
@@ -102,10 +102,10 @@
static void txtenc_enum(int32_t val, const upb_fielddef *f, txtenc *e) {
const upb_enumdef *e_def = upb_fielddef_enumsubdef(f);
- const char *name = upb_enumdef_iton(e_def, val);
+ const upb_enumvaldef *ev = upb_enumdef_lookupnum(e_def, val);
- if (name) {
- txtenc_printf(e, "%s", name);
+ if (ev) {
+ txtenc_printf(e, "%s", upb_enumvaldef_name(ev));
} else {
txtenc_printf(e, "%" PRId32, val);
}