ffi_struct.lua (3117B)
1 local base = string.match(..., "(.-)[^%.]+%.[^%.]+$") 2 local eh = require(base.."helper.enum") 3 local ffi = require("ffi") 4 local mth = require(base.."helper.mt") 5 6 local assert, error, pairs, select, type = assert, error, pairs, select, type 7 local getmetatable, setmetatable = getmetatable, setmetatable 8 local e_to_str, e_to_int = eh.to_str, eh.to_int 9 local ffi_copy = ffi.copy 10 11 local module = {} 12 13 local base_funcs = {} 14 function base_funcs:set_from_table(tbl) 15 for k,v in pairs(tbl) do 16 assert(k ~= "raw", "Can't set raw key") 17 self[k] = v 18 end 19 end 20 module.base_funcs = base_funcs 21 22 function module.base(mt, index, ct) 23 if type(ct) == "string" then ct = ffi.typeof(ct) end 24 index.struct_name = tostring(ct):match("ctype<struct (.*)>") 25 26 local size = ffi.sizeof(ct) 27 index.raw_struct_size = size 28 function index.clone(stuff) 29 local t = type(stuff) 30 if t == "cdata" then 31 return setmetatable({raw = ct(stuff)}, mt) 32 elseif t == "table" then 33 assert(getmetatable(stuff) == mt, "Wrong type") 34 return setmetatable({raw = ct(stuff.raw)}, mt) 35 end 36 end 37 38 local function new(...) 39 if select('#', ...) ~= 1 then 40 return setmetatable({raw = ct(...)}, mt) 41 end 42 43 local stuff = ... 44 local t = type(stuff) 45 local res 46 if t == "nil" then 47 res = setmetatable({raw = ct()}, mt) 48 elseif t == "cdata" then 49 res = setmetatable({raw = stuff}, mt) 50 elseif t == "table" and stuff.raw then 51 if getmetatable(stuff) ~= mt then 52 error("Wrong type "..tostring(stuff), 2) 53 end 54 res = stuff 55 elseif t == "table" then 56 res = setmetatable({raw = ct()}, mt) 57 res:set_from_table(stuff) 58 elseif t == "string" then 59 if #stuff ~= size then 60 error("String size mismatch (expected: "..size..", got: "..#stuff..")") 61 end 62 local x = ct() 63 ffi_copy(x, stuff, size) 64 res = setmetatable({raw = x}, mt) 65 else 66 error("Bad argument to ffi_struct constructor: "..t) 67 end 68 return res 69 end 70 index.new = new 71 72 setmetatable(index, { 73 __index = base_funcs, 74 __call = function(_, ...) return new(...) end, 75 }) 76 mth.add_index_methods(mt, index) 77 return index 78 end 79 80 function module.gen_raw_accessor(index, name) 81 index["get_"..name] = function(self) return self.raw[name] end 82 index["set_"..name] = function(self, val) self.raw[name] = val end 83 end 84 85 function module.gen_wrap_accessor(index, name, wrap) 86 index["get_"..name] = function(self) return wrap(self.raw[name]) end 87 index["set_"..name] = function(self, ...) self.raw[name] = wrap(...).raw end 88 end 89 90 local function gen_enum_getter(index, enum, name) 91 index["get_"..name] = function(self) 92 return e_to_str(enum, self.raw[name]) 93 end 94 end 95 module.gen_enum_getter = gen_enum_getter 96 97 local function gen_enum_setter(index, enum, name) 98 index["set_"..name] = function(self, val) 99 self.raw[name] = e_to_int(enum, val) 100 end 101 end 102 module.gen_enum_setter = gen_enum_setter 103 104 function module.gen_enum_accessor(index, enum, name) 105 gen_enum_getter(index, enum, name) 106 gen_enum_setter(index, enum, name) 107 end 108 109 return module