Skip to content

Commit

Permalink
Add support for importing objects from other LuaNativeObject modules.
Browse files Browse the repository at this point in the history
  • Loading branch information
Neopallium committed Oct 13, 2012
1 parent 6a00eba commit 6a409d6
Show file tree
Hide file tree
Showing 5 changed files with 258 additions and 4 deletions.
22 changes: 22 additions & 0 deletions native_objects.lua
Expand Up @@ -249,6 +249,28 @@ function object(name)
end
end

function import_object(mod)
return function (name)
return function (rec)
rec = rec or {}
local userdata_type = rec.userdata_type or 'generic'
rec.userdata_type = userdata_type
if userdata_type == 'generic' or userdata_type == 'embed' or userdata_type == 'simple ptr' then
ctype(name .. " *", rec,"import_object")
rec.is_ptr = true
rec.name = name
-- map the c_type to this record
new_c_type(name, rec)
else
ctype(name, rec, "import_object")
end
-- external module name.
rec.mod_name = mod
return rec
end
end
end

function interface(name)
return function (rec)
local rec = ctype(name, rec,"interface")
Expand Down
145 changes: 144 additions & 1 deletion native_objects/gen_lua.lua
Expand Up @@ -144,6 +144,7 @@ typedef void (*dyn_caster_t)(void **obj, obj_type **type);
#define OBJ_TYPE_FLAG_WEAK_REF (1<<0)
#define OBJ_TYPE_SIMPLE (1<<1)
#define OBJ_TYPE_IMPORT (1<<2)
struct obj_type {
dyn_caster_t dcaster; /**< caster to support casting to sub-objects. */
int32_t id; /**< type's id. */
Expand Down Expand Up @@ -249,6 +250,48 @@ local objHelperFunc = [[
#define OBJ_DATA_HIDDEN_METATABLE 1
#endif
static FUNC_UNUSED int obj_import_external_type(lua_State *L, obj_type *type) {
/* find the external type's metatable using it's name. */
lua_pushstring(L, type->name);
lua_rawget(L, LUA_REGISTRYINDEX); /* external type's metatable. */
if(!lua_isnil(L, -1)) {
/* found it. Now we will map our 'type' pointer to the metatable. */
/* REGISTERY[lightuserdata<type>] = REGISTERY[type->name] */
lua_pushlightuserdata(L, type); /* use our 'type' pointer as lookup key. */
lua_pushvalue(L, -2); /* dup. type's metatable. */
lua_rawset(L, LUA_REGISTRYINDEX); /* save external type's metatable. */
/* NOTE: top of Lua stack still has the type's metatable. */
return 1;
} else {
lua_pop(L, 1); /* pop nil. */
}
return 0;
}
static FUNC_UNUSED int obj_import_external_ffi_type(lua_State *L, obj_type *type) {
/* find the external type's metatable using it's name. */
lua_pushstring(L, type->name);
lua_rawget(L, LUA_REGISTRYINDEX); /* external type's metatable. */
if(!lua_isnil(L, -1)) {
/* found it. Now we will map our 'type' pointer to the C check function. */
/* _priv_table[lightuserdata<type>] = REGISTERY[type->name].c_check */
lua_getfield(L, -1, "c_check");
lua_remove(L, -2); /* remove metatable. */
if(lua_isfunction(L, -1)) {
lua_pushlightuserdata(L, type); /* use our 'type' pointer as lookup key. */
lua_pushvalue(L, -2); /* dup. check function */
lua_rawset(L, -4); /* save check function to module's private table. */
/* NOTE: top of Lua stack still has the type's C check function. */
return 1;
} else {
lua_pop(L, 1); /* pop non function value. */
}
} else {
lua_pop(L, 1); /* pop nil. */
}
return 0;
}
static FUNC_UNUSED obj_udata *obj_udata_toobj(lua_State *L, int _index) {
obj_udata *ud;
size_t len;
Expand All @@ -272,10 +315,23 @@ static FUNC_UNUSED int obj_udata_is_compatible(lua_State *L, obj_udata *ud, void
obj_type *ud_type;
lua_pushlightuserdata(L, type);
lua_rawget(L, LUA_REGISTRYINDEX); /* type's metatable. */
recheck_metatable:
if(lua_rawequal(L, -1, -2)) {
*obj = ud->obj;
/* same type no casting needed. */
return 1;
} else if(lua_isnil(L, -1)) {
lua_pop(L, 1); /* pop nil. */
if((type->flags & OBJ_TYPE_IMPORT) == 0) {
/* can't resolve internal type. */
luaL_error(L, "Unknown object type(id=%d, name=%s)", type->id, type->name);
}
/* try to import external type. */
if(obj_import_external_type(L, type)) {
/* imported type, re-try metatable check. */
goto recheck_metatable;
}
/* External type not yet available, so the object can't be compatible. */
} else {
/* Different types see if we can cast to the required type. */
lua_rawgeti(L, -2, type->id);
Expand Down Expand Up @@ -339,6 +395,7 @@ static FUNC_UNUSED obj_udata *obj_udata_luacheck_internal(lua_State *L, int _ind
/* check for function. */
if(!lua_isnil(L, -1)) {
got_check_func:
/* pass cdata value to type checking function. */
lua_pushvalue(L, _index);
lua_call(L, 1, 1);
Expand All @@ -350,7 +407,15 @@ static FUNC_UNUSED obj_udata *obj_udata_luacheck_internal(lua_State *L, int _ind
}
lua_pop(L, 2);
} else {
lua_pop(L, 1);
lua_pop(L, 1); /* pop nil. */
if(type->flags & OBJ_TYPE_IMPORT) {
/* try to import external ffi type. */
if(obj_import_external_ffi_type(L, type)) {
/* imported type. */
goto got_check_func;
}
/* External type not yet available, so the object can't be compatible. */
}
}
}
if(not_delete) {
Expand Down Expand Up @@ -552,9 +617,23 @@ static FUNC_UNUSED void * obj_simple_udata_luacheck(lua_State *L, int _index, ob
if(lua_getmetatable(L, _index)) {
lua_pushlightuserdata(L, type);
lua_rawget(L, LUA_REGISTRYINDEX); /* type's metatable. */
recheck_metatable:
if(lua_rawequal(L, -1, -2)) {
lua_pop(L, 2); /* pop both metatables. */
return ud;
} else if(lua_isnil(L, -1)) {
lua_pop(L, 1); /* pop nil. */
if((type->flags & OBJ_TYPE_IMPORT) == 0) {
/* can't resolve internal type. */
luaL_error(L, "Unknown object type(id=%d, name=%s)", type->id, type->name);
}
/* try to import external type. */
if(obj_import_external_type(L, type)) {
/* imported type, re-try metatable check. */
goto recheck_metatable;
}
/* External type not yet available, so the object can't be compatible. */
return 0;
}
}
} else if(!lua_isnoneornil(L, _index)) {
Expand All @@ -568,6 +647,7 @@ static FUNC_UNUSED void * obj_simple_udata_luacheck(lua_State *L, int _index, ob
/* check for function. */
if(!lua_isnil(L, -1)) {
got_check_func:
/* pass cdata value to type checking function. */
lua_pushvalue(L, _index);
lua_call(L, 1, 1);
Expand All @@ -576,6 +656,15 @@ static FUNC_UNUSED void * obj_simple_udata_luacheck(lua_State *L, int _index, ob
lua_pop(L, 2);
return (void *)lua_topointer(L, _index);
}
} else {
if(type->flags & OBJ_TYPE_IMPORT) {
/* try to import external ffi type. */
if(obj_import_external_ffi_type(L, type)) {
/* imported type. */
goto got_check_func;
}
/* External type not yet available, so the object can't be compatible. */
}
}
}
luaL_typerror(L, _index, type->name); /* is not a userdata value. */
Expand Down Expand Up @@ -1094,6 +1183,40 @@ static void obj_type_register_implements(lua_State *L, const reg_impl *impls) {
]]

-- template for imported type *_check macros.
local obj_import_type_check = {
['simple'] = [[
#define obj_type_${object_name}_check(L, _index) \
*((${object_name} *)obj_simple_udata_luacheck(L, _index, &(obj_type_${object_name})))
#define obj_type_${object_name}_optional(L, _index) \
*((${object_name} *)obj_simple_udata_luaoptional(L, _index, &(obj_type_${object_name})))
]],
['simple ptr'] = [[
#define obj_type_${object_name}_check(L, _index) \
*((${object_name} **)obj_simple_udata_luacheck(L, _index, &(obj_type_${object_name})))
#define obj_type_${object_name}_optional(L, _index) \
*((${object_name} **)obj_simple_udata_luaoptional(L, _index, &(obj_type_${object_name})))
]],
['embed'] = [[
#define obj_type_${object_name}_check(L, _index) \
(${object_name} *)obj_simple_udata_luacheck(L, _index, &(obj_type_${object_name}))
#define obj_type_${object_name}_optional(L, _index) \
(${object_name} *)obj_simple_udata_luaoptional(L, _index, &(obj_type_${object_name}))
]],
['object id'] = [[
#define obj_type_${object_name}_check(L, _index) \
(${object_name})(uintptr_t)obj_udata_luacheck(L, _index, &(obj_type_${object_name}))
#define obj_type_${object_name}_optional(L, _index) \
(${object_name})(uintptr_t)obj_udata_luaoptional(L, _index, &(obj_type_${object_name}))
]],
['generic'] = [[
#define obj_type_${object_name}_check(L, _index) \
obj_udata_luacheck(L, _index, &(obj_type_${object_name}))
#define obj_type_${object_name}_optional(L, _index) \
obj_udata_luaoptional(L, _index, &(obj_type_${object_name}))
]],
}

-- templates for typed *_check/*_delete/*_push macros.
local obj_type_check_delete_push = {
['simple'] = [[
Expand Down Expand Up @@ -1755,6 +1878,26 @@ object_end = function(self, rec, parent)
parent:copy_parts(rec, parts)

end,
import_object_end = function(self, rec, parent)
rec:add_var('object_name', rec.name)
-- create check/delete/push macros
local ud_type = rec.userdata_type
rec:write_part("obj_check_delete_push", {
obj_import_type_check[ud_type],
'\n'
})

-- build obj_type info.
rec:write_part('obj_types', {
'#define obj_type_id_${object_name} ', rec._obj_id, '\n',
'#define ', rec._obj_type_name, ' (obj_types[obj_type_id_${object_name}])\n',
' { NULL, ', rec._obj_id , ', OBJ_TYPE_IMPORT, "${object_name}" },\n'
})
-- copy parts to parent
local parts = { "obj_types", "obj_check_delete_push" }
rec:vars_parts(parts)
parent:copy_parts(rec, parts)
end,
callback_state = function(self, rec, parent)
rec:add_var('wrap_type', rec.wrap_type)
rec:add_var('base_type', rec.base_type)
Expand Down
51 changes: 48 additions & 3 deletions native_objects/gen_lua_ffi.lua
Expand Up @@ -375,15 +375,19 @@ do
end
-- type checking function for C API.
_priv[obj_type] = function(obj)
local function c_check(obj)
if ffi.istype(obj_ctype, obj) then return obj._wrapped_val end
return nil
end
_priv[obj_type] = c_check
-- push function for C API.
reg_table[obj_type] = function(ptr)
return obj_type_${object_name}_push(ffi.cast("${object_name} *", ptr)[0])
end
-- export check functions for use in other modules.
obj_mt.c_check = c_check
obj_mt.ffi_check = obj_type_${object_name}_check
end
]],
Expand Down Expand Up @@ -427,15 +431,19 @@ do
end
-- type checking function for C API.
_priv[obj_type] = function(ptr)
local function c_check(ptr)
if ffi.istype(obj_ctype, ptr) then return ptr end
return nil
end
_priv[obj_type] = c_check
-- push function for C API.
reg_table[obj_type] = function(ptr)
return obj_type_${object_name}_push(ffi.cast(obj_ctype, ptr)[0])
end
-- export check functions for use in other modules.
obj_mt.c_check = c_check
obj_mt.ffi_check = obj_type_${object_name}_check
end
]],
Expand Down Expand Up @@ -471,17 +479,21 @@ do
end
-- type checking function for C API.
_priv[obj_type] = function(obj)
local function c_check(obj)
if ffi.istype(obj_type, obj) then return obj end
return nil
end
_priv[obj_type] = c_check
-- push function for C API.
reg_table[obj_type] = function(ptr)
local obj = obj_ctype()
ffi.copy(obj, ptr, ${object_name}_sizeof);
return obj
end
-- export check functions for use in other modules.
obj_mt.c_check = c_check
obj_mt.ffi_check = obj_type_${object_name}_check
end
]],
Expand Down Expand Up @@ -546,6 +558,9 @@ do
return obj_type_${object_name}_push(ffi.cast('uintptr_t',ptr), flags)
end
-- export check functions for use in other modules.
obj_mt.c_check = obj_type_${object_name}_check
obj_mt.ffi_check = obj_type_${object_name}_check
end
]],
Expand Down Expand Up @@ -599,6 +614,9 @@ ${dyn_caster}
return obj_type_${object_name}_push(ffi.cast(obj_ctype,ptr), flags)
end
-- export check functions for use in other modules.
obj_mt.c_check = obj_type_${object_name}_check
obj_mt.ffi_check = obj_type_${object_name}_check
end
]],
Expand Down Expand Up @@ -655,6 +673,9 @@ ${dyn_caster}
return obj_type_${object_name}_push(ffi.cast(obj_ctype,ptr), flags)
end
-- export check functions for use in other modules.
obj_mt.c_check = obj_type_${object_name}_check
obj_mt.ffi_check = obj_type_${object_name}_check
end
]],
Expand Down Expand Up @@ -1203,6 +1224,30 @@ object_end = function(self, rec, parent)
end

end,
import_object_end = function(self, rec, parent)
rec:add_var('object_name', rec.name)
-- create FFI check functions
rec:write_part("ffi_obj_type", [[
local function obj_type_${object_name}_check(obj)
-- try to import FFI check function from external module.
local mt = reg_table['${object_name}']
if mt then
local ffi_check = mt.ffi_check
if ffi_check then
obj_type_${object_name}_check = ffi_check
return ffi_check(obj)
end
end
return error("Expected '${object_name}'", 2)
end
]])

-- copy parts to parent
local ffi_parts = { "ffi_obj_type" }
rec:vars_parts(ffi_parts)
parent:copy_parts(rec, ffi_parts)
end,
callback_state = function(self, rec, parent)
rec:add_var('wrap_type', rec.wrap_type)
rec:add_var('base_type', rec.base_type)
Expand Down

0 comments on commit 6a409d6

Please sign in to comment.