diff --git a/test/box/misc.result b/test/box/misc.result index 9488a70b35931f6ac1d4f0ea478dd63f2ec24e4b..911d71b10de00be32ce8d9b249f1cd5b5f64471c 100644 --- a/test/box/misc.result +++ b/test/box/misc.result @@ -477,3 +477,105 @@ space:delete{1} space:drop() --- ... +---------------- +-- # yaml encode/decode on cdata +---------------- +ffi = require('ffi') +--- +... +ffi.new('uint8_t', 128) +--- +- 128 +... +ffi.new('int8_t', -128) +--- +- -128 +... +ffi.new('uint16_t', 128) +--- +- 128 +... +ffi.new('int16_t', -128) +--- +- -128 +... +ffi.new('uint32_t', 128) +--- +- 128 +... +ffi.new('int32_t', -128) +--- +- -128 +... +ffi.new('uint64_t', 128) +--- +- 128 +... +ffi.new('int64_t', -128) +--- +- -128 +... +ffi.new('char', 128) +--- +- -128 +... +ffi.new('char', -128) +--- +- -128 +... +ffi.new('bool', true) +--- +- true +... +ffi.new('bool', false) +--- +- false +... +ffi.new('float', 1.23456) +--- +- 1.2345600128174 +... +ffi.new('float', 1e10) +--- +- 10000000000 +... +ffi.new('double', 1.23456) +--- +- 1.23456 +... +ffi.new('double', 1e10) +--- +- 10000000000 +... +ffi.cast('void *', 0) +--- +- null +... +ffi.cast('void *', 0xabcdef) +--- +- 'cdata<void *>: 0x00abcdef' +... +ffi.cdef([[struct test { int a; }; ]]) +--- +... +ffi.cast('struct test *', 0) +--- +- 'cdata<struct test *>: NULL' +... +--# setopt delimiter ';' +type(ffi.metatype('struct test', { + __index = { + totable = function(test) + return { 'yaml totable test = ' .. test.a } + end + } +})); +--- +- cdata +... +--# setopt delimiter '' +-- custom totable function will be called by yaml.encode +ffi.new('struct test', { a = 15 }) +--- +- - yaml totable test = 15 +... diff --git a/test/box/misc.test.lua b/test/box/misc.test.lua index dd96ea48662bdd8762bcb0857ece41bf743ebf6f..df3f2bfacabb91cfc08a50c782f0087618742ecf 100644 --- a/test/box/misc.test.lua +++ b/test/box/misc.test.lua @@ -147,3 +147,47 @@ fifo_top(space, 1) space:delete{1} space:drop() + +---------------- +-- # yaml encode/decode on cdata +---------------- + +ffi = require('ffi') + +ffi.new('uint8_t', 128) +ffi.new('int8_t', -128) +ffi.new('uint16_t', 128) +ffi.new('int16_t', -128) +ffi.new('uint32_t', 128) +ffi.new('int32_t', -128) +ffi.new('uint64_t', 128) +ffi.new('int64_t', -128) + +ffi.new('char', 128) +ffi.new('char', -128) +ffi.new('bool', true) +ffi.new('bool', false) + +ffi.new('float', 1.23456) +ffi.new('float', 1e10) +ffi.new('double', 1.23456) +ffi.new('double', 1e10) + +ffi.cast('void *', 0) +ffi.cast('void *', 0xabcdef) + +ffi.cdef([[struct test { int a; }; ]]) +ffi.cast('struct test *', 0) + +--# setopt delimiter ';' +type(ffi.metatype('struct test', { + __index = { + totable = function(test) + return { 'yaml totable test = ' .. test.a } + end + } +})); + +--# setopt delimiter '' +-- custom totable function will be called by yaml.encode +ffi.new('struct test', { a = 15 }) diff --git a/third_party/lua-yaml/lyaml.cc b/third_party/lua-yaml/lyaml.cc index c462b3a64499827a8cd54fbc898a405a128583bc..b94ab2a013f94306ae599cdeea6a953353d35344 100644 --- a/third_party/lua-yaml/lyaml.cc +++ b/third_party/lua-yaml/lyaml.cc @@ -560,20 +560,29 @@ dump_node(struct lua_yaml_dumper *dumper) int type = lua_type(dumper->L, top); if (field.type == MP_EXT && (type == LUA_TUSERDATA || type == LUA_TCDATA)) { - /* has metatable, try to call 'totable' and use return value */ - lua_getfield(dumper->L, top, "totable"); - if (lua_isfunction(dumper->L, -1)) { - lua_pushvalue(dumper->L, top); /* copy object itself */ - lua_call(dumper->L, 1, 1); - lua_replace(dumper->L, top); - luaL_tofield(dumper->L, -1, &field); - } else { - lua_pop(dumper->L, 1); /* pop result */ + /* try to call 'totable' method on udata/cdata */ + try { + /* + * LuaJIT specific: lua_getfield raises exception on + * cdata objects if field doesn't exist. + */ + lua_getfield(dumper->L, top, "totable"); + if (lua_isfunction(dumper->L, -1)) { + /* copy object itself */ + lua_pushvalue(dumper->L, top); + lua_call(dumper->L, 1, 1); + if (lua_istable(dumper->L, -1)) { + /* replace obj with the unpacked table*/ + lua_replace(dumper->L, top); + luaL_tofield(dumper->L, -1, &field); + } + } + } catch (...) { + /* ignore lua_getfield exceptions */ } + lua_settop(dumper->L, top); /* remove temporary objects */ } - luaL_tofield(dumper->L, top, &field); - /* Still have unknown type on the stack, * try to call 'tostring' */ if (field.type == MP_EXT) {