mirror of
https://github.com/gvx/bitser.git
synced 2024-11-11 01:44:21 +00:00
Actually, going ahead and replacing the implementation
Thanks to git I can always roll back if this was a bad idea
This commit is contained in:
parent
529cd80c7a
commit
06d5b69b61
260
bitser.lua
260
bitser.lua
@ -22,79 +22,104 @@ local getmetatable = getmetatable
|
|||||||
local setmetatable = setmetatable
|
local setmetatable = setmetatable
|
||||||
|
|
||||||
local ffi = require("ffi")
|
local ffi = require("ffi")
|
||||||
|
local buf_pos = 0
|
||||||
|
local buf_size = -1
|
||||||
|
local buf = nil
|
||||||
|
local writable_buf = nil
|
||||||
|
local writable_buf_size = nil
|
||||||
|
|
||||||
local function Buffer_newWriter(size)
|
local function Buffer_prereserve(min_size)
|
||||||
size = size or 4096
|
if buf_size < min_size then
|
||||||
return {size = size, pos = 0, buf = ffi.new("uint8_t[?]", size)}
|
buf_size = min_size
|
||||||
end
|
buf = ffi.new("uint8_t[?]", buf_size)
|
||||||
|
|
||||||
local function Buffer_newReader(str)
|
|
||||||
local buf = ffi.new("uint8_t[?]", #str)
|
|
||||||
ffi.copy(buf, str, #str)
|
|
||||||
return {size = #str, pos = 0, buf = buf}
|
|
||||||
end
|
|
||||||
|
|
||||||
local function Buffer_newDataReader(data, size)
|
|
||||||
return {size = size, pos = 0, buf = ffi.cast("uint8_t*", data)}
|
|
||||||
end
|
|
||||||
|
|
||||||
local function Buffer_reserve(self, additional_size)
|
|
||||||
while self.pos + additional_size > self.size do
|
|
||||||
self.size = self.size * 2
|
|
||||||
local oldbuf = self.buf
|
|
||||||
self.buf = ffi.new("uint8_t[?]", self.size)
|
|
||||||
ffi.copy(self.buf, oldbuf, self.pos)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function Buffer_write_byte(self, x)
|
local function Buffer_makeBuffer(size)
|
||||||
Buffer_reserve(self, 1)
|
if writable_buf then
|
||||||
self.buf[self.pos] = x
|
buf = writable_buf
|
||||||
self.pos = self.pos + 1
|
buf_size = writable_buf_size
|
||||||
|
writable_buf = nil
|
||||||
|
writable_buf_size = nil
|
||||||
|
end
|
||||||
|
buf_pos = 0
|
||||||
|
Buffer_prereserve(size)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function Buffer_write_string(self, s)
|
local function Buffer_newWriter(size)
|
||||||
Buffer_reserve(self, #s)
|
Buffer_makeBuffer(size or 0)
|
||||||
ffi.copy(self.buf + self.pos, s, #s)
|
|
||||||
self.pos = self.pos + #s
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function Buffer_write_data(self, ct, len, ...)
|
local function Buffer_newReader(str)
|
||||||
Buffer_reserve(self, len)
|
Buffer_makeBuffer(#str)
|
||||||
ffi.copy(self.buf + self.pos, ffi.new(ct, ...), len)
|
ffi.copy(buf, str, #str)
|
||||||
self.pos = self.pos + len
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local function Buffer_get(self)
|
local function Buffer_newDataReader(data, size)
|
||||||
return self.buf, self.pos
|
writable_buf = buf
|
||||||
|
writable_buf_size = buf_size
|
||||||
|
buf_pos = 0
|
||||||
|
buf_size = size
|
||||||
|
buf = ffi.cast("uint8_t*", data)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function Buffer_ensure(self, numbytes)
|
local function Buffer_reserve(additional_size)
|
||||||
if self.pos + numbytes > self.size then
|
while buf_pos + additional_size > buf_size do
|
||||||
|
buf_size = buf_size * 2
|
||||||
|
local oldbuf = buf
|
||||||
|
buf = ffi.new("uint8_t[?]", buf_size)
|
||||||
|
ffi.copy(buf, oldbuf, buf_pos)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function Buffer_write_byte(x)
|
||||||
|
Buffer_reserve(1)
|
||||||
|
buf[buf_pos] = x
|
||||||
|
buf_pos = buf_pos + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local function Buffer_write_string(s)
|
||||||
|
Buffer_reserve(#s)
|
||||||
|
ffi.copy(buf + buf_pos, s, #s)
|
||||||
|
buf_pos = buf_pos + #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
|
||||||
|
end
|
||||||
|
|
||||||
|
local function Buffer_get()
|
||||||
|
return buf, buf_pos
|
||||||
|
end
|
||||||
|
|
||||||
|
local function Buffer_ensure(numbytes)
|
||||||
|
if buf_pos + numbytes > buf_size then
|
||||||
error("malformed serialized data")
|
error("malformed serialized data")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function Buffer_read_byte(self)
|
local function Buffer_read_byte()
|
||||||
Buffer_ensure(self, 1)
|
Buffer_ensure(1)
|
||||||
local x = self.buf[self.pos]
|
local x = buf[buf_pos]
|
||||||
self.pos = self.pos + 1
|
buf_pos = buf_pos + 1
|
||||||
return x
|
return x
|
||||||
end
|
end
|
||||||
|
|
||||||
local function Buffer_read_string(self, len)
|
local function Buffer_read_string(len)
|
||||||
Buffer_ensure(self, len)
|
Buffer_ensure(len)
|
||||||
local pos = self.pos
|
local x = ffi.string(buf + buf_pos, len)
|
||||||
self.pos = pos + len
|
buf_pos = buf_pos + len
|
||||||
return ffi.string(self.buf + pos, len)
|
return x
|
||||||
end
|
end
|
||||||
|
|
||||||
local function Buffer_read_data(self, ct, len)
|
local function Buffer_read_data(ct, len)
|
||||||
Buffer_ensure(self, len)
|
Buffer_ensure(len)
|
||||||
local t = ffi.new(ct)
|
local x = ffi.new(ct)
|
||||||
ffi.copy(t, self.buf + self.pos, len)
|
ffi.copy(x, buf + buf_pos, len)
|
||||||
self.pos = self.pos + len
|
buf_pos = buf_pos + len
|
||||||
return t
|
return x
|
||||||
end
|
end
|
||||||
|
|
||||||
local resource_registry = {}
|
local resource_registry = {}
|
||||||
@ -106,48 +131,48 @@ local class_deserialize_registry = {}
|
|||||||
|
|
||||||
local serialize_value
|
local serialize_value
|
||||||
|
|
||||||
local function write_number(value, buffer, _)
|
local function write_number(value, _)
|
||||||
if floor(value) == value and value >= -2147483648 and value <= 2147483647 then
|
if floor(value) == value and value >= -2147483648 and value <= 2147483647 then
|
||||||
if value >= -27 and value <= 100 then
|
if value >= -27 and value <= 100 then
|
||||||
--small int
|
--small int
|
||||||
Buffer_write_byte(buffer, value + 27)
|
Buffer_write_byte(value + 27)
|
||||||
elseif value >= -32768 and value <= 32767 then
|
elseif value >= -32768 and value <= 32767 then
|
||||||
--short int
|
--short int
|
||||||
Buffer_write_byte(buffer, 250)
|
Buffer_write_byte(250)
|
||||||
Buffer_write_data(buffer, "int16_t[1]", 2, value)
|
Buffer_write_data("int16_t[1]", 2, value)
|
||||||
else
|
else
|
||||||
--long int
|
--long int
|
||||||
Buffer_write_byte(buffer, 245)
|
Buffer_write_byte(245)
|
||||||
Buffer_write_data(buffer, "int32_t[1]", 4, value)
|
Buffer_write_data("int32_t[1]", 4, value)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
--double
|
--double
|
||||||
Buffer_write_byte(buffer, 246)
|
Buffer_write_byte(246)
|
||||||
Buffer_write_data(buffer, "double[1]", 8, value)
|
Buffer_write_data("double[1]", 8, value)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function write_string(value, buffer, seen)
|
local function write_string(value, seen)
|
||||||
if #value < 32 then
|
if #value < 32 then
|
||||||
--short string
|
--short string
|
||||||
Buffer_write_byte(buffer, 192 + #value)
|
Buffer_write_byte(192 + #value)
|
||||||
else
|
else
|
||||||
--long string
|
--long string
|
||||||
Buffer_write_byte(buffer, 244)
|
Buffer_write_byte(244)
|
||||||
write_number(#value, buffer, seen)
|
write_number(#value, seen)
|
||||||
end
|
end
|
||||||
Buffer_write_string(buffer, value)
|
Buffer_write_string(value)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function write_nil(_, buffer, _)
|
local function write_nil(_, _)
|
||||||
Buffer_write_byte(buffer, 247)
|
Buffer_write_byte(247)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function write_boolean(value, buffer, _)
|
local function write_boolean(value, _)
|
||||||
Buffer_write_byte(buffer, value and 249 or 248)
|
Buffer_write_byte(value and 249 or 248)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function write_table(value, buffer, seen)
|
local function write_table(value, seen)
|
||||||
local classkey
|
local classkey
|
||||||
local class = (class_name_registry[value.class] -- MiddleClass
|
local class = (class_name_registry[value.class] -- MiddleClass
|
||||||
or class_name_registry[value.__baseclass] -- SECL
|
or class_name_registry[value.__baseclass] -- SECL
|
||||||
@ -155,15 +180,15 @@ local function write_table(value, buffer, seen)
|
|||||||
or class_name_registry[value.__class__]) -- Slither
|
or class_name_registry[value.__class__]) -- Slither
|
||||||
if class then
|
if class then
|
||||||
classkey = classkey_registry[class]
|
classkey = classkey_registry[class]
|
||||||
Buffer_write_byte(buffer, 242)
|
Buffer_write_byte(242)
|
||||||
write_string(class, buffer)
|
write_string(class)
|
||||||
else
|
else
|
||||||
Buffer_write_byte(buffer, 240)
|
Buffer_write_byte(240)
|
||||||
end
|
end
|
||||||
local len = #value
|
local len = #value
|
||||||
write_number(len, buffer, seen)
|
write_number(len, seen)
|
||||||
for i = 1, len do
|
for i = 1, len do
|
||||||
serialize_value(value[i], buffer, seen)
|
serialize_value(value[i], seen)
|
||||||
end
|
end
|
||||||
local klen = 0
|
local klen = 0
|
||||||
for k in pairs(value) do
|
for k in pairs(value) do
|
||||||
@ -171,27 +196,27 @@ local function write_table(value, buffer, seen)
|
|||||||
klen = klen + 1
|
klen = klen + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
write_number(klen, buffer, seen)
|
write_number(klen, seen)
|
||||||
for k, v in pairs(value) do
|
for k, v in pairs(value) do
|
||||||
if (type(k) ~= 'number' or floor(k) ~= k or k > len or k < 1) and k ~= classkey then
|
if (type(k) ~= 'number' or floor(k) ~= k or k > len or k < 1) and k ~= classkey then
|
||||||
serialize_value(k, buffer, seen)
|
serialize_value(k, seen)
|
||||||
serialize_value(v, buffer, seen)
|
serialize_value(v, seen)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local types = {number = write_number, string = write_string, table = write_table, boolean = write_boolean, ["nil"] = write_nil}
|
local types = {number = write_number, string = write_string, table = write_table, boolean = write_boolean, ["nil"] = write_nil}
|
||||||
|
|
||||||
serialize_value = function(value, buffer, seen)
|
serialize_value = function(value, seen)
|
||||||
if seen[value] then
|
if seen[value] then
|
||||||
local ref = seen[value]
|
local ref = seen[value]
|
||||||
if ref < 64 then
|
if ref < 64 then
|
||||||
--small reference
|
--small reference
|
||||||
Buffer_write_byte(buffer, 128 + ref)
|
Buffer_write_byte(128 + ref)
|
||||||
else
|
else
|
||||||
--long reference
|
--long reference
|
||||||
Buffer_write_byte(buffer, 243)
|
Buffer_write_byte(243)
|
||||||
write_number(ref, buffer, seen)
|
write_number(ref, seen)
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
@ -204,25 +229,25 @@ serialize_value = function(value, buffer, seen)
|
|||||||
local name = resource_name_registry[value]
|
local name = resource_name_registry[value]
|
||||||
if #name < 16 then
|
if #name < 16 then
|
||||||
--small resource
|
--small resource
|
||||||
Buffer_write_byte(buffer, 224 + #name)
|
Buffer_write_byte(224 + #name)
|
||||||
Buffer_write_string(buffer, name)
|
Buffer_write_string(name)
|
||||||
else
|
else
|
||||||
--long resource
|
--long resource
|
||||||
Buffer_write_byte(buffer, 241)
|
Buffer_write_byte(241)
|
||||||
write_string(name, buffer, seen)
|
write_string(name, seen)
|
||||||
end
|
end
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
(types[t] or
|
(types[t] or
|
||||||
error("cannot serialize type " .. t)
|
error("cannot serialize type " .. t)
|
||||||
)(value, buffer, seen)
|
)(value, seen)
|
||||||
end
|
end
|
||||||
|
|
||||||
local function serialize(value)
|
local function serialize(value)
|
||||||
local buffer = Buffer_newWriter()
|
Buffer_newWriter()
|
||||||
local seen = {len = 0}
|
local seen = {len = 0}
|
||||||
serialize_value(value, buffer, seen)
|
serialize_value(value, seen)
|
||||||
return Buffer_get(buffer)
|
return Buffer_get()
|
||||||
end
|
end
|
||||||
|
|
||||||
local function add_to_seen(value, seen)
|
local function add_to_seen(value, seen)
|
||||||
@ -235,8 +260,8 @@ local function reserve_seen(seen)
|
|||||||
return #seen
|
return #seen
|
||||||
end
|
end
|
||||||
|
|
||||||
local function deserialize_value(buffer, seen)
|
local function deserialize_value(seen)
|
||||||
local t = Buffer_read_byte(buffer)
|
local t = Buffer_read_byte()
|
||||||
if t < 128 then
|
if t < 128 then
|
||||||
--small int
|
--small int
|
||||||
return t - 27
|
return t - 27
|
||||||
@ -245,44 +270,44 @@ local function deserialize_value(buffer, seen)
|
|||||||
return seen[t - 127]
|
return seen[t - 127]
|
||||||
elseif t < 224 then
|
elseif t < 224 then
|
||||||
--small string
|
--small string
|
||||||
return add_to_seen(Buffer_read_string(buffer, t - 192), seen)
|
return add_to_seen(Buffer_read_string(t - 192), seen)
|
||||||
elseif t < 240 then
|
elseif t < 240 then
|
||||||
--small resource
|
--small resource
|
||||||
return add_to_seen(resource_registry[Buffer_read_string(buffer, t - 224)], seen)
|
return add_to_seen(resource_registry[Buffer_read_string(t - 224)], seen)
|
||||||
elseif t == 240 then
|
elseif t == 240 then
|
||||||
--table
|
--table
|
||||||
local v = add_to_seen({}, seen)
|
local v = add_to_seen({}, seen)
|
||||||
local len = deserialize_value(buffer, seen)
|
local len = deserialize_value(seen)
|
||||||
for i = 1, len do
|
for i = 1, len do
|
||||||
v[i] = deserialize_value(buffer, seen)
|
v[i] = deserialize_value(seen)
|
||||||
end
|
end
|
||||||
len = deserialize_value(buffer, seen)
|
len = deserialize_value(seen)
|
||||||
for _ = 1, len do
|
for _ = 1, len do
|
||||||
local key = deserialize_value(buffer, seen)
|
local key = deserialize_value(seen)
|
||||||
v[key] = deserialize_value(buffer, seen)
|
v[key] = deserialize_value(seen)
|
||||||
end
|
end
|
||||||
return v
|
return v
|
||||||
elseif t == 241 then
|
elseif t == 241 then
|
||||||
--long resource
|
--long resource
|
||||||
local idx = reserve_seen(seen)
|
local idx = reserve_seen(seen)
|
||||||
local value = resource_registry[deserialize_value(buffer, seen)]
|
local value = resource_registry[deserialize_value(seen)]
|
||||||
seen[idx] = value
|
seen[idx] = value
|
||||||
return value
|
return value
|
||||||
elseif t == 242 then
|
elseif t == 242 then
|
||||||
--instance
|
--instance
|
||||||
local instance = add_to_seen({}, seen)
|
local instance = add_to_seen({}, seen)
|
||||||
local classname = deserialize_value(buffer, seen)
|
local classname = deserialize_value(seen)
|
||||||
local class = class_registry[classname]
|
local class = class_registry[classname]
|
||||||
local classkey = classkey_registry[classname]
|
local classkey = classkey_registry[classname]
|
||||||
local deserializer = class_deserialize_registry[classname]
|
local deserializer = class_deserialize_registry[classname]
|
||||||
local len = deserialize_value(buffer, seen)
|
local len = deserialize_value(seen)
|
||||||
for i = 1, len do
|
for i = 1, len do
|
||||||
instance[i] = deserialize_value(buffer, seen)
|
instance[i] = deserialize_value(seen)
|
||||||
end
|
end
|
||||||
len = deserialize_value(buffer, seen)
|
len = deserialize_value(seen)
|
||||||
for _ = 1, len do
|
for _ = 1, len do
|
||||||
local key = deserialize_value(buffer, seen)
|
local key = deserialize_value(seen)
|
||||||
instance[key] = deserialize_value(buffer, seen)
|
instance[key] = deserialize_value(seen)
|
||||||
end
|
end
|
||||||
if classkey then
|
if classkey then
|
||||||
instance[classkey] = class
|
instance[classkey] = class
|
||||||
@ -290,16 +315,16 @@ local function deserialize_value(buffer, seen)
|
|||||||
return deserializer(instance, class)
|
return deserializer(instance, class)
|
||||||
elseif t == 243 then
|
elseif t == 243 then
|
||||||
--reference
|
--reference
|
||||||
return seen[deserialize_value(buffer, seen) + 1]
|
return seen[deserialize_value(seen) + 1]
|
||||||
elseif t == 244 then
|
elseif t == 244 then
|
||||||
--long string
|
--long string
|
||||||
return add_to_seen(Buffer_read_string(buffer, deserialize_value(buffer, seen)), seen)
|
return add_to_seen(Buffer_read_string(deserialize_value(seen)), seen)
|
||||||
elseif t == 245 then
|
elseif t == 245 then
|
||||||
--long int
|
--long int
|
||||||
return Buffer_read_data(buffer, "int32_t[1]", 4)[0]
|
return Buffer_read_data("int32_t[1]", 4)[0]
|
||||||
elseif t == 246 then
|
elseif t == 246 then
|
||||||
--double
|
--double
|
||||||
return Buffer_read_data(buffer, "double[1]", 8)[0]
|
return Buffer_read_data("double[1]", 8)[0]
|
||||||
elseif t == 247 then
|
elseif t == 247 then
|
||||||
--nil
|
--nil
|
||||||
return nil
|
return nil
|
||||||
@ -311,17 +336,12 @@ local function deserialize_value(buffer, seen)
|
|||||||
return true
|
return true
|
||||||
elseif t == 250 then
|
elseif t == 250 then
|
||||||
--short int
|
--short int
|
||||||
return Buffer_read_data(buffer, "int16_t[1]", 2)[0]
|
return Buffer_read_data("int16_t[1]", 2)[0]
|
||||||
else
|
else
|
||||||
error("unsupported serialized type " .. t)
|
error("unsupported serialized type " .. t)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function deserialize(buffer)
|
|
||||||
local seen = {}
|
|
||||||
return deserialize_value(buffer, seen)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function deserialize_MiddleClass(instance, class)
|
local function deserialize_MiddleClass(instance, class)
|
||||||
return setmetatable(instance, class.__instanceDict)
|
return setmetatable(instance, class.__instanceDict)
|
||||||
end
|
end
|
||||||
@ -339,9 +359,11 @@ end
|
|||||||
return {dumps = function(value)
|
return {dumps = function(value)
|
||||||
return ffi.string(serialize(value))
|
return ffi.string(serialize(value))
|
||||||
end, loadData = function(data, size)
|
end, loadData = function(data, size)
|
||||||
return deserialize(Buffer_newDataReader(data, size))
|
Buffer_newDataReader(data, size)
|
||||||
|
return deserialize_value({})
|
||||||
end, loads = function(str)
|
end, loads = function(str)
|
||||||
return deserialize(Buffer_newReader(str))
|
Buffer_newReader(str)
|
||||||
|
return deserialize_value({})
|
||||||
end, register = function(name, resource)
|
end, register = function(name, resource)
|
||||||
assert(not resource_registry[name], name .. " already registered")
|
assert(not resource_registry[name], name .. " already registered")
|
||||||
resource_registry[name] = resource
|
resource_registry[name] = resource
|
||||||
@ -393,4 +415,4 @@ end, unregisterClass = function(name)
|
|||||||
classkey_registry[name] = nil
|
classkey_registry[name] = nil
|
||||||
class_deserialize_registry[name] = nil
|
class_deserialize_registry[name] = nil
|
||||||
class_registry[name] = nil
|
class_registry[name] = nil
|
||||||
end}
|
end, reserve_buffer = Buffer_prereserve}
|
@ -1,418 +0,0 @@
|
|||||||
--[[
|
|
||||||
Copyright (c) 2016, Robin 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
|
|
||||||
copyright notice and this permission notice appear in all copies.
|
|
||||||
|
|
||||||
THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
|
||||||
WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
|
||||||
MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
|
||||||
ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
|
||||||
WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
|
||||||
ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
|
||||||
OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
|
||||||
]]
|
|
||||||
|
|
||||||
local floor = math.floor
|
|
||||||
local pairs = pairs
|
|
||||||
local type = type
|
|
||||||
local insert = table.insert
|
|
||||||
local getmetatable = getmetatable
|
|
||||||
local setmetatable = setmetatable
|
|
||||||
|
|
||||||
local ffi = require("ffi")
|
|
||||||
local buf_pos = 0
|
|
||||||
local buf_size = -1
|
|
||||||
local buf = nil
|
|
||||||
local writable_buf = nil
|
|
||||||
local writable_buf_size = nil
|
|
||||||
|
|
||||||
local function Buffer_prereserve(min_size)
|
|
||||||
if buf_size < min_size then
|
|
||||||
buf_size = min_size
|
|
||||||
buf = ffi.new("uint8_t[?]", buf_size)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function Buffer_makeBuffer(size)
|
|
||||||
if writable_buf then
|
|
||||||
buf = writable_buf
|
|
||||||
buf_size = writable_buf_size
|
|
||||||
writable_buf = nil
|
|
||||||
writable_buf_size = nil
|
|
||||||
end
|
|
||||||
buf_pos = 0
|
|
||||||
Buffer_prereserve(size)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function Buffer_newWriter(size)
|
|
||||||
Buffer_makeBuffer(size or 0)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function Buffer_newReader(str)
|
|
||||||
Buffer_makeBuffer(#str)
|
|
||||||
ffi.copy(buf, str, #str)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function Buffer_newDataReader(data, size)
|
|
||||||
writable_buf = buf
|
|
||||||
writable_buf_size = buf_size
|
|
||||||
buf_pos = 0
|
|
||||||
buf_size = size
|
|
||||||
buf = ffi.cast("uint8_t*", data)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function Buffer_reserve(additional_size)
|
|
||||||
while buf_pos + additional_size > buf_size do
|
|
||||||
buf_size = buf_size * 2
|
|
||||||
local oldbuf = buf
|
|
||||||
buf = ffi.new("uint8_t[?]", buf_size)
|
|
||||||
ffi.copy(buf, oldbuf, buf_pos)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function Buffer_write_byte(x)
|
|
||||||
Buffer_reserve(1)
|
|
||||||
buf[buf_pos] = x
|
|
||||||
buf_pos = buf_pos + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
local function Buffer_write_string(s)
|
|
||||||
Buffer_reserve(#s)
|
|
||||||
ffi.copy(buf + buf_pos, s, #s)
|
|
||||||
buf_pos = buf_pos + #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
|
|
||||||
end
|
|
||||||
|
|
||||||
local function Buffer_get()
|
|
||||||
return buf, buf_pos
|
|
||||||
end
|
|
||||||
|
|
||||||
local function Buffer_ensure(numbytes)
|
|
||||||
if buf_pos + numbytes > buf_size then
|
|
||||||
error("malformed serialized data")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function Buffer_read_byte()
|
|
||||||
Buffer_ensure(1)
|
|
||||||
local x = buf[buf_pos]
|
|
||||||
buf_pos = buf_pos + 1
|
|
||||||
return x
|
|
||||||
end
|
|
||||||
|
|
||||||
local function Buffer_read_string(len)
|
|
||||||
Buffer_ensure(len)
|
|
||||||
local x = ffi.string(buf + buf_pos, len)
|
|
||||||
buf_pos = buf_pos + 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)
|
|
||||||
buf_pos = buf_pos + len
|
|
||||||
return x
|
|
||||||
end
|
|
||||||
|
|
||||||
local resource_registry = {}
|
|
||||||
local resource_name_registry = {}
|
|
||||||
local class_registry = {}
|
|
||||||
local class_name_registry = {}
|
|
||||||
local classkey_registry = {}
|
|
||||||
local class_deserialize_registry = {}
|
|
||||||
|
|
||||||
local serialize_value
|
|
||||||
|
|
||||||
local function write_number(value, _)
|
|
||||||
if floor(value) == value and value >= -2147483648 and value <= 2147483647 then
|
|
||||||
if value >= -27 and value <= 100 then
|
|
||||||
--small int
|
|
||||||
Buffer_write_byte(value + 27)
|
|
||||||
elseif value >= -32768 and value <= 32767 then
|
|
||||||
--short int
|
|
||||||
Buffer_write_byte(250)
|
|
||||||
Buffer_write_data("int16_t[1]", 2, value)
|
|
||||||
else
|
|
||||||
--long int
|
|
||||||
Buffer_write_byte(245)
|
|
||||||
Buffer_write_data("int32_t[1]", 4, value)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
--double
|
|
||||||
Buffer_write_byte(246)
|
|
||||||
Buffer_write_data("double[1]", 8, value)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function write_string(value, seen)
|
|
||||||
if #value < 32 then
|
|
||||||
--short string
|
|
||||||
Buffer_write_byte(192 + #value)
|
|
||||||
else
|
|
||||||
--long string
|
|
||||||
Buffer_write_byte(244)
|
|
||||||
write_number(#value, seen)
|
|
||||||
end
|
|
||||||
Buffer_write_string(value)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function write_nil(_, _)
|
|
||||||
Buffer_write_byte(247)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function write_boolean(value, _)
|
|
||||||
Buffer_write_byte(value and 249 or 248)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function write_table(value, seen)
|
|
||||||
local classkey
|
|
||||||
local class = (class_name_registry[value.class] -- MiddleClass
|
|
||||||
or class_name_registry[value.__baseclass] -- SECL
|
|
||||||
or class_name_registry[getmetatable(value)] -- hump.class
|
|
||||||
or class_name_registry[value.__class__]) -- Slither
|
|
||||||
if class then
|
|
||||||
classkey = classkey_registry[class]
|
|
||||||
Buffer_write_byte(242)
|
|
||||||
write_string(class)
|
|
||||||
else
|
|
||||||
Buffer_write_byte(240)
|
|
||||||
end
|
|
||||||
local len = #value
|
|
||||||
write_number(len, seen)
|
|
||||||
for i = 1, len do
|
|
||||||
serialize_value(value[i], seen)
|
|
||||||
end
|
|
||||||
local klen = 0
|
|
||||||
for k in pairs(value) do
|
|
||||||
if (type(k) ~= 'number' or floor(k) ~= k or k > len or k < 1) and k ~= classkey then
|
|
||||||
klen = klen + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
write_number(klen, seen)
|
|
||||||
for k, v in pairs(value) do
|
|
||||||
if (type(k) ~= 'number' or floor(k) ~= k or k > len or k < 1) and k ~= classkey then
|
|
||||||
serialize_value(k, seen)
|
|
||||||
serialize_value(v, seen)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local types = {number = write_number, string = write_string, table = write_table, boolean = write_boolean, ["nil"] = write_nil}
|
|
||||||
|
|
||||||
serialize_value = function(value, seen)
|
|
||||||
if seen[value] then
|
|
||||||
local ref = seen[value]
|
|
||||||
if ref < 64 then
|
|
||||||
--small reference
|
|
||||||
Buffer_write_byte(128 + ref)
|
|
||||||
else
|
|
||||||
--long reference
|
|
||||||
Buffer_write_byte(243)
|
|
||||||
write_number(ref, seen)
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
local t = type(value)
|
|
||||||
if t ~= 'number' and t ~= 'boolean' and t ~= 'nil' then
|
|
||||||
seen[value] = seen.len
|
|
||||||
seen.len = seen.len + 1
|
|
||||||
end
|
|
||||||
if resource_name_registry[value] then
|
|
||||||
local name = resource_name_registry[value]
|
|
||||||
if #name < 16 then
|
|
||||||
--small resource
|
|
||||||
Buffer_write_byte(224 + #name)
|
|
||||||
Buffer_write_string(name)
|
|
||||||
else
|
|
||||||
--long resource
|
|
||||||
Buffer_write_byte(241)
|
|
||||||
write_string(name, seen)
|
|
||||||
end
|
|
||||||
return
|
|
||||||
end
|
|
||||||
(types[t] or
|
|
||||||
error("cannot serialize type " .. t)
|
|
||||||
)(value, seen)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function serialize(value)
|
|
||||||
Buffer_newWriter()
|
|
||||||
local seen = {len = 0}
|
|
||||||
serialize_value(value, seen)
|
|
||||||
return Buffer_get()
|
|
||||||
end
|
|
||||||
|
|
||||||
local function add_to_seen(value, seen)
|
|
||||||
insert(seen, value)
|
|
||||||
return value
|
|
||||||
end
|
|
||||||
|
|
||||||
local function reserve_seen(seen)
|
|
||||||
insert(seen, 42)
|
|
||||||
return #seen
|
|
||||||
end
|
|
||||||
|
|
||||||
local function deserialize_value(seen)
|
|
||||||
local t = Buffer_read_byte()
|
|
||||||
if t < 128 then
|
|
||||||
--small int
|
|
||||||
return t - 27
|
|
||||||
elseif t < 192 then
|
|
||||||
--small reference
|
|
||||||
return seen[t - 127]
|
|
||||||
elseif t < 224 then
|
|
||||||
--small string
|
|
||||||
return add_to_seen(Buffer_read_string(t - 192), seen)
|
|
||||||
elseif t < 240 then
|
|
||||||
--small resource
|
|
||||||
return add_to_seen(resource_registry[Buffer_read_string(t - 224)], seen)
|
|
||||||
elseif t == 240 then
|
|
||||||
--table
|
|
||||||
local v = add_to_seen({}, seen)
|
|
||||||
local len = deserialize_value(seen)
|
|
||||||
for i = 1, len do
|
|
||||||
v[i] = deserialize_value(seen)
|
|
||||||
end
|
|
||||||
len = deserialize_value(seen)
|
|
||||||
for _ = 1, len do
|
|
||||||
local key = deserialize_value(seen)
|
|
||||||
v[key] = deserialize_value(seen)
|
|
||||||
end
|
|
||||||
return v
|
|
||||||
elseif t == 241 then
|
|
||||||
--long resource
|
|
||||||
local idx = reserve_seen(seen)
|
|
||||||
local value = resource_registry[deserialize_value(seen)]
|
|
||||||
seen[idx] = value
|
|
||||||
return value
|
|
||||||
elseif t == 242 then
|
|
||||||
--instance
|
|
||||||
local instance = add_to_seen({}, seen)
|
|
||||||
local classname = deserialize_value(seen)
|
|
||||||
local class = class_registry[classname]
|
|
||||||
local classkey = classkey_registry[classname]
|
|
||||||
local deserializer = class_deserialize_registry[classname]
|
|
||||||
local len = deserialize_value(seen)
|
|
||||||
for i = 1, len do
|
|
||||||
instance[i] = deserialize_value(seen)
|
|
||||||
end
|
|
||||||
len = deserialize_value(seen)
|
|
||||||
for _ = 1, len do
|
|
||||||
local key = deserialize_value(seen)
|
|
||||||
instance[key] = deserialize_value(seen)
|
|
||||||
end
|
|
||||||
if classkey then
|
|
||||||
instance[classkey] = class
|
|
||||||
end
|
|
||||||
return deserializer(instance, class)
|
|
||||||
elseif t == 243 then
|
|
||||||
--reference
|
|
||||||
return seen[deserialize_value(seen) + 1]
|
|
||||||
elseif t == 244 then
|
|
||||||
--long string
|
|
||||||
return add_to_seen(Buffer_read_string(deserialize_value(seen)), seen)
|
|
||||||
elseif t == 245 then
|
|
||||||
--long int
|
|
||||||
return Buffer_read_data("int32_t[1]", 4)[0]
|
|
||||||
elseif t == 246 then
|
|
||||||
--double
|
|
||||||
return Buffer_read_data("double[1]", 8)[0]
|
|
||||||
elseif t == 247 then
|
|
||||||
--nil
|
|
||||||
return nil
|
|
||||||
elseif t == 248 then
|
|
||||||
--false
|
|
||||||
return false
|
|
||||||
elseif t == 249 then
|
|
||||||
--true
|
|
||||||
return true
|
|
||||||
elseif t == 250 then
|
|
||||||
--short int
|
|
||||||
return Buffer_read_data("int16_t[1]", 2)[0]
|
|
||||||
else
|
|
||||||
error("unsupported serialized type " .. t)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function deserialize_MiddleClass(instance, class)
|
|
||||||
return setmetatable(instance, class.__instanceDict)
|
|
||||||
end
|
|
||||||
|
|
||||||
local function deserialize_SECL(instance, class)
|
|
||||||
return setmetatable(instance, getmetatable(class))
|
|
||||||
end
|
|
||||||
|
|
||||||
local deserialize_humpclass = setmetatable
|
|
||||||
|
|
||||||
local function deserialize_Slither(instance, class)
|
|
||||||
return getmetatable(class).allocate(instance)
|
|
||||||
end
|
|
||||||
|
|
||||||
return {dumps = function(value)
|
|
||||||
return ffi.string(serialize(value))
|
|
||||||
end, loadData = function(data, size)
|
|
||||||
Buffer_newDataReader(data, size)
|
|
||||||
return deserialize_value({})
|
|
||||||
end, loads = function(str)
|
|
||||||
Buffer_newReader(str)
|
|
||||||
return deserialize_value({})
|
|
||||||
end, register = function(name, resource)
|
|
||||||
assert(not resource_registry[name], name .. " already registered")
|
|
||||||
resource_registry[name] = resource
|
|
||||||
resource_name_registry[resource] = name
|
|
||||||
return resource
|
|
||||||
end, unregister = function(name)
|
|
||||||
resource_name_registry[resource_registry[name]] = nil
|
|
||||||
resource_registry[name] = nil
|
|
||||||
end, registerClass = function(name, class, classkey, deserializer)
|
|
||||||
if not class then
|
|
||||||
class = name
|
|
||||||
name = class.__name__ or class.name
|
|
||||||
end
|
|
||||||
if not classkey then
|
|
||||||
if class.__instanceDict then
|
|
||||||
-- assume MiddleClass
|
|
||||||
classkey = 'class'
|
|
||||||
elseif class.__baseclass then
|
|
||||||
-- assume SECL
|
|
||||||
classkey = '__baseclass'
|
|
||||||
end
|
|
||||||
-- assume hump.class, Slither, or something else that doesn't store the
|
|
||||||
-- class directly on the instance
|
|
||||||
end
|
|
||||||
if not deserializer then
|
|
||||||
if class.__instanceDict then
|
|
||||||
-- assume MiddleClass
|
|
||||||
deserializer = deserialize_MiddleClass
|
|
||||||
elseif class.__baseclass then
|
|
||||||
-- assume SECL
|
|
||||||
deserializer = deserialize_SECL
|
|
||||||
elseif class.__index == class then
|
|
||||||
-- assume hump.class
|
|
||||||
deserializer = deserialize_humpclass
|
|
||||||
elseif class.__name__ then
|
|
||||||
-- assume Slither
|
|
||||||
deserializer = deserialize_Slither
|
|
||||||
else
|
|
||||||
error("no deserializer given for unsupported class library")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
class_registry[name] = class
|
|
||||||
classkey_registry[name] = classkey
|
|
||||||
class_deserialize_registry[name] = deserializer
|
|
||||||
class_name_registry[class] = name
|
|
||||||
return class
|
|
||||||
end, unregisterClass = function(name)
|
|
||||||
class_name_registry[class_registry[name]] = nil
|
|
||||||
classkey_registry[name] = nil
|
|
||||||
class_deserialize_registry[name] = nil
|
|
||||||
class_registry[name] = nil
|
|
||||||
end, reserve_buffer = Buffer_prereserve}
|
|
Loading…
Reference in New Issue
Block a user