You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

110 lines
3.0 KiB
Lua

local base = string.match(..., "(.-)[^%.]+%.[^%.]+$")
local eh = require(base.."helper.enum")
local ffi = require("ffi")
local mth = require(base.."helper.mt")
local assert, error, pairs, select, type = assert, error, pairs, select, type
local getmetatable, setmetatable = getmetatable, setmetatable
local e_to_str, e_to_int = eh.to_str, eh.to_int
local ffi_copy = ffi.copy
local module = {}
local base_funcs = {}
function base_funcs:set_from_table(tbl)
for k,v in pairs(tbl) do
assert(k ~= "raw", "Can't set raw key")
self[k] = v
end
end
module.base_funcs = base_funcs
function module.base(mt, index, ct)
if type(ct) == "string" then ct = ffi.typeof(ct) end
index.struct_name = tostring(ct):match("ctype<struct (.*)>")
local size = ffi.sizeof(ct)
index.raw_struct_size = size
function index.clone(stuff)
local t = type(stuff)
if t == "cdata" then
return setmetatable({raw = ct(stuff)}, mt)
elseif t == "table" then
assert(getmetatable(stuff) == mt, "Wrong type")
return setmetatable({raw = ct(stuff.raw)}, mt)
end
end
local function new(...)
if select('#', ...) ~= 1 then
return setmetatable({raw = ct(...)}, mt)
end
local stuff = ...
local t = type(stuff)
local res
if t == "nil" then
res = setmetatable({raw = ct()}, mt)
elseif t == "cdata" then
res = setmetatable({raw = stuff}, mt)
elseif t == "table" and stuff.raw then
if getmetatable(stuff) ~= mt then
error("Wrong type "..tostring(stuff), 2)
end
res = stuff
elseif t == "table" then
res = setmetatable({raw = ct()}, mt)
res:set_from_table(stuff)
elseif t == "string" then
if #stuff ~= size then
error("String size mismatch (expected: "..size..", got: "..#stuff..")")
end
local x = ct()
ffi_copy(x, stuff, size)
res = setmetatable({raw = x}, mt)
else
error("Bad argument to ffi_struct constructor: "..t)
end
return res
end
index.new = new
setmetatable(index, {
__index = base_funcs,
__call = function(_, ...) return new(...) end,
})
mth.add_index_methods(mt, index)
return index
end
function module.gen_raw_accessor(index, name)
index["get_"..name] = function(self) return self.raw[name] end
index["set_"..name] = function(self, val) self.raw[name] = val end
end
function module.gen_wrap_accessor(index, name, wrap)
index["get_"..name] = function(self) return wrap(self.raw[name]) end
index["set_"..name] = function(self, ...) self.raw[name] = wrap(...).raw end
end
local function gen_enum_getter(index, enum, name)
index["get_"..name] = function(self)
return e_to_str(enum, self.raw[name])
end
end
module.gen_enum_getter = gen_enum_getter
local function gen_enum_setter(index, enum, name)
index["set_"..name] = function(self, val)
self.raw[name] = e_to_int(enum, val)
end
end
module.gen_enum_setter = gen_enum_setter
function module.gen_enum_accessor(index, enum, name)
gen_enum_getter(index, enum, name)
gen_enum_setter(index, enum, name)
end
return module