From 6b5b76b0c908c338dbc4aaa86aa42722da4adca3 Mon Sep 17 00:00:00 2001 From: UENISHI Kota Date: Sun, 30 May 2010 15:01:10 +0900 Subject: [PATCH 1/6] initial import from http://bitbucket.org/kuenishi/messagepack-for-erlang --- erlang/.gitignore | 3 + erlang/msgpack.erl | 377 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 380 insertions(+) create mode 100644 erlang/.gitignore create mode 100644 erlang/msgpack.erl diff --git a/erlang/.gitignore b/erlang/.gitignore new file mode 100644 index 00000000..911d6e38 --- /dev/null +++ b/erlang/.gitignore @@ -0,0 +1,3 @@ +MANIFEST +*.beam + diff --git a/erlang/msgpack.erl b/erlang/msgpack.erl new file mode 100644 index 00000000..4b8da47b --- /dev/null +++ b/erlang/msgpack.erl @@ -0,0 +1,377 @@ +%% +%% MessagePack for Erlang +%% +%% Copyright (C) 2009 UENISHI Kota +%% +%% Licensed under the Apache License, Version 2.0 (the "License"); +%% you may not use this file except in compliance with the License. +%% You may obtain a copy of the License at +%% +%% http://www.apache.org/licenses/LICENSE-2.0 +%% +%% Unless required by applicable law or agreed to in writing, software +%% distributed under the License is distributed on an "AS IS" BASIS, +%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +%% See the License for the specific language governing permissions and +%% limitations under the License. +% +% Thanks to id:frsyuki for his sophiscated binary format specification. +% + +-module(msgpack). +-author('kuenishi+msgpack@gmail.com'). + +-export([pack/1, unpack/1, unpack_all/1, test/0]). + +% compile: +% erl> c(msgpack). +% erl> S = . +% erl> {S, <<>>} = msgpack:unpack( msgpack:pack(S) ). + +%% tuples, atoms are not supported. +%% lists, integers, double, and so on. +%% see http://msgpack.sourceforge.jp/spec for +%% supported formats. APIs are almost compatible +%% for C API (http://msgpack.sourceforge.jp/c:doc) +%% except buffering functions (both copying and zero-copying). +-export([ + pack_fixnum/1, + pack_nfixnum/1, + pack_uint8/1, + pack_uint16/1, + pack_uint32/1, + pack_uint64/1, + pack_short/1, + pack_int8/1, + pack_int/1, + pack_long/1, + pack_long_long/1, + pack_unsigned_short/1, + pack_unsigned_int/1, + pack_unsigned_long/1, + pack_unsigned_long_long/1, + pack_nil/0, + pack_bool/1, + pack_float/1, + pack_double/1, + pack_raw/1, + pack_array/1, + pack_map/1, + pack_object/1 ]). + + +% packing functions + +pack_short(N) when is_integer(N)-> + pack_int16(N). +pack_int(N) when is_integer(N)-> + pack_int32(N). +pack_long(N) when is_integer(N)-> + pack_int32(N). +pack_long_long(N) when is_integer(N)-> + pack_int64(N). +pack_unsigned_short(N) when is_integer(N)-> + pack_uint16(N). +pack_unsigned_int(N) when is_integer(N)-> + pack_uint32(N). +pack_unsigned_long(N) when is_integer(N)-> + pack_uint32(N). +pack_unsigned_long_long(N) when is_integer(N)-> + pack_uint64(N). + +% positive fixnum +pack_fixnum( N ) when is_integer( N ) and N >= 0 , N < 128 -> + << 2#0:1, N:7 >>. +% negative fixnum +pack_nfixnum( N ) when is_integer( N ) and N >= -32 , N < 0 -> + << 2#111:3, N:5 >>. +% uint 8 +pack_uint8( N ) when is_integer( N )-> + << 16#CC:8, N:8 >>. +% uint 16 +pack_uint16( N ) when is_integer( N )-> + << 16#CD:8, N:16/big-unsigned-integer-unit:1 >>. +% uint 32 +pack_uint32( N ) when is_integer( N )-> + << 16#CE:8, N:32/big-unsigned-integer-unit:1 >>. +% uint 64 +pack_uint64( N ) when is_integer( N )-> + << 16#CF:8, N:64/big-unsigned-integer-unit:1 >>. +% int 8 +pack_int8( N ) when is_integer( N )-> + << 16#D0:8, N:8 >>. +% int 16 +pack_int16( N ) when is_integer( N )-> + << 16#D1:8, N:16/big-signed-integer-unit:1 >>. +% int 32 +pack_int32( N ) when is_integer( N )-> + << 16#D2:8, N:32/big-signed-integer-unit:1 >>. +% int 64 +pack_int64( N ) when is_integer( N )-> + << 16#D3:8, N:64/big-signed-integer-unit:1 >>. + +% nil +pack_nil()-> + << 16#C0:8 >>. +% pack_true / pack_false +pack_bool(true)-> << 16#C3:8 >>; +pack_bool(false)-> << 16#C2:8 >>. + +% float : erlang's float is always IEEE 754 64bit format. +pack_float(F) when is_float(F)-> +% << 16#CA:8, F:32/big-float-unit:1 >>. + pack_double(F). +% double +pack_double(F) when is_float(F)-> + << 16#CB:8, F:64/big-float-unit:1 >>. + +power(N,0) when is_integer(N) -> 1; +power(N,D) when is_integer(N) and is_integer(D) -> N * power(N, D-1). + +% raw bytes +pack_raw(Bin) when is_binary(Bin)-> + MaxLen = power(2,16), + case byte_size(Bin) of + Len when Len < 6-> + << 2#101:3, Len:5, Bin/binary >>; + Len when Len < MaxLen -> + << 16#DA:8, Len:16/big-unsigned-integer-unit:1, Bin/binary >>; + Len -> + << 16#DB:8, Len:32/big-unsigned-integer-unit:1, Bin/binary >> + end. + +% list / tuple +pack_array(L) when is_list(L)-> + MaxLen = power(2,16), + case length(L) of + Len when Len < 16 -> + << 2#1001:4, Len:4/integer-unit:1, (pack_array_(L))/binary >>; + Len when Len < MaxLen -> + << 16#DC:8, Len:16/big-unsigned-integer-unit:1,(pack_array_(L))/binary >>; + Len -> + << 16#DD:8, Len:32/big-unsigned-integer-unit:1,(pack_array_(L))/binary >> + end. +pack_array_([])-> <<>>; +pack_array_([Head|Tail])-> + << (pack_object(Head))/binary, (pack_array_(Tail))/binary >>. + +unpack_array_(<<>>, 0)-> []; +unpack_array_(Remain, 0) when is_binary(Remain)-> [Remain]; +unpack_array_(Bin, RestLen) when is_binary(Bin)-> + {Term, Rest} = unpack(Bin), + [Term|unpack_array_(Rest, RestLen-1)]. + +pack_map({dict,M})-> + MaxLen = power(2,16), + case dict:size(M) of + Len when Len < 16 -> + << 2#1001:4, Len:4/integer-unit:1, (pack_map_(dict:to_list(M))) >>; + Len when Len < MaxLen -> + << 16#DE:8, Len:16/big-unsigned-integer-unit:1, (pack_map_(dict:to_list(M))) >>; + Len -> + << 16#DF:8, Len:32/big-unsigned-integer-unit:1, (pack_map_(dict:to_list(M))) >> + end. + +pack_map_([])-> <<>>; +pack_map_([{Key,Value}|Tail]) -> + << (pack_object(Key)),(pack_object(Value)),(pack_map_(Tail)) >>. + +unpack_map_(<<>>, 0)-> []; +unpack_map_(Bin, 0) when is_binary(Bin)-> [Bin]; +unpack_map_(Bin, Len) when is_binary(Bin) and is_integer(Len) -> + { Key, Rest } = unpack(Bin), + { Value, Rest2 } = unpack(Rest), + [{Key,Value}|unpack_map_(Rest2,Len-1)]. + +pack_object(O) when is_integer(O)-> + pack_long_long(O); +pack_object(O) when is_float(O)-> + pack_double(O); +pack_object(nil) -> + pack_nil(); +pack_object(Bool) when is_atom(Bool) -> + pack_bool(Bool); +pack_object(Bin) when is_binary(Bin)-> + pack_raw(Bin); +pack_object(List) when is_list(List)-> + pack_array(List); +pack_object({dict, Map})-> + pack_map({dict, Map}); +pack_object(_) -> + undefined. + +pack(Obj)-> + pack_object(Obj). + + +% unpacking. +% if failed in decoding and not end, get more data +% and feed more Bin into this function. +% TODO: error case for imcomplete format when short for any type formats. +-spec unpack( binary() )-> {term(), binary()}. +unpack(Bin) when bit_size(Bin) >= 8 -> + << Flag:8, Payload/binary >> = Bin, + case Flag of + 16#C0 -> + {nil, Payload}; + 16#C2 -> + {false, Payload}; + 16#C3 -> + {true, Payload}; + 16#CA -> % 32bit float + << Return:32/float-unit:1, Rest/binary >> = Payload, + {Return, Rest}; + 16#CB -> % 64bit float + << Return:64/float-unit:1, Rest/binary >> = Payload, + {Return, Rest}; + 16#CC -> + << Int:8/unsigned-integer, Rest/binary >> = Payload, + {Int, Rest}; + 16#CD -> + << Int:16/big-unsigned-integer-unit:1, Rest/binary >> = Payload, + {Int, Rest}; + 16#CE -> + << Int:32/big-unsigned-integer-unit:1, Rest/binary >> = Payload, + {Int, Rest}; + 16#CF -> + << Int:64/big-unsigned-integer-unit:1, Rest/binary >> = Payload, + {Int, Rest}; + 16#D0 -> + << Int:8/big-signed-integer-unit:1, Rest/binary >> = Payload, + {Int, Rest}; + 16#D1 -> + << Int:16/big-signed-integer-unit:1, Rest/binary >> = Payload, + {Int, Rest}; + 16#D2 -> + << Int:32/big-signed-integer-unit:1, Rest/binary >> = Payload, + {Int, Rest}; + 16#D3 -> + << Int:64/big-signed-integer-unit:1, Rest/binary >> = Payload, + {Int, Rest}; + 16#DA -> % raw 16 + << Len:16/unsigned-integer-unit:1, Rest/binary >> = Payload, + << Return:Len/binary, Remain/binary >> = Rest, + {Return, Remain}; + 16#DB -> % raw 32 + << Len:32/big-unsigned-integer-unit:1, Rest/binary >> = Payload, + << Return:Len/binary, Remain/binary >> = Rest, + {Return, Remain}; + 16#DC -> % array 16 + << Len:16/big-unsigned-integer-unit:1, Rest/binary >> = Payload, + Array=unpack_array_(Rest, Len), + case length(Array) of + Len -> {Array, <<>>}; + _ -> + {Return, RemainRest} = lists:split(Len, Array), + [Remain] = RemainRest, + {Return, Remain} + end; + 16#DD -> % array 32 + << Len:32/big-unsigned-integer-unit:1, Rest/binary >> = Payload, + Array=unpack_array_(Rest, Len), + case length(Array) of + Len -> {Array, <<>>}; + _ -> + {Return, RemainRest} = lists:split(Len, Array), + [Remain] = RemainRest, + {Return, Remain} + end; + 16#DE -> % map 16 + << Len:16/big-unsigned-integer-unit:1, Rest/binary >> = Payload, + Array=unpack_map_(Rest, Len), + case length(Array) of + Len -> { dict:from_list(Array), <<>>}; + _ -> + {Return, RemainRest} = lists:split(Len, Array), + [Remain] = RemainRest, + {dict:from_list(Return), Remain} + end; + 16#DF -> % map 32 + << Len:32/big-unsigned-integer-unit:1, Rest/binary >> = Payload, + Array=unpack_map_(Rest, Len), + case length(Array) of + Len -> { dict:from_list(Array), <<>>}; + _ -> + {Return, RemainRest} = lists:split(Len, Array), + [Remain] = RemainRest, + {dict:from_list(Return), Remain} + end; + + Code when Code >= 2#10100000 , Code < 2#11000000 -> +% 101XXXXX for FixRaw + Len = Code rem 2#10100000, + << Return:Len/binary, Remain/binary >> = Payload, + {Return, Remain}; + + Code when Code >= 2#10010000 , Code < 2#10100000 -> +% 1001XXXX for FixArray + Len = Code rem 2#10010000, + Array=unpack_array_(Payload, Len), + case length(Array) of + Len -> { Array, <<>>}; + _ -> + {Return, RemainRest} = lists:split(Len, Array), + [Remain] = RemainRest, + {Return, Remain} + end; + + Code when Code >= 2#10000000 , Code < 2#10010000 -> +% 1000XXXX for FixMap + Len = Code rem 2#10000000, + Array=unpack_map_(Payload, Len), + case length(Array) of + Len -> { dict:from_list(Array), <<>>}; + _ -> + {Return, RemainRest} = lists:split(Len, Array), + [Remain] = RemainRest, + {dict:from_list(Return), Remain} + end; + + _ -> + {error, no_code_matches} + end. + +unpack_all(Data)-> + case unpack(Data) of + { Term, Binary } when bit_size(Binary) =:= 0 -> + [Term]; + { Term, Binary } when is_binary(Binary) -> + [Term|unpack_all(Binary)] + end. + +test()-> + Tests = [0, 1, 2, 123, 123.123, [23, 234, 0.23], "hogehoge", <<"hoasfdafdas][">>], + Passed = test_(Tests), + Passed = length(Tests). +%% Port = open_port({spawn, "./a.out"}, [stream]), +%% receive {Port, {data, Data}}-> +%% io:format("~p~n", [unpack_all( list_to_binary(Data) )]) +%% after 1024-> timeout end, +%% Passed2 = test_(Tests, Port), +%% Passed2 = length(Tests), +%% Port ! {self(), close}, +%% receive {Port, closed}-> ok +%% after 1024 -> timeout end. + +test_([]) -> 0; +test_([S|Rest])-> +% io:format("testing: ~p~n", [S]), + {S, <<>>} = msgpack:unpack( msgpack:pack(S) ), + test_(Rest) + 1. + +test_([], _)-> 0; +test_([S|Rest], Port) -> + Bin = msgpack:pack(S), + io:format("sending: ~p - ", [S]), + Port ! {self(), {command, Bin}}, + receive + {Port, {data, Data}}-> + io:format("~p~n", [Data]), + test_(Rest, Port) + 1; + Other-> + io:format("fail: ~p~n", [Other]) + after 1024-> + test_(Rest, Port) + end. + + From d43921823ea5a20f0677410e965a54dd19c2effe Mon Sep 17 00:00:00 2001 From: Hideyuki Tanaka Date: Sun, 30 May 2010 17:19:43 +0900 Subject: [PATCH 2/6] fix initialize pointer --- haskell/src/Data/MessagePack/Base.hsc | 1 + 1 file changed, 1 insertion(+) diff --git a/haskell/src/Data/MessagePack/Base.hsc b/haskell/src/Data/MessagePack/Base.hsc index 72c421ce..8c7b9f54 100644 --- a/haskell/src/Data/MessagePack/Base.hsc +++ b/haskell/src/Data/MessagePack/Base.hsc @@ -560,6 +560,7 @@ unpackObject z dat = allocaBytes (#size msgpack_object) $ \ptr -> BS.useAsCStringLen dat $ \(str, len) -> alloca $ \poff -> do + poke poff 0 ret <- msgpack_unpack str (fromIntegral len) poff z ptr case ret of (#const MSGPACK_UNPACK_SUCCESS) -> do From 0da22193bd628690bfc58d4c36d6d48493fa7f51 Mon Sep 17 00:00:00 2001 From: Hideyuki Tanaka Date: Sun, 30 May 2010 17:20:49 +0900 Subject: [PATCH 3/6] fix typo --- haskell/src/Data/MessagePack/Monad.hs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haskell/src/Data/MessagePack/Monad.hs b/haskell/src/Data/MessagePack/Monad.hs index c718b8ad..15f21fe0 100644 --- a/haskell/src/Data/MessagePack/Monad.hs +++ b/haskell/src/Data/MessagePack/Monad.hs @@ -82,7 +82,7 @@ packToString m = do _ <- runPackerT m pc liftIO $ simpleBufferData sb --- | Execcute given serializer and write byte sequence to Handle. +-- | Execute given serializer and write byte sequence to Handle. packToHandle :: MonadIO m => Handle -> PackerT m r -> m () packToHandle h m = do sb <- packToString m From e61dc76ae1abb6235d09b52ad24383ccd75d5222 Mon Sep 17 00:00:00 2001 From: Hideyuki Tanaka Date: Sun, 30 May 2010 19:11:04 +0900 Subject: [PATCH 4/6] fix peek object --- haskell/src/Data/MessagePack/Base.hsc | 18 ++++++++++-------- 1 file changed, 10 insertions(+), 8 deletions(-) diff --git a/haskell/src/Data/MessagePack/Base.hsc b/haskell/src/Data/MessagePack/Base.hsc index 8c7b9f54..b6cdc287 100644 --- a/haskell/src/Data/MessagePack/Base.hsc +++ b/haskell/src/Data/MessagePack/Base.hsc @@ -506,20 +506,22 @@ peekObjectRAW ptr = do peekObjectArray :: Ptr a -> IO Object peekObjectArray ptr = do - size <- (#peek msgpack_object, via.array.size) ptr - p <- (#peek msgpack_object, via.array.ptr) ptr - objs <- mapM (\i -> peekObject $ p `plusPtr` + csize <- (#peek msgpack_object, via.array.size) ptr + let size = fromIntegral (csize :: Word32) + p <- (#peek msgpack_object, via.array.ptr) ptr + objs <- mapM (\i -> peekObject $ p `plusPtr` ((#size msgpack_object) * i)) - [0..size-1] + [0..size-1] return $ ObjectArray objs peekObjectMap :: Ptr a -> IO Object peekObjectMap ptr = do - size <- (#peek msgpack_object, via.map.size) ptr - p <- (#peek msgpack_object, via.map.ptr) ptr - dat <- mapM (\i -> peekObjectKV $ p `plusPtr` + csize <- (#peek msgpack_object, via.map.size) ptr + let size = fromIntegral (csize :: Word32) + p <- (#peek msgpack_object, via.map.ptr) ptr + dat <- mapM (\i -> peekObjectKV $ p `plusPtr` ((#size msgpack_object_kv) * i)) - [0..size-1] + [0..size-1] return $ ObjectMap dat peekObjectKV :: Ptr a -> IO (Object, Object) From 5a12d36a0a68e97dcdd2e030486f6a67138c8b44 Mon Sep 17 00:00:00 2001 From: Hideyuki Tanaka Date: Sun, 30 May 2010 19:45:00 +0900 Subject: [PATCH 5/6] incr version --- haskell/msgpack.cabal | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/haskell/msgpack.cabal b/haskell/msgpack.cabal index 31cad3bc..82cdb525 100644 --- a/haskell/msgpack.cabal +++ b/haskell/msgpack.cabal @@ -1,5 +1,5 @@ Name: msgpack -Version: 0.2.1 +Version: 0.2.2 License: BSD3 License-File: LICENSE Author: Hideyuki Tanaka From d7d78d9a2b77df0661fb0cd6b0be7b565e6f7a25 Mon Sep 17 00:00:00 2001 From: UENISHI Kota Date: Mon, 31 May 2010 00:25:53 +0900 Subject: [PATCH 6/6] added more tests, and OMake continuous building. --- erlang/OMakefile | 42 +++++++++++++ erlang/OMakeroot | 45 ++++++++++++++ erlang/msgpack.erl | 152 +++++++++++++++++++-------------------------- 3 files changed, 151 insertions(+), 88 deletions(-) create mode 100644 erlang/OMakefile create mode 100644 erlang/OMakeroot diff --git a/erlang/OMakefile b/erlang/OMakefile new file mode 100644 index 00000000..ee72f784 --- /dev/null +++ b/erlang/OMakefile @@ -0,0 +1,42 @@ +######################################################################## +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this file, to deal in the File without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the File, and to permit persons to whom the +# File is furnished to do so, subject to the following condition: +# +# THE FILE 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 FILE OR +# THE USE OR OTHER DEALINGS IN THE FILE. + +######################################################################## +# The standard OMakefile. +# You will usually need to modify this file for your project. + +######################################################################## +# Phony targets are scoped, so you probably want to declare them first. +# + +.PHONY: all clean test #install + +######################################################################## +# Subdirectories. +# You may want to include some subdirectories in this project. +# If so, define the subdirectory targets and uncomment this section. +# + +.DEFAULT: msgpack.beam + +msgpack.beam: msgpack.erl + erlc $< + +test: msgpack.beam + erl -s msgpack test -s init stop + +clean: + -rm *.beam diff --git a/erlang/OMakeroot b/erlang/OMakeroot new file mode 100644 index 00000000..35c219da --- /dev/null +++ b/erlang/OMakeroot @@ -0,0 +1,45 @@ +######################################################################## +# Permission is hereby granted, free of charge, to any person +# obtaining a copy of this file, to deal in the File without +# restriction, including without limitation the rights to use, +# copy, modify, merge, publish, distribute, sublicense, and/or +# sell copies of the File, and to permit persons to whom the +# File is furnished to do so, subject to the following condition: +# +# THE FILE 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 FILE OR +# THE USE OR OTHER DEALINGS IN THE FILE. + +######################################################################## +# The standard OMakeroot file. +# You will not normally need to modify this file. +# By default, your changes should be placed in the +# OMakefile in this directory. +# +# If you decide to modify this file, note that it uses exactly +# the same syntax as the OMakefile. +# + +# +# Include the standard installed configuration files. +# Any of these can be deleted if you are not using them, +# but you probably want to keep the Common file. +# +open build/C +open build/OCaml +open build/LaTeX + +# +# The command-line variables are defined *after* the +# standard configuration has been loaded. +# +DefineCommandVars() + +# +# Include the OMakefile in this directory. +# +.SUBDIRS: . diff --git a/erlang/msgpack.erl b/erlang/msgpack.erl index 4b8da47b..df7974db 100644 --- a/erlang/msgpack.erl +++ b/erlang/msgpack.erl @@ -14,42 +14,25 @@ %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %% See the License for the specific language governing permissions and %% limitations under the License. -% -% Thanks to id:frsyuki for his sophiscated binary format specification. -% -module(msgpack). -author('kuenishi+msgpack@gmail.com'). -export([pack/1, unpack/1, unpack_all/1, test/0]). +-include_lib("eunit/include/eunit.hrl"). + % compile: % erl> c(msgpack). % erl> S = . % erl> {S, <<>>} = msgpack:unpack( msgpack:pack(S) ). -%% tuples, atoms are not supported. -%% lists, integers, double, and so on. +%% tuples, atoms are not supported. lists, integers, double, and so on. %% see http://msgpack.sourceforge.jp/spec for %% supported formats. APIs are almost compatible %% for C API (http://msgpack.sourceforge.jp/c:doc) %% except buffering functions (both copying and zero-copying). -export([ - pack_fixnum/1, - pack_nfixnum/1, - pack_uint8/1, - pack_uint16/1, - pack_uint32/1, - pack_uint64/1, - pack_short/1, - pack_int8/1, - pack_int/1, - pack_long/1, - pack_long_long/1, - pack_unsigned_short/1, - pack_unsigned_int/1, - pack_unsigned_long/1, - pack_unsigned_long_long/1, pack_nil/0, pack_bool/1, pack_float/1, @@ -59,55 +42,39 @@ pack_map/1, pack_object/1 ]). - -% packing functions - -pack_short(N) when is_integer(N)-> - pack_int16(N). -pack_int(N) when is_integer(N)-> - pack_int32(N). -pack_long(N) when is_integer(N)-> - pack_int32(N). -pack_long_long(N) when is_integer(N)-> - pack_int64(N). -pack_unsigned_short(N) when is_integer(N)-> - pack_uint16(N). -pack_unsigned_int(N) when is_integer(N)-> - pack_uint32(N). -pack_unsigned_long(N) when is_integer(N)-> - pack_uint32(N). -pack_unsigned_long_long(N) when is_integer(N)-> - pack_uint64(N). - % positive fixnum -pack_fixnum( N ) when is_integer( N ) and N >= 0 , N < 128 -> - << 2#0:1, N:7 >>. -% negative fixnum -pack_nfixnum( N ) when is_integer( N ) and N >= -32 , N < 0 -> - << 2#111:3, N:5 >>. +pack_uint_(N) when is_integer( N ) , N < 128 -> + << 2#0:1, N:7 >>; % uint 8 -pack_uint8( N ) when is_integer( N )-> - << 16#CC:8, N:8 >>. +pack_uint_( N ) when is_integer( N ) andalso N < 256 -> + << 16#CC:8, N:8 >>; + % uint 16 -pack_uint16( N ) when is_integer( N )-> - << 16#CD:8, N:16/big-unsigned-integer-unit:1 >>. +pack_uint_( N ) when is_integer( N ) andalso N < 65536 -> + << 16#CD:8, N:16/big-unsigned-integer-unit:1 >>; + % uint 32 -pack_uint32( N ) when is_integer( N )-> - << 16#CE:8, N:32/big-unsigned-integer-unit:1 >>. +pack_uint_( N ) when is_integer( N ) andalso N < 16#FFFFFFFF-> + << 16#CE:8, N:32/big-unsigned-integer-unit:1 >>; + % uint 64 -pack_uint64( N ) when is_integer( N )-> +pack_uint_( N ) when is_integer( N )-> << 16#CF:8, N:64/big-unsigned-integer-unit:1 >>. + +% negative fixnum +pack_int_( N ) when is_integer( N ) , N >= -32-> + << 2#111:3, N:5 >>; % int 8 -pack_int8( N ) when is_integer( N )-> - << 16#D0:8, N:8 >>. +pack_int_( N ) when is_integer( N ) , N >= -256 -> + << 16#D0:8, N:8 >>; % int 16 -pack_int16( N ) when is_integer( N )-> - << 16#D1:8, N:16/big-signed-integer-unit:1 >>. +pack_int_( N ) when is_integer( N ), N >= -65536 -> + << 16#D1:8, N:16/big-signed-integer-unit:1 >>; % int 32 -pack_int32( N ) when is_integer( N )-> - << 16#D2:8, N:32/big-signed-integer-unit:1 >>. +pack_int_( N ) when is_integer( N ), N >= -16#FFFFFFFF -> + << 16#D2:8, N:32/big-signed-integer-unit:1 >>; % int 64 -pack_int64( N ) when is_integer( N )-> +pack_int_( N ) when is_integer( N )-> << 16#D3:8, N:64/big-signed-integer-unit:1 >>. % nil @@ -183,8 +150,10 @@ unpack_map_(Bin, Len) when is_binary(Bin) and is_integer(Len) -> { Value, Rest2 } = unpack(Rest), [{Key,Value}|unpack_map_(Rest2,Len-1)]. -pack_object(O) when is_integer(O)-> - pack_long_long(O); +pack_object(O) when is_integer(O) andalso O < 0 -> + pack_int_(O); +pack_object(O) when is_integer(O) -> + pack_uint_(O); pack_object(O) when is_float(O)-> pack_double(O); pack_object(nil) -> @@ -210,7 +179,7 @@ pack(Obj)-> % TODO: error case for imcomplete format when short for any type formats. -spec unpack( binary() )-> {term(), binary()}. unpack(Bin) when bit_size(Bin) >= 8 -> - << Flag:8, Payload/binary >> = Bin, + << Flag:8/unsigned-integer, Payload/binary >> = Bin, case Flag of 16#C0 -> {nil, Payload}; @@ -218,16 +187,18 @@ unpack(Bin) when bit_size(Bin) >= 8 -> {false, Payload}; 16#C3 -> {true, Payload}; + 16#CA -> % 32bit float << Return:32/float-unit:1, Rest/binary >> = Payload, {Return, Rest}; 16#CB -> % 64bit float << Return:64/float-unit:1, Rest/binary >> = Payload, {Return, Rest}; - 16#CC -> + + 16#CC -> % uint 8 << Int:8/unsigned-integer, Rest/binary >> = Payload, {Int, Rest}; - 16#CD -> + 16#CD -> % uint 16 << Int:16/big-unsigned-integer-unit:1, Rest/binary >> = Payload, {Int, Rest}; 16#CE -> @@ -236,16 +207,17 @@ unpack(Bin) when bit_size(Bin) >= 8 -> 16#CF -> << Int:64/big-unsigned-integer-unit:1, Rest/binary >> = Payload, {Int, Rest}; - 16#D0 -> + + 16#D0 -> % int 8 << Int:8/big-signed-integer-unit:1, Rest/binary >> = Payload, {Int, Rest}; - 16#D1 -> + 16#D1 -> % int 16 << Int:16/big-signed-integer-unit:1, Rest/binary >> = Payload, {Int, Rest}; - 16#D2 -> + 16#D2 -> % int 32 << Int:32/big-signed-integer-unit:1, Rest/binary >> = Payload, {Int, Rest}; - 16#D3 -> + 16#D3 -> % int 64 << Int:64/big-signed-integer-unit:1, Rest/binary >> = Payload, {Int, Rest}; 16#DA -> % raw 16 @@ -297,6 +269,14 @@ unpack(Bin) when bit_size(Bin) >= 8 -> {dict:from_list(Return), Remain} end; + % positive fixnum + Code when Code >= 2#00000000, Code < 2#10000000-> + {Code, Payload}; + + % negative fixnum + Code when Code >= 2#11100000 -> + {(Code - 16#100), Payload}; + Code when Code >= 2#10100000 , Code < 2#11000000 -> % 101XXXXX for FixRaw Len = Code rem 2#10100000, @@ -327,7 +307,8 @@ unpack(Bin) when bit_size(Bin) >= 8 -> {dict:from_list(Return), Remain} end; - _ -> + _Other -> + erlang:display(_Other), {error, no_code_matches} end. @@ -339,8 +320,17 @@ unpack_all(Data)-> [Term|unpack_all(Binary)] end. +-ifdef(EUNIT). + test()-> - Tests = [0, 1, 2, 123, 123.123, [23, 234, 0.23], "hogehoge", <<"hoasfdafdas][">>], + Tests = [0, 1, 2, 123, 512, 1230, 678908, 16#FFFFFFFFFF, + -1, -23, -512, -1230, -567898, -16#FFFFFFFFFF, + 123.123, -234.4355, 1.0e-34, 1.0e64, + [23, 234, 0.23], + "hogehoge", "243546rf7g68h798j", + <<"hoasfdafdas][">>, + [0,42,"sum", [1,2]], [1,42, nil, [3]] + ], Passed = test_(Tests), Passed = length(Tests). %% Port = open_port({spawn, "./a.out"}, [stream]), @@ -355,23 +345,9 @@ test()-> test_([]) -> 0; test_([S|Rest])-> -% io:format("testing: ~p~n", [S]), - {S, <<>>} = msgpack:unpack( msgpack:pack(S) ), + Pack = msgpack:pack(S), +% io:format("testing: ~p => ~p~n", [S, Pack]), + {S, <<>>} = msgpack:unpack( Pack ), test_(Rest) + 1. -test_([], _)-> 0; -test_([S|Rest], Port) -> - Bin = msgpack:pack(S), - io:format("sending: ~p - ", [S]), - Port ! {self(), {command, Bin}}, - receive - {Port, {data, Data}}-> - io:format("~p~n", [Data]), - test_(Rest, Port) + 1; - Other-> - io:format("fail: ~p~n", [Other]) - after 1024-> - test_(Rest, Port) - end. - - +-endif.