Add map for sproto

This commit is contained in:
Cloud Wu
2020-10-10 13:55:15 +08:00
parent eaa60ca8dd
commit 4484c1ed50
5 changed files with 245 additions and 94 deletions

View File

@@ -4,7 +4,7 @@ local table = require "table"
local packbytes
local packvalue
if _VERSION == "Lua 5.4" then
if _VERSION == "Lua 5.3" then
function packbytes(str)
return string.pack("<s4",str)
end
@@ -69,7 +69,7 @@ local word = alpha * alnum ^ 0
local name = C(word)
local typename = C(word * ("." * word) ^ 0)
local tag = R"09" ^ 1 / tonumber
local mainkey = "(" * blank0 * name * blank0 * ")"
local mainkey = "(" * blank0 * C((word ^ 0)) * blank0 * ")"
local decimal = "(" * blank0 * C(tag) * blank0 * ")"
local function multipat(pat)
@@ -82,7 +82,7 @@ end
local typedef = P {
"ALL",
FIELD = namedpat("field", (name * blanks * tag * blank0 * ":" * blank0 * (C"*")^-1 * typename * (mainkey + decimal)^0)),
FIELD = namedpat("field", name * blanks * tag * blank0 * ":" * blank0 * (C"*")^-1 * typename * (mainkey + decimal)^0),
STRUCT = P"{" * multipat(V"FIELD" + V"TYPE") * P"}",
TYPE = namedpat("type", P"." * name * blank0 * V"STRUCT" ),
SUBPROTO = Ct((C"request" + C"response") * blanks * (typename + V"STRUCT")),
@@ -118,6 +118,11 @@ function convert.protocol(all, obj)
return result
end
local map_keytypes = {
integer = true,
string = true,
}
function convert.type(all, obj)
local result = {}
local typename = obj[1]
@@ -258,7 +263,8 @@ end
type 2 : integer
tag 3 : integer
array 4 : boolean
key 5 : integer # If key exists, array must be true, and it's a map.
key 5 : integer # If key exists, array must be true
map 6 : boolean # Interpret two fields struct as map when decoding
}
name 0 : string
fields 1 : *field
@@ -282,7 +288,11 @@ local function packfield(f)
local strtbl = {}
if f.array then
if f.key then
table.insert(strtbl, "\6\0") -- 6 fields
if f.map then
table.insert(strtbl, "\7\0") -- 7 fields
else
table.insert(strtbl, "\6\0") -- 6 fields
end
else
table.insert(strtbl, "\5\0") -- 5 fields
end
@@ -305,9 +315,12 @@ local function packfield(f)
end
if f.array then
table.insert(strtbl, packvalue(1)) -- array = true (tag = 4)
end
if f.key then
table.insert(strtbl, packvalue(f.key)) -- key tag (tag = 5)
if f.key then
table.insert(strtbl, packvalue(f.key)) -- key tag (tag = 5)
if f.map then
table.insert(strtbl, packvalue(f.map)) -- map tag (tag = 6)
end
end
end
table.insert(strtbl, packbytes(f.name)) -- external object (name)
return packbytes(table.concat(strtbl))
@@ -334,10 +347,27 @@ local function packtype(name, t, alltypes)
tmp.type = nil
end
if f.key then
tmp.key = subtype.fields[f.key]
if not tmp.key then
assert(f.array)
if f.key == "" then
tmp.map = 1
local c = 0
local min_t = math.maxinteger
for n, t in pairs(subtype.fields) do
c = c + 1
if t.tag < min_t then
min_t = t.tag
f.key = n
end
end
if c ~= 2 then
error(string.format("Invalid map definition: %s, must only have two fields", tmp.name))
end
end
local stfield = subtype.fields[f.key]
if not stfield or not stfield.buildin then
error("Invalid map index :" .. f.key)
end
tmp.key = stfield.tag
else
tmp.key = nil
end
@@ -415,9 +445,10 @@ local function packgroup(t,p)
for idx, name in ipairs(alltypes) do
local fields = {}
for _, type_fields in ipairs(t[name]) do
if buildin_types[type_fields.typename] then
fields[type_fields.name] = type_fields.tag
end
fields[type_fields.name] = {
tag = type_fields.tag,
buildin = buildin_types[type_fields.typename]
}
end
alltypes[name] = { id = idx - 1, fields = fields }
end