diff --git a/include/fluent-bit/flb_lua.h b/include/fluent-bit/flb_lua.h index a578b00deae..ada88dbca5b 100644 --- a/include/fluent-bit/flb_lua.h +++ b/include/fluent-bit/flb_lua.h @@ -36,7 +36,8 @@ enum flb_lua_l2c_type_enum { FLB_LUA_L2C_TYPE_INT, - FLB_LUA_L2C_TYPE_ARRAY + FLB_LUA_L2C_TYPE_ARRAY, + FLB_LUA_L2C_TYPE_MAP }; struct flb_lua_l2c_type { @@ -50,6 +51,27 @@ struct flb_lua_l2c_config { struct mk_list l2c_types; /* data types (lua -> C) */ }; + +/* + * Metatable for Lua table. + * https://www.lua.org/manual/5.1/manual.html#2.8 + */ +struct flb_lua_metadata { + int initialized; + int data_type; /* Map or Array */ +}; + +static inline int flb_lua_metadata_init(struct flb_lua_metadata *meta) +{ + if (meta == NULL) { + return -1; + } + meta->initialized = FLB_TRUE; + meta->data_type = -1; + + return 0; +} + /* convert from negative index to positive index */ static inline int flb_lua_absindex(lua_State *l , int index) { diff --git a/src/flb_lua.c b/src/flb_lua.c index 3b3af4926b8..e4df896c515 100644 --- a/src/flb_lua.c +++ b/src/flb_lua.c @@ -64,12 +64,35 @@ int flb_lua_is_valid_func(lua_State *lua, flb_sds_t func) return ret; } +static int flb_lua_setmetatable(lua_State *l, struct flb_lua_metadata *meta, int index) +{ + int abs_index; + + if (meta->initialized != FLB_TRUE) { + return -1; + } + abs_index = flb_lua_absindex(l, index); + + lua_createtable(l, 0, 1); + + /* data type */ + lua_pushlstring(l, "type", 4); + lua_pushinteger(l, meta->data_type); + lua_settable(l, -3); /* point created table */ + + lua_setmetatable(l, abs_index); + + return 0; +} + int flb_lua_pushmpack(lua_State *l, mpack_reader_t *reader) { int ret = 0; mpack_tag_t tag; uint32_t length; uint32_t i; + int index; + struct flb_lua_metadata meta; tag = mpack_read_tag(reader); switch (mpack_tag_type(&tag)) { @@ -99,8 +122,12 @@ int flb_lua_pushmpack(lua_State *l, mpack_reader_t *reader) reader->data += length; break; case mpack_type_array: + flb_lua_metadata_init(&meta); + meta.data_type = FLB_LUA_L2C_TYPE_ARRAY; + length = mpack_tag_array_count(&tag); lua_createtable(l, length, 0); + index = lua_gettop(l); /* save index of created table */ for (i = 0; i < length; i++) { ret = flb_lua_pushmpack(l, reader); if (ret) { @@ -108,10 +135,16 @@ int flb_lua_pushmpack(lua_State *l, mpack_reader_t *reader) } lua_rawseti(l, -2, i+1); } + flb_lua_setmetatable(l, &meta, index); + break; case mpack_type_map: + flb_lua_metadata_init(&meta); + meta.data_type = FLB_LUA_L2C_TYPE_MAP; + length = mpack_tag_map_count(&tag); lua_createtable(l, length, 0); + index = lua_gettop(l); /* save index of created table */ for (i = 0; i < length; i++) { ret = flb_lua_pushmpack(l, reader); if (ret) { @@ -123,6 +156,8 @@ int flb_lua_pushmpack(lua_State *l, mpack_reader_t *reader) } lua_settable(l, -3); } + flb_lua_setmetatable(l, &meta, index); + break; default: return -1; @@ -134,6 +169,8 @@ void flb_lua_pushmsgpack(lua_State *l, msgpack_object *o) { int i; int size; + int index; + struct flb_lua_metadata meta; lua_checkstack(l, 3); @@ -172,28 +209,38 @@ void flb_lua_pushmsgpack(lua_State *l, msgpack_object *o) break; case MSGPACK_OBJECT_ARRAY: + flb_lua_metadata_init(&meta); + meta.data_type = FLB_LUA_L2C_TYPE_ARRAY; + size = o->via.array.size; lua_createtable(l, size, 0); + index = lua_gettop(l); /* save index of created table */ if (size != 0) { msgpack_object *p = o->via.array.ptr; for (i = 0; i < size; i++) { flb_lua_pushmsgpack(l, p+i); - lua_rawseti (l, -2, i+1); + lua_rawseti (l, index, i+1); } } + flb_lua_setmetatable(l, &meta, index); break; case MSGPACK_OBJECT_MAP: + flb_lua_metadata_init(&meta); + meta.data_type = FLB_LUA_L2C_TYPE_MAP; + size = o->via.map.size; lua_createtable(l, 0, size); + index = lua_gettop(l); /* save index of created table */ if (size != 0) { msgpack_object_kv *p = o->via.map.ptr; for (i = 0; i < size; i++) { flb_lua_pushmsgpack(l, &(p+i)->key); flb_lua_pushmsgpack(l, &(p+i)->val); - lua_settable(l, -3); + lua_settable(l, index); } } + flb_lua_setmetatable(l, &meta, index); break; } } @@ -288,10 +335,10 @@ int flb_lua_arraylength(lua_State *l, int index) return max; } -static void lua_toarray(lua_State *l, - msgpack_packer *pck, - int index, - struct flb_lua_l2c_config *l2cc) +static void lua_toarray_msgpack(lua_State *l, + msgpack_packer *pck, + int index, + struct flb_lua_l2c_config *l2cc) { int len; int i; @@ -330,7 +377,6 @@ static void lua_toarray_mpack(lua_State *l, static void try_to_convert_data_type(lua_State *l, msgpack_packer *pck, - int index, struct flb_lua_l2c_config *l2cc) { size_t len; @@ -362,7 +408,7 @@ static void try_to_convert_data_type(lua_State *l, l2c = mk_list_entry(head, struct flb_lua_l2c_type, _head); if (!strncmp(l2c->key, tmp, len) && l2c->type == FLB_LUA_L2C_TYPE_ARRAY) { flb_lua_tomsgpack(l, pck, -1, l2cc); - lua_toarray(l, pck, 0, l2cc); + lua_toarray_msgpack(l, pck, 0, l2cc); return; } } @@ -375,7 +421,6 @@ static void try_to_convert_data_type(lua_State *l, static void try_to_convert_data_type_mpack(lua_State *l, mpack_writer_t *writer, - int index, struct flb_lua_l2c_config *l2cc) { size_t len; @@ -418,6 +463,89 @@ static void try_to_convert_data_type_mpack(lua_State *l, flb_lua_tompack(l, writer, 0, l2cc); } +static int flb_lua_getmetatable(lua_State *l, int index, struct flb_lua_metadata *meta) +{ + int lua_ret; + int abs_index; + const char *str; + size_t len; + + if (meta->initialized != FLB_TRUE) { + return -1; + } + + lua_ret = lua_getmetatable(l, index); + if (lua_ret == 0) { + /* no metadata */ + return -1; + } + else if (lua_type(l, -1) != LUA_TTABLE) { + /* invalid metatable? */ + lua_pop(l, 1); + return -1; + } + + lua_pushnil(l); + abs_index = flb_lua_absindex(l, -2); + while (lua_next(l, abs_index) != 0) { + if (lua_type(l, -2) != LUA_TSTRING) { + /* key is not a string */ + flb_debug("key is not a string"); + lua_pop(l, 1); + continue; + } + + str = lua_tolstring(l, -2, &len); /* key */ + + if (len == 4 && strncmp(str, "type", 4) == 0) { + /* data_type */ + if (lua_type(l, -1) != LUA_TNUMBER) { + /* value is not data type */ + flb_debug("type is not num. type=%s", lua_typename(l, lua_type(l, -1))); + lua_pop(l, 1); + continue; + } + meta->data_type = (int)lua_tointeger(l, -1); + } + lua_pop(l, 1); + } + lua_pop(l, 1); /* pop metatable */ + + return 0; +} + +static void lua_tomap_mpack(lua_State *l, + mpack_writer_t *writer, + int index, + struct flb_lua_l2c_config *l2cc) +{ + int len; + + len = 0; + lua_pushnil(l); + while (lua_next(l, -2) != 0) { + lua_pop(l, 1); + len++; + } + mpack_write_tag(writer, mpack_tag_map(len)); + + lua_pushnil(l); + + if (l2cc->l2c_types_num > 0) { + /* type conversion */ + while (lua_next(l, -2) != 0) { + try_to_convert_data_type_mpack(l, writer, l2cc); + lua_pop(l, 1); + } + } else { + while (lua_next(l, -2) != 0) { + flb_lua_tompack(l, writer, -1, l2cc); + flb_lua_tompack(l, writer, 0, l2cc); + lua_pop(l, 1); + } + } +} + void flb_lua_tompack(lua_State *l, mpack_writer_t *writer, int index, @@ -425,6 +553,8 @@ void flb_lua_tompack(lua_State *l, { int len; int i; + int use_metatable = FLB_FALSE; + struct flb_lua_metadata meta; switch (lua_type(l, -1 + index)) { case LUA_TSTRING: @@ -456,6 +586,23 @@ void flb_lua_tompack(lua_State *l, mpack_write_false(writer); break; case LUA_TTABLE: + flb_lua_metadata_init(&meta); + if (flb_lua_getmetatable(l, -1 + index, &meta) == 0 && + meta.data_type >= 0) { + use_metatable = FLB_TRUE; + } + if (use_metatable) { + if (meta.data_type == FLB_LUA_L2C_TYPE_ARRAY) { + /* array */ + lua_toarray_mpack(l, writer, 0, l2cc); + } + else { + /* map */ + lua_tomap_mpack(l, writer, -1 + index, l2cc); + } + break; + } + len = flb_lua_arraylength(l, -1 + index); if (len > 0) { mpack_write_tag(writer, mpack_tag_array(len)); @@ -464,31 +611,9 @@ void flb_lua_tompack(lua_State *l, flb_lua_tompack(l, writer, 0, l2cc); lua_pop(l, 1); } - } else - { - len = 0; - lua_pushnil(l); - while (lua_next(l, -2) != 0) { - lua_pop(l, 1); - len++; - } - mpack_write_tag(writer, mpack_tag_map(len)); - - lua_pushnil(l); - - if (l2cc->l2c_types_num > 0) { - /* type conversion */ - while (lua_next(l, -2) != 0) { - try_to_convert_data_type_mpack(l, writer, index, l2cc); - lua_pop(l, 1); - } - } else { - while (lua_next(l, -2) != 0) { - flb_lua_tompack(l, writer, -1, l2cc); - flb_lua_tompack(l, writer, 0, l2cc); - lua_pop(l, 1); - } - } + } + else { + lua_tomap_mpack(l, writer, -1 + index, l2cc); } break; case LUA_TNIL: @@ -508,6 +633,41 @@ void flb_lua_tompack(lua_State *l, } } +static inline void lua_tomap_msgpack(lua_State *l, + msgpack_packer *pck, + int index, + struct flb_lua_l2c_config *l2cc) +{ + int len; + int abs_index; + + abs_index = flb_lua_absindex(l, index); + + len = 0; + lua_pushnil(l); + while (lua_next(l, abs_index) != 0) { + lua_pop(l, 1); + len++; + } + msgpack_pack_map(pck, len); + + lua_pushnil(l); + + if (l2cc->l2c_types_num > 0) { + /* type conversion */ + while (lua_next(l, abs_index) != 0) { + try_to_convert_data_type(l, pck, l2cc); + lua_pop(l, 1); + } + } else { + while (lua_next(l, abs_index) != 0) { + flb_lua_tomsgpack(l, pck, -1, l2cc); + flb_lua_tomsgpack(l, pck, 0, l2cc); + lua_pop(l, 1); + } + } +} + void flb_lua_tomsgpack(lua_State *l, msgpack_packer *pck, int index, @@ -515,6 +675,8 @@ void flb_lua_tomsgpack(lua_State *l, { int len; int i; + int use_metatable = FLB_FALSE; + struct flb_lua_metadata meta; switch (lua_type(l, -1 + index)) { case LUA_TSTRING: @@ -547,6 +709,23 @@ void flb_lua_tomsgpack(lua_State *l, msgpack_pack_false(pck); break; case LUA_TTABLE: + flb_lua_metadata_init(&meta); + if (flb_lua_getmetatable(l, -1 + index, &meta) == 0 && + meta.data_type >= 0) { + use_metatable = FLB_TRUE; + } + if (use_metatable) { + if (meta.data_type == FLB_LUA_L2C_TYPE_ARRAY) { + /* array */ + lua_toarray_msgpack(l, pck, 0, l2cc); + } + else { + /* map */ + lua_tomap_msgpack(l, pck, -1 + index, l2cc); + } + break; + } + len = flb_lua_arraylength(l, -1 + index); if (len > 0) { msgpack_pack_array(pck, len); @@ -555,31 +734,9 @@ void flb_lua_tomsgpack(lua_State *l, flb_lua_tomsgpack(l, pck, 0, l2cc); lua_pop(l, 1); } - } else - { - len = 0; - lua_pushnil(l); - while (lua_next(l, -2) != 0) { - lua_pop(l, 1); - len++; - } - msgpack_pack_map(pck, len); - - lua_pushnil(l); - - if (l2cc->l2c_types_num > 0) { - /* type conversion */ - while (lua_next(l, -2) != 0) { - try_to_convert_data_type(l, pck, index, l2cc); - lua_pop(l, 1); - } - } else { - while (lua_next(l, -2) != 0) { - flb_lua_tomsgpack(l, pck, -1, l2cc); - flb_lua_tomsgpack(l, pck, 0, l2cc); - lua_pop(l, 1); - } - } + } + else { + lua_tomap_msgpack(l, pck, -1 + index, l2cc); } break; case LUA_TNIL: