Commit 7e67b55d authored by François Perrad's avatar François Perrad
Browse files

first code

parent 0f9e2457
LUA := lua
VERSION := $(shell cd src && $(LUA) -e "m = require [[MessagePack]]; print(m._VERSION)")
TARBALL := lua-messagepack-$(VERSION).tar.gz
REV := 1
LUAVER := 5.1
PREFIX := /usr/local
DPREFIX := $(DESTDIR)$(PREFIX)
LIBDIR := $(DPREFIX)/share/lua/$(LUAVER)
INSTALL := install
all:
@echo "Nothing to build here, you can just make install"
install:
$(INSTALL) -m 644 -D src/MessagePack.lua $(LIBDIR)/MessagePack.lua
uninstall:
rm -f $(LIBDIR)/MessagePack.lua
manifest_pl := \
use strict; \
use warnings; \
my @files = qw{MANIFEST}; \
while (<>) { \
chomp; \
next if m{^\.}; \
next if m{^doc/\.}; \
next if m{^doc/google}; \
next if m{^rockspec/}; \
push @files, $$_; \
} \
print join qq{\n}, sort @files;
rockspec_pl := \
use strict; \
use warnings; \
use Digest::MD5; \
open my $$FH, q{<}, q{$(TARBALL)} \
or die qq{Cannot open $(TARBALL) ($$!)}; \
binmode $$FH; \
my %config = ( \
version => q{$(VERSION)}, \
rev => q{$(REV)}, \
md5 => Digest::MD5->new->addfile($$FH)->hexdigest(), \
); \
close $$FH; \
while (<>) { \
s{@(\w+)@}{$$config{$$1}}g; \
print; \
}
version:
@echo $(VERSION)
CHANGES:
perl -i.bak -pe "s{^$(VERSION).*}{q{$(VERSION) }.localtime()}e" CHANGES
tag:
git tag -a -m 'tag release $(VERSION)' $(VERSION)
doc:
git read-tree --prefix=doc/ -u remotes/origin/gh-pages
MANIFEST: doc
git ls-files | perl -e '$(manifest_pl)' > MANIFEST
$(TARBALL): MANIFEST
[ -d lua-MessagePack-$(VERSION) ] || ln -s . lua-MessagePack-$(VERSION)
perl -ne 'print qq{lua-TestLongString-$(VERSION)/$$_};' MANIFEST | \
tar -zc -T - -f $(TARBALL)
rm lua-MessagePack-$(VERSION)
rm -rf doc
git rm doc/*
dist: $(TARBALL)
rockspec: $(TARBALL)
perl -e '$(rockspec_pl)' rockspec.in > rockspec/lua-messagepack-$(VERSION)-$(REV).rockspec
check: test
test:
cd src && prove --exec=$(LUA) ../test/*.t
coverage:
rm -f src/luacov.stats.out src/luacov.report.out
cd src && prove --exec="$(LUA) -lluacov" ../test/*.t
cd src && luacov
README.html: README.md
Markdown.pl README.md > README.html
clean:
rm -rf doc
rm -f MANIFEST *.bak src/luacov.*.out README.html
realclean: clean
.PHONY: test rockspec CHANGES
lua-MessagePack
===============
lua-MessagePack : a pure Lua implementation
===========================================
Introduction
------------
[MessagePack](http://msgpack.org/) is an efficient binary serialization format.
It lets you exchange data among multiple languages like JSON but it's faster and smaller.
Links
-----
......
package = 'lua-MessagePack'
version = '@version@-@rev@'
source = {
url = 'http://cloud.github.com/downloads/fperrad/lua-MessagePack/lua-messagepack-@version@.tar.gz',
md5 = '@md5@',
dir = 'lua-MessagePack-@version@',
}
description = {
summary = "a pure Lua implementation",
detailed = [[
MessagePack is an efficient binary serialization format.
It lets you exchange data among multiple languages like JSON but it's faster and smaller.
]],
homepage = 'http://fperrad.github.com/lua-MessagePack/',
maintainer = 'Francois Perrad',
license = 'MIT/X11'
}
dependencies = {
'lua >= 5.1',
}
build = {
type = 'builtin',
modules = {
['MessagePack'] = 'src/MessagePack.lua',
},
copy_directories = { 'doc', 'test' },
}
--
-- lua-MessagePack : <http://fperrad.github.com/lua-MessagePack/>
--
local r, jit = pcall(require, 'jit')
if not r then
jit = nil
end
local SIZEOF_NUMBER = 8
local NUMBER_INTEGRAL = false
if not jit then
-- Lua 5.1 & 5.2
local loadstring = loadstring or load
local luac = string.dump(loadstring "a = 1")
local header = { luac:sub(1, 12):byte(1, 12) }
SIZEOF_NUMBER = header[11]
NUMBER_INTEGRAL = 1 == header[12]
end
local error = error
local pairs = pairs
local setmetatable = setmetatable
local tostring = tostring
local type = type
local char = require'string'.char
local floor = require'math'.floor
local frexp = require'math'.frexp
local ldexp = require'math'.ldexp
local huge = require'math'.huge
local tconcat = require'table'.concat
_ENV = nil
local m = {}
local function argerror (caller, narg, extramsg)
error("bad argument #" .. tostring(narg) .. " to "
.. caller .. " (" .. extramsg .. ")")
end
local function typeerror (caller, narg, arg, tname)
argerror(caller, narg, tname .. " expected, got " .. type(arg))
end
local function checktype (caller, narg, arg, tname)
if type(arg) ~= tname then
typeerror(caller, narg, arg, tname)
end
end
local packers = setmetatable({}, {
__index = function (t, k) error("pack '" .. k .. "' is unimplemented") end
})
packers['nil'] = function (buffer)
buffer[#buffer+1] = char(0xC0) -- nil
end
packers['boolean'] = function(buffer, bool)
if bool then
buffer[#buffer+1] = char(0xC3) -- true
else
buffer[#buffer+1] = char(0xC2) -- false
end
end
packers['string'] = function(buffer, str)
local n = #str
if n <= 0x1F then
buffer[#buffer+1] = char(0xA0 + n) -- fixraw
elseif n <= 0xFFFF then
buffer[#buffer+1] = char(0xDA, -- raw16
floor(n / 0x100),
n % 0x100)
elseif n <= 0xFFFFFFFF then
buffer[#buffer+1] = char(0xDB, -- raw32
floor(n / 0x1000000),
floor(n / 0x10000) % 0x100,
floor(n / 0x100) % 0x100,
n % 0x100)
else
error"overflow in pack 'string'"
end
buffer[#buffer+1] = str
end
packers['table'] = function(buffer, tbl)
local is_map, n, max = false, 0, 0
for k in pairs(tbl) do
if type(k) == 'number' and k > 0 then
if k > max then
max = k
end
else
is_map = true
end
n = n + 1
end
if max ~= n then -- there are holes
is_map = true
end
if is_map then
if n <= 0x0F then
buffer[#buffer+1] = char(0x80 + n) -- fixmap
elseif n <= 0xFFFF then
buffer[#buffer+1] = char(0xDE, -- map16
floor(n / 0x100),
n % 0x100)
elseif n <= 0xFFFFFFFF then
buffer[#buffer+1] = char(0xDF, -- map32
floor(n / 0x1000000),
floor(n / 0x10000) % 0x100,
floor(n / 0x100) % 0x100,
n % 0x100)
else
error"overflow in pack 'map'"
end
for k, v in pairs(tbl) do
packers[type(k)](buffer, k)
packers[type(v)](buffer, v)
end
else
if n <= 0x0F then
buffer[#buffer+1] = char(0x90 + n) -- fixarray
elseif n <= 0xFFFF then
buffer[#buffer+1] = char(0xDC, -- array16
floor(n / 0x100),
n % 0x100)
elseif n <= 0xFFFFFFFF then
buffer[#buffer+1] = char(0xDD, -- array32
floor(n / 0x1000000),
floor(n / 0x10000) % 0x100,
floor(n / 0x100) % 0x100,
n % 0x100)
else
error"overflow in pack 'array'"
end
for i = 1, n do
local v = tbl[i]
packers[type(v)](buffer, v)
end
end
end
packers['integer'] = function(buffer, n)
if n >= 0 then
if n <= 0x7F then
buffer[#buffer+1] = char(n) -- fixnum_pos
elseif n <= 0xFF then
buffer[#buffer+1] = char(0xCC, -- uint8
n)
elseif n <= 0xFFFF then
buffer[#buffer+1] = char(0xCD, -- uint16
floor(n / 0x100),
n % 0x100)
elseif n <= 0xFFFFFFFF then
buffer[#buffer+1] = char(0xCE, -- uint32
floor(n / 0x1000000),
floor(n / 0x10000) % 0x100,
floor(n / 0x100) % 0x100,
n % 0x100)
else
return packers['uint64'](buffer, n)
end
else
if n >= -0x20 then
buffer[#buffer+1] = char(0xE0 + 0x20 + n) -- fixnum_neg
elseif n >= -0x80 then
buffer[#buffer+1] = char(0xD0, -- int8
0x100 + n)
elseif n >= -0x8000 then
n = 0x10000 + n
buffer[#buffer+1] = char(0xD1, -- int16
floor(n / 0x100),
n % 0x100)
elseif n >= -0x80000000 then
n = 0x100000000 + n
buffer[#buffer+1] = char(0xD2, -- int32
floor(n / 0x1000000),
floor(n / 0x10000) % 0x100,
floor(n / 0x100) % 0x100,
n % 0x100)
else
return packers['int64'](buffer, n)
end
end
end
packers['float'] = function (buffer, n)
if n ~= n then -- nan
buffer[#buffer+1] = char(0xCA,
0xFF, 0x88, 0x00, 0x00)
elseif n == huge then
buffer[#buffer+1] = char(0xCA,
0x7F, 0x80, 0x00, 0x00)
elseif n == -huge then
buffer[#buffer+1] = char(0xCA,
0xFF, 0x80, 0x00, 0x00)
else
local sign = 0
if n < 0 then
sign = 0x80
n = -n
end
local mant, expo = frexp(n)
mant = (mant * 2 - 1) * ldexp(0.5, 24)
expo = expo + 0x7E
buffer[#buffer+1] = char(0xCA,
sign + floor(expo / 0x2),
(expo % 0x2) * 0x80 + floor(mant / 0x10000),
floor(mant / 0x100) % 0x100,
mant % 0x100)
end
end
packers['double'] = function (buffer, n)
if n ~= n then -- nan
buffer[#buffer+1] = char(0xCB,
0xFF, 0xF8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
elseif n == huge then
buffer[#buffer+1] = char(0xCB,
0x7F, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
elseif n == -huge then
buffer[#buffer+1] = char(0xCB,
0xFF, 0xF0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00)
else
local sign = 0
if n < 0 then
sign = 0x80
n = -n
end
local mant, expo = frexp(n)
mant = (mant * 2 - 1) * ldexp(0.5, 53)
expo = expo + 0x3FE
buffer[#buffer+1] = char(0xCB,
sign + floor(expo / 0x10),
(expo % 0x10) * 0x10 + floor(mant / 0x1000000000000),
floor(mant / 0x10000000000) % 0x100,
floor(mant / 0x100000000) % 0x100,
floor(mant / 0x1000000) % 0x100,
floor(mant / 0x10000) % 0x100,
floor(mant / 0x100) % 0x100,
mant % 0x100)
end
end
local set_number = function(number)
if number == 'integer' then
packers['number'] = packers['integer']
elseif number == 'float' then
packers['number'] = function (buffer, n)
if floor(n) ~= n or n ~= n or n == huge or n == -huge then
return packers['float'](buffer, n)
else
return packers['integer'](buffer, n)
end
end
packers['uint64'] = packers['float']
packers['int64'] = packers['float']
elseif number == 'double' then
packers['number'] = function (buffer, n)
if floor(n) ~= n or n ~= n or n == huge or n == -huge then
return packers['double'](buffer, n)
else
return packers['integer'](buffer, n)
end
end
packers['uint64'] = packers['double']
packers['int64'] = packers['double']
else
argerror ('set_number', 1, "invalid option '" .. number .."'")
end
end
m.set_number = set_number
local types_map = setmetatable({
[0xC0] = 'nil',
[0xC2] = 'false',
[0xC3] = 'true',
[0xCA] = 'float',
[0xCB] = 'double',
[0xCC] = 'uint8',
[0xCD] = 'uint16',
[0xCE] = 'uint32',
[0xCF] = 'uint64',
[0xD0] = 'int8',
[0xD1] = 'int16',
[0xD2] = 'int32',
[0xD3] = 'int64',
[0xDA] = 'raw16',
[0xDB] = 'raw32',
[0xDC] = 'array16',
[0xDD] = 'array32',
[0xDE] = 'map16',
[0xDF] = 'map32',
}, { __index = function (t, k)
if k < 0xC0 then
if k < 0x80 then
return 'fixnum_pos'
elseif k < 0x90 then
return 'fixmap'
elseif k < 0xA0 then
return 'fixarray'
else
return 'fixraw'
end
elseif k > 0xDF then
return 'fixnum_neg'
else
return 'reserved' .. k
end
end })
local unpackers = setmetatable({}, {
__index = function (t, k) error("unpack '" .. k .. "' is unimplemented") end
})
local function unpack_array(c, n)
local t = {}
while n > 0 do
local v = unpackers['any'](c)
t[#t+1] = v
n = n-1
end
return t
end
local function unpack_map(c, n)
local t = {}
while n > 0 do
local k = unpackers['any'](c)
local v = unpackers['any'](c)
t[k] = v
n = n-1
end
return t
end
unpackers['any'] = function (c)
local s, i, j = c.s, c.i, c.j
if i > j then
c:underflow()
end
local val = s:sub(i, i):byte()
c.i = i+1
return unpackers[types_map[val]](c, val)
end
unpackers['nil'] = function (c)
return nil
end
unpackers['false'] = function(c)
return false
end
unpackers['true'] = function(c)
return true
end
unpackers['float'] = function(c)
local s, i, j = c.s, c.i, c.j
if i+3 > j then
c:underflow()
end
local b1, b2, b3, b4 = s:sub(i, i+3):byte(1, 4)
local sign = b1 > 0x7F
local expo = (b1 % 0x80) * 0x2 + floor(b2 / 0x80)
local mant = ((b2 % 0x80) * 0x100 + b3) * 0x100 + b4
if sign then
sign = -1
else
sign = 1
end
local n
if mant == 0 and expo == 0 then
n = 0
elseif mant == 0 and expo == 0xFF then
n = sign * huge
else
n = sign * ldexp(1 + mant / 0x800000, expo - 0x7F)
end
c.i = i+4
return n
end
unpackers['double'] = function(c)
local s, i, j = c.s, c.i, c.j
if i+7 > j then
c:underflow()
end
local b1, b2, b3, b4, b5, b6, b7, b8 = s:sub(i, i+7):byte(1, 8)
local sign = b1 > 0x7F
local expo = (b1 % 0x80) * 0x10 + floor(b2 / 0x10)
local mant = ((((((b2 % 0x10) * 0x100 + b3) * 0x100 + b4) * 0x100 + b5) * 0x100 + b6) * 0x100 + b7) * 0x100 + b8
if sign then
sign = -1
else
sign = 1
end
local n
if mant == 0 and expo == 0 then
n = 0
elseif mant == 0 and expo == 0x7FF then
n = sign * huge
else
n = sign * ldexp(1 + mant / 0x10000000000000, expo - 0x3FF)
end
c.i = i+8
return n
end
unpackers['fixnum_pos'] = function (c, val)
return val
end
unpackers['uint8'] = function(c)
local s, i, j = c.s, c.i, c.j
if i > j then
c:underflow()
end
local b1 = s:sub(i, i):byte()
c.i = i+1
return b1
end
unpackers['uint16'] = function(c)
local s, i, j = c.s, c.i, c.j
if i+1 > j then
c:underflow()
end
local b1, b2 = s:sub(i, i+1):byte(1, 2)
c.i = i+2
return b1 * 0x100 + b2
end
unpackers['uint32'] = function(c)
local s, i, j = c.s, c.i, c.j
if i+3 > j then
c:underflow()
end
local b1, b2, b3, b4 = s:sub(i, i+3):byte(1, 4)
c.i = i+4
return ((b1 * 0x100 + b2) * 0x100 + b3) * 0x100 + b4
end
unpackers['fixnum_neg'] = function (c, val)
return val % 0x20 - 0x20
end
unpackers['int8'] = function(c)
local s, i, j = c.s, c.i, c.j
if i > j then
c:underflow()
end
local b1 = s:sub(i, i):byte()
c.i = i+1
return b1 - 0x100
end
unpackers['int16'] = function(c)
local s, i, j = c.s, c.i, c.j
if i+1 > j then
c:underflow()
end
local b1, b2 = s:sub(i, i+1):byte(1, 2)
c.i = i+2