[tarantool-patches] Re: [PATCH v9 4/7] lua: remove exceptions from function luaL_tofield()
Vladislav Shpilevoy
v.shpilevoy at tarantool.org
Thu Mar 28 21:40:00 MSK 2019
Thanks for the fixes! I've pushed my review fixes on the
branch, and dropped at the end of the email. But I've not
tested them, so I propose you to do that, if you agree
with the concept.
=========================================================
diff --git a/src/lua/utils.c b/src/lua/utils.c
index 6150e84ff..38245a979 100644
--- a/src/lua/utils.c
+++ b/src/lua/utils.c
@@ -399,47 +399,58 @@ lua_field_inspect_ucdata(struct lua_State *L, struct luaL_serializer *cfg,
}
/**
- * Check that the field LUAL_SERIALIZE of the metatable is
- * available. If so, create field using it.
- *
- * This function returns two values on stack. On top of the stack
- * is boolean that shows if error happened. On the next position
- * can be boolean or result of execution of function from the
- * metatable. If it is boolean, that if its value is false than
- * there were no metatables.It its value is true than there was
- * string in that field of metatable.
- *
- * @param L Lua State.
+ * A helper structure to simplify safe call of __serialize method.
+ * It passes some arguments into the serializer called via pcall,
+ * and carries out some results.
+ */
+struct lua_serialize_status {
+ /**
+ * True if an attempt to call __serialize has failed. A
+ * diag message is set.
+ */
+ bool is_error;
+ /**
+ * True, if __serialize exists. Otherwise an ordinary
+ * default serialization is used.
+ */
+ bool is_serialize_used;
+ /** Parameters, passed originally to luaL_tofield. */
+ struct luaL_serializer *cfg;
+ struct luaL_field *field;
+};
+
+/**
+ * Call __serialize method of a table object if the former exists.
+ * The function expects 2 values pushed onto the Lua stack: a
+ * value to serialize, and a pointer at a struct
+ * lua_serialize_status object. If __serialize exists and is
+ * correct, then one value is pushed as a result of serialization.
+ * Otherwise is_error and is_serialize_used attributes of status
+ * should be checked.
*/
static int
-get_metafield_serialize(struct lua_State *L)
+lua_field_try_serialize(struct lua_State *L)
{
- if (luaL_getmetafield(L, 1, LUAL_SERIALIZE) == 0) {
- lua_pushboolean(L, false);
- lua_pushboolean(L, false);
- return 2;
- }
- bool is_error = false;
- struct luaL_serializer *cfg =
- (struct luaL_serializer *)lua_touserdata(L, 2);
- struct luaL_field *field =
- (struct luaL_field *)lua_touserdata(L, 3);
-
+ struct lua_serialize_status *s =
+ (struct lua_serialize_status *) lua_touserdata(L, 2);
+ s->is_serialize_used = (luaL_getmetafield(L, 1, LUAL_SERIALIZE) != 0);
+ s->is_error = false;
+ if (! s->is_serialize_used)
+ return 0;
+ struct luaL_serializer *cfg = s->cfg;
+ struct luaL_field *field = s->field;
if (lua_isfunction(L, -1)) {
/* copy object itself */
lua_pushvalue(L, 1);
lua_call(L, 1, 1);
- is_error = (luaL_tofield(L, cfg, -1, field) != 0);
- lua_pushboolean(L, is_error);
- return 2;
+ s->is_error = (luaL_tofield(L, cfg, -1, field) != 0);
+ return s->is_error ? 0 : 1;
}
-
if (!lua_isstring(L, -1)) {
diag_set(LuajitError, "invalid " LUAL_SERIALIZE " value");
- lua_pushboolean(L, true);
- return 2;
+ s->is_error = true;
+ return 0;
}
-
const char *type = lua_tostring(L, -1);
if (strcmp(type, "array") == 0 || strcmp(type, "seq") == 0 ||
strcmp(type, "sequence") == 0) {
@@ -449,9 +460,7 @@ get_metafield_serialize(struct lua_State *L)
if (cfg->has_compact && type[3] == '\0')
field->compact = true;
lua_pop(L, 1); /* type */
- lua_pushboolean(L, true);
- lua_pushboolean(L, false);
- return 2;
+ return 1;
} else if (strcmp(type, "map") == 0 || strcmp(type, "mapping") == 0) {
field->type = MP_MAP; /* Override type */
field->size = luaL_maplen(L, 1);
@@ -459,13 +468,11 @@ get_metafield_serialize(struct lua_State *L)
if (cfg->has_compact && type[3] == '\0')
field->compact = true;
lua_pop(L, 1); /* type */
- lua_pushboolean(L, true);
- lua_pushboolean(L, false);
- return 2;
+ return 1;
} else {
diag_set(LuajitError, "invalid " LUAL_SERIALIZE " value");
- lua_pushboolean(L, true);
- return 2;
+ s->is_error = true;
+ return 0;
}
}
@@ -478,27 +485,19 @@ lua_field_inspect_table(struct lua_State *L, struct luaL_serializer *cfg,
uint32_t max = 0;
if (cfg->encode_load_metatables) {
- lua_pushcfunction(L, get_metafield_serialize);
+ struct lua_serialize_status s;
+ s.cfg = cfg;
+ s.field = field;
+ lua_pushcfunction(L, lua_field_try_serialize);
lua_pushvalue(L, idx);
- lua_pushlightuserdata(L, cfg);
- lua_pushlightuserdata(L, field);
- if (lua_pcall(L, 3, 2, 0) != 0) {
+ lua_pushlightuserdata(L, &s);
+ if (lua_pcall(L, 2, 1, 0) != 0) {
diag_set(LuajitError, lua_tostring(L, -1));
return -1;
}
- bool is_error = lua_toboolean(L, -1);
- bool is_bool = lua_isboolean(L, -2);
- if (is_error) {
- lua_pop(L, 2);
+ if (s.is_error)
return -1;
- }
- if (is_bool) {
- bool is_metatable_available = lua_toboolean(L, -2);
- lua_pop(L, 2);
- if (is_metatable_available)
- return 0;
- } else {
- lua_pop(L, 1);
+ if (s.is_serialize_used) {
lua_replace(L, idx);
return 0;
}
More information about the Tarantool-patches
mailing list