refser is yet another Lua table serialization library mostly written in C++.
Features:
- Can save and load nil, booleans, numbers, strings, tables and tuples of them.
- Output is endian-portable and binary safe.
- Recursive tables and cross-references are handled correctly.
- Options to restrict saved and loaded data at run-time.
- Options to persist context across several operations.
Install refser using luarocks:
luarocks install refser
Last version uploaded to luarocks is v0.2.
-
Include refser:
local refser = require "refser"
Note: plain
require "refser"
doesn't work. -
Save data and check for errors:
local output, err = refser.save(...) if not output then -- error handling else -- ... end
-
Load data and check for errors:
local count, ... = refser.load(input) if not count then -- error handling else -- ... end
refser provides several methods to restrict saved and loaded data.
- Nesting level of tables can't be larger than refser.maxnesting.
- Tuple length can't be larger than refser.maxtuple.
- Number of items can't be larger than refser.maxitems.
Saves tuple of Lua values into string and returns it. In case of error returns nil
plus error message.
Output is binary safe, it can not contain newlines and embedded zeros.
print(refser.save([[Newlines
and embedded]].."\0zeros"))
-- "Newlines\nand embedded\zzeros"
refser.save preserves all references in table.
x = {}
x[x] = x
s = refser.save(x)
ok, y = refser.load(s)
assert(y == y[y]) -- OK
Loads tuple from string s
. Returns length of loaded tuple and tuple itself. In case of error returns nil
plus error message.
This variable sets maximum nesting level for saved and loaded tables. Default value is 250
. It can be changed at run-time to suit user's needs.
x = {{{}}}
refser.maxnesting = 2
assert(refser.save(x)) -- refser.save error: table is too deep
refser.maxnesting = 3
assert(refser.save(x)) -- OK
This variable sets maximum tuple length for saved and loaded tuples. Default value is 20
. It can be changed at run-time to suit user's needs.
a, b, c = "foo", "bar", "baz"
refser.maxtuple = 2
assert(refser.save(a, b, c)) -- refser.save error: tuple is too long
refser.maxtuple = 3
assert(refser.save(a, b, c)) -- OK
This variable sets maximum number of items for saved and loaded tuples. Default value is 1000000
. It can be changed at run-time to suit user's needs. All values are considered items.
a = {} -- 1 item
a[a] = a -- +2 items; both keys and values count
b = "foo" -- +1 item
c = {a} -- +2 items; in array part of table only values count
-- Total items: 6
refser.maxitems = 5
assert(refser.save(a, b, c)) -- refser.save error: too many items
refser.maxitems = 6
assert(refser.save(a, b, c)) -- OK
Returns a refser worker object which may be used for a number of save/load operations in the same context.
options
argument should be nil or a table. Possible fields:
Sets maximum nesting level for all operations of the worker. Overrides refser.maxnesting.
Sets maximum tuple length for all operations of the worker. Overrides refser.maxtuple.
Sets maximum items count for all operations of the worker. Overrides refser.maxitems.
When specified, refser will use provided table as context instead of a new, empty context. Context determines which tables are recognised by refser. New records may be added into context during save and load.
Example:
x = {1, 2, 3, 4, 5}
c = {[x] = 1, n = 1} -- context table includes x, its id is 1, size of context is 1
worker = refser.new{
context = c
}
y = {x}
s = worker:save(y)
print(s) -- prints {@1|} - x is recognised and not serialized
A string defining which operations worker can perform.
If character "s" can be found in the string, saving is enabled; if "l" is present, loading is enabled.
Default value is "sl".
Similar to refser.save, but uses worker's options and context.
Similar to refser.load, but uses worker's options and context.
Sets options of worker in the same way it is done on initialization.
Sets context of worker.
Sets maxnesting option.
Sets maxtuples option.
Sets maxitems option.
This section is work in process.
Example:
-- worker of first state
worker1 = refser.new()
-- worker of second state
worker2 = refser.new()
-- first state creates and sends data
x1 = {}
y1 = {}
x1[x1] = y1
y1[x1] = x1
s1 = worker1:save(x1, y1)
-- send(s1)
-- second state receives data and sends back some new data
ok, x2, y2 = worker2:load(s1)
z2 = {[x2] = y2}
s2 = worker2:save(z2)
-- send(s2)
-- first state receives data
ok, z1 = worker1:load(s2)
assert(z1[x1] == y1) -- OK
Output format is developed to be easily read by computer, not human, but it still can be used for debugging purposes, if necessary.
nil
is saved asn
.true
andfalse
are saved asT
andF
, respectively.math.huge
and-math.huge
are saved asI
andi
, respectively.NaN
is saved asN
.- numbers are saved using
tostring
, with additionalD
in the beginning. - strings are saved using
string.format("%q")
. - tables' contents are saved between curly braces, with array part separated from hash part by
|
. There are no separators between values in array part, or between key and values in hash part, or between key-value pairs. - references are saved as
@
plus ID of corresponding table(withoutD
in the beginning). Tables receive their IDs in the orderrefser.save
meets them. - tuples are saved as sequence of values.
-
An empty tuple.
print(refser.save()) -- prints nothing print(string.len(refser.save())) -- 0
-
A single value.
print(refser.save("foo")) -- "foo"
-
Three values.
print(refser.save("foo", "bar", "baz")) -- "foo""bar""baz"
-
An empty table. No array part, no hash part.
x = {} print(refser.save(x)) -- {|}
-
An array with 3 numbers.
x = {1, 2, 3} print(refser.save(x)) -- {D1D2D3|}
-
One string in array part and a key-value pair.
x = {"foo", bar = "baz"} print(refser.save(x)) -- {"foo"|"bar""baz"}
-
Nested tables.
x = {{}, [{}] = {}} print(refser.save(x)) -- {{|}|{|}{|}}
-
A table with self-references.
x = {} x[x] = x print(refser.save(x)) -- {|@1@1}
-
A more complicated example of cross-references.
x = {} y = {} y[y] = y x[x] = y print(refser.save(x)) -- {|@1{|@2@2}}
@1
isx
and@2
isy
. -
A tuple with cross-references.
x = {} print(refser.save(x, x, {x})) -- {|}@1{@1|}
Copyright © 2013 lua4web lua4web@gmail.com
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.