Add support for cdata

More testing needed
This commit is contained in:
R.E.J. Wellner 2020-04-28 16:51:41 +02:00
parent 5a134b4fce
commit caf972ca80
4 changed files with 96 additions and 18 deletions

View File

@ -1,5 +1,5 @@
--[[
Copyright (c) 2016, Robin Wellner
Copyright (c) 2020, Jasmijn Wellner
Permission to use, copy, modify, and/or distribute this software for any
purpose with or without fee is hereby granted, provided that the above
@ -82,16 +82,18 @@ local function Buffer_write_byte(x)
buf_pos = buf_pos + 1
end
local function Buffer_write_raw(data, len)
Buffer_reserve(len)
ffi.copy(buf + buf_pos, data, len)
buf_pos = buf_pos + len
end
local function Buffer_write_string(s)
Buffer_reserve(#s)
ffi.copy(buf + buf_pos, s, #s)
buf_pos = buf_pos + #s
Buffer_write_raw(s, #s)
end
local function Buffer_write_data(ct, len, ...)
Buffer_reserve(len)
ffi.copy(buf + buf_pos, ffi.new(ct, ...), len)
buf_pos = buf_pos + len
Buffer_write_raw(ffi.new(ct, ...), len)
end
local function Buffer_ensure(numbytes)
@ -114,12 +116,14 @@ local function Buffer_read_string(len)
return x
end
local function Buffer_read_data(ct, len)
Buffer_ensure(len)
local x = ffi.new(ct)
ffi.copy(x, buf + buf_pos, len)
local function Buffer_read_raw(data, len)
ffi.copy(data, buf + buf_pos, len)
buf_pos = buf_pos + len
return x
return data
end
local function Buffer_read_data(ct, len)
return Buffer_read_raw(ffi.new(ct), len)
end
local resource_registry = {}
@ -206,7 +210,23 @@ local function write_table(value, seen)
end
end
local types = {number = write_number, string = write_string, table = write_table, boolean = write_boolean, ["nil"] = write_nil}
local function write_cdata(value, seen)
local ty = ffi.typeof(value)
if ty == value then
-- ctype
Buffer_write_byte(251)
serialize_value(tostring(ty):sub(7, -2), seen)
return
end
-- cdata
Buffer_write_byte(252)
serialize_value(ty, seen)
local len = ffi.sizeof(value)
write_number(len)
Buffer_write_raw(ffi.typeof('$[1]', ty)(value), len)
end
local types = {number = write_number, string = write_string, table = write_table, boolean = write_boolean, ["nil"] = write_nil, cdata = write_cdata}
serialize_value = function(value, seen)
if seen[value] then
@ -337,6 +357,15 @@ local function deserialize_value(seen)
elseif t == 250 then
--short int
return Buffer_read_data("int16_t[1]", 2)[0]
elseif t == 251 then
--ctype
return ffi.typeof(deserialize_value(seen))
elseif t == 252 then
local ctype = deserialize_value(seen)
local len = deserialize_value(seen)
local read_into = ffi.typeof('$[1]', ctype)()
Buffer_read_raw(read_into, len)
return ctype(read_into[0])
else
error("unsupported serialized type " .. t)
end

23
cases/cdata.lua Normal file
View File

@ -0,0 +1,23 @@
local ffi = require("ffi")
ffi.cdef[[
struct simple_struct {
int a;
int b;
};
struct nested_struct {
int a;
struct simple_struct b;
};
]]
local bitser = require 'bitser'
local int_data = ffi.new('int', 5)
local struct_data = ffi.new('struct nested_struct', {10, {20, 30}})
local value = ffi.new('struct { int a; double b; }', 42, 1.25)
return {int_data, struct_data, value}, 1000, 3

View File

@ -100,6 +100,12 @@ function love.draw()
for i, case in ipairs(cases) do
love.graphics.print(case, selected_case == i and 60 or 20, i * 20)
end
local i = 2
love.graphics.print('serialisation libraries installed:', 200, 20)
for sername in pairs(sers) do
love.graphics.print(sername, 200, i * 20)
i = i + 1
end
elseif state == 'calculate_results' then
love.graphics.print("Running benchmark...", 20, 20)
love.graphics.print("This may take a while", 20, 40)
@ -111,6 +117,7 @@ function love.draw()
resultname = "serialisation time in seconds"
results_size = {}
results_deser = {}
errors = {}
for sername, serializer in pairs(sers) do
results_ser[sername] = math.huge
results_deser[sername] = math.huge
@ -126,7 +133,9 @@ function love.draw()
end
return os.clock() - t
end)
if success and diff < results_ser[sername] then
if not success and not errors[sername] then
errors[sername] = diff
elseif success and diff < results_ser[sername] then
results_ser[sername] = diff
end
if try == 1 then
@ -145,7 +154,9 @@ function love.draw()
end
return os.clock() - t
end)
if success and diff < results_deser[sername] then
if not success and not errors[sername] then
errors[sername] = diff
elseif success and diff < results_deser[sername] then
results_deser[sername] = diff
end
end
@ -171,6 +182,7 @@ function love.draw()
love.graphics.setColor(220/256, 30/256, 0)
love.graphics.rectangle('fill', 100, i * 20, 780 - 100, 18)
love.graphics.setColor(40/256, 30/256, 0)
love.graphics.print(errors[sername], 102, i * 20 + 2)
else
love.graphics.rectangle('fill', 100, i * 20, (780 - 100) * (result - results_min) / (results_max - results_min), 18)
end

View File

@ -270,8 +270,6 @@ describe("bitser", function()
assert.has_error(function() bitser.registerClass('Horse', {mane = 'majestic'}) end, "no deserializer given for unsupported class library")
end)
it("cannot deserialize values from unassigned type bytes", function()
assert.has_error(function() bitser.loads("\251") end, "unsupported serialized type 251")
assert.has_error(function() bitser.loads("\252") end, "unsupported serialized type 252")
assert.has_error(function() bitser.loads("\253") end, "unsupported serialized type 253")
assert.has_error(function() bitser.loads("\254") end, "unsupported serialized type 254")
assert.has_error(function() bitser.loads("\255") end, "unsupported serialized type 255")
@ -296,9 +294,25 @@ describe("bitser", function()
bitser.loadData(ffi.new("uint8_t[4]", 195, 103, 118, 120), 4)
test_serdeser("bitser")
end)
it("it can dump and load LÖVE files", function()
it("can dump and load LÖVE files", function()
local v = {value = "value"}
bitser.dumpLoveFile("some_file_name", v)
assert.are.same(v, bitser.loadLoveFile("some_file_name"))
end)
it("can read and write cdata", function()
-- a simple value
test_serdeser(ffi.new('double', 42.5))
local value = ffi.new('struct some_struct { int a; double b; }', 42, 1.25)
local type_of_struct = ffi.typeof(value)
-- with a registered type
bitser.register('struct_type', type_of_struct)
test_serdeser(value)
bitser.unregister('struct_type')
-- with an unregistered type
test_serdeser(value)
end)
it("cannot read from anonymous structs", function()
local v = bitser.dumps(ffi.new('struct { int a; }'))
assert.has_error(function() bitser.loads(v) end)
end)
end)