mirror of
https://github.com/valitydev/msgpack-erlang.git
synced 2024-11-06 00:35:24 +00:00
commit
06d8d98c78
34
Makefile
34
Makefile
@ -18,10 +18,10 @@ deps:
|
||||
compile:
|
||||
@$(REBAR) compile
|
||||
|
||||
xref:
|
||||
xref: compile
|
||||
@$(REBAR) xref
|
||||
|
||||
eunit: compile
|
||||
eunit: xref
|
||||
@$(REBAR) skip_deps=true eunit
|
||||
|
||||
test: eunit
|
||||
@ -33,13 +33,37 @@ doc:
|
||||
@$(REBAR) doc
|
||||
|
||||
bench: compile
|
||||
@$(REBAR) euni skip_deps=true suites=bench_tests
|
||||
@$(REBAR) eunit skip_deps=true suites=bench_tests
|
||||
|
||||
APPS = kernel stdlib sasl erts ssl tools os_mon runtime_tools crypto inets \
|
||||
xmerl webtool snmp public_key mnesia eunit syntax_tools compiler
|
||||
COMBO_PLT = $(HOME)/.msgpack_dialyzer_plt
|
||||
|
||||
check_plt: xref
|
||||
dialyzer --check_plt --plt $(COMBO_PLT) --apps $(APPS) \
|
||||
deps/*/ebin
|
||||
|
||||
build_plt: xref
|
||||
dialyzer --build_plt --output_plt $(COMBO_PLT) --apps $(APPS) \
|
||||
deps/*/ebin
|
||||
|
||||
dialyzer: xref
|
||||
@echo
|
||||
@echo Use "'make check_plt'" to check PLT prior to using this target.
|
||||
@echo Use "'make build_plt'" to build PLT prior to using this target.
|
||||
@echo
|
||||
@sleep 1
|
||||
dialyzer -Wno_return --plt $(COMBO_PLT) deps/*/ebin | \
|
||||
fgrep -v -f ./dialyzer.ignore-warnings
|
||||
|
||||
|
||||
|
||||
check: compile xref
|
||||
# @echo "you need $(REBAR) build-plt before make check"
|
||||
# @$(REBAR) build-plt
|
||||
@$(REBAR) check-plt
|
||||
@$(REBAR) dialyze
|
||||
dialyzer --check
|
||||
# @$(REBAR) check-plt
|
||||
# @$(REBAR) dialyze
|
||||
|
||||
crosslang:
|
||||
@echo "do ERL_LIBS=../ before you make crosslang or fail"
|
||||
|
27
include/msgpack.hrl
Normal file
27
include/msgpack.hrl
Normal file
@ -0,0 +1,27 @@
|
||||
%%
|
||||
%% MessagePack for Erlang
|
||||
%%
|
||||
%% Copyright (C) 2009-2013 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.
|
||||
%%
|
||||
|
||||
-type option() :: [jsx | jiffy | nif].
|
||||
|
||||
-record(options_v1, {
|
||||
interface = jiffy :: jiffy | jsx,
|
||||
map_unpack_fun = fun msgpack_unpacker:unpack_map_jiffy/4 :: fun(),
|
||||
impl = erlang :: erlang | nif
|
||||
}).
|
||||
-define(OPTION, #options_v1).
|
||||
-type msgpack_option() :: #options_v1{}.
|
@ -1,6 +1,6 @@
|
||||
{application, msgpack,
|
||||
[{description, "MessagePack serializer/deserializer"},
|
||||
{vsn, "0.1.2"},
|
||||
{vsn, "0.1.3"},
|
||||
{modules,
|
||||
[msgpack]
|
||||
},
|
||||
|
@ -50,68 +50,30 @@
|
||||
-export_type([object/0, msgpack_map/0]).
|
||||
-type object() :: msgpack_term().
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% external APIs
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
-include("msgpack.hrl").
|
||||
|
||||
%% @doc Encode an erlang term into an msgpack binary.
|
||||
%% Returns {error, {badarg, term()}} if the input is illegal.
|
||||
|
||||
-spec pack(Term::msgpack_term()) -> binary() | {error, {badarg, term()}}.
|
||||
-spec pack(msgpack_term()) -> binary() | {error, {badarg, term()}}.
|
||||
pack(Term) ->
|
||||
pack(Term, [jiffy]).
|
||||
|
||||
pack(Term, Opt)->
|
||||
try
|
||||
pack_(Term, Opt)
|
||||
msgpack_packer:pack(Term, ?OPTION{})
|
||||
catch
|
||||
throw:Exception ->
|
||||
{error, Exception}
|
||||
throw:Exception -> {error, Exception}
|
||||
end.
|
||||
|
||||
pack_(Term, [jiffy])->
|
||||
msgpack_jiffy:pack(Term);
|
||||
|
||||
pack_(Term, [jsx])->
|
||||
msgpack_jsx:pack(Term);
|
||||
|
||||
pack_(Term, [nif])->
|
||||
msgpack_nif:pack(Term).
|
||||
|
||||
%% @doc Decode an msgpack binary into an erlang term.
|
||||
%% It only decodes the first msgpack packet contained in the binary; the rest is returned as is.
|
||||
%% Returns {error, {badarg, term()}} if the input is corrupted.
|
||||
%% Returns {error, incomplete} if the input is not a full msgpack packet (caller should gather more data and try again).
|
||||
|
||||
unpack_stream(D) ->
|
||||
unpack_stream(D, [jiffy]).
|
||||
|
||||
unpack(D) ->
|
||||
unpack(D, [jiffy]).
|
||||
|
||||
-spec unpack_stream(Bin::binary()) -> {msgpack_term(), binary()} | {error, incomplete} | {error, {badarg, term()}}.
|
||||
|
||||
unpack_stream(Bin, Opt) ->
|
||||
pack(Term, [nif])->
|
||||
msgpack_nif:pack(Term);
|
||||
pack(Term, [Interface]) ->
|
||||
try
|
||||
unpack_stream_(Bin, Opt)
|
||||
msgpack_packer:pack(Term, ?OPTION{interface=Interface,
|
||||
map_unpack_fun=msgpack_unpacker:map_unpacker(Interface)})
|
||||
catch
|
||||
throw:Exception ->
|
||||
{error, Exception}
|
||||
throw:Exception -> {error, Exception}
|
||||
end.
|
||||
|
||||
unpack_stream_(Bin, [jiffy]) when is_binary(Bin) ->
|
||||
msgpack_jiffy:unpack(Bin);
|
||||
|
||||
|
||||
unpack_stream_(Bin, [jsx]) when is_binary(Bin) ->
|
||||
msgpack_jsx:unpack(Bin);
|
||||
|
||||
unpack_stream_(Bin, [nif]) when is_binary(Bin) ->
|
||||
msgpack_nif:unpack(Bin);
|
||||
|
||||
unpack_stream_(Other, _Opts) ->
|
||||
{error, {badarg, Other}}.
|
||||
|
||||
%%% @doc Decode an msgpack binary into an erlang terms.
|
||||
%%% It only decodes ONLY ONE msgpack packets contained in the binary. No packets should not remain.
|
||||
%%% Returns {error, {badarg, term()}} if the input is corrupted.
|
||||
@ -120,15 +82,48 @@ unpack_stream_(Other, _Opts) ->
|
||||
| {error, not_just_binary} % a term deserilized, but binary remains
|
||||
| {error, incomplete} % too few binary to deserialize complete binary
|
||||
| {error, {badarg, term()}}.
|
||||
unpack(Data, Opts) when is_binary(Data) ->
|
||||
case unpack_stream(Data, Opts) of
|
||||
unpack(Bin) when is_binary(Bin) ->
|
||||
case unpack_stream(Bin) of
|
||||
{error, _} = E -> E;
|
||||
{Term, <<>>} -> {ok, Term};
|
||||
{_, Binary} when is_binary(Binary) andalso byte_size(Binary) > 0 -> {error, not_just_binary}
|
||||
end;
|
||||
unpack(Other) ->
|
||||
{error, {badarg, Other}}.
|
||||
|
||||
unpack(Badarg, _Opts) ->
|
||||
{error, {badarg, Badarg}}.
|
||||
unpack(Bin, Opts) when is_binary(Bin) ->
|
||||
case unpack_stream(Bin, Opts) of
|
||||
{error, _} = E -> E;
|
||||
{Term, <<>>} -> {ok, Term};
|
||||
{_, Binary} when is_binary(Binary) andalso byte_size(Binary) > 0 -> {error, not_just_binary}
|
||||
end;
|
||||
unpack(Other, _) ->
|
||||
{error, {badarg, Other}}.
|
||||
|
||||
|
||||
-spec unpack_stream(binary()) -> {msgpack_term(), binary()}
|
||||
| {error, incomplete}
|
||||
| {error, {badarg, term()}}.
|
||||
unpack_stream(Bin)->
|
||||
try
|
||||
msgpack_unpacker:unpack_stream(Bin, ?OPTION{})
|
||||
catch
|
||||
throw:Exception -> {error, Exception}
|
||||
end.
|
||||
|
||||
-spec unpack_stream(binary(), list())-> {msgpack_term(), binary()}
|
||||
| {error, incomplete}
|
||||
| {error, {badarg, term()}}.
|
||||
unpack_stream(Bin, [nif]) ->
|
||||
msgpack_nif:unpack_stream(Bin);
|
||||
unpack_stream(Bin, [Interface]) ->
|
||||
try
|
||||
msgpack_unpacker:unpack_stream(Bin,
|
||||
?OPTION{interface=Interface,
|
||||
map_unpack_fun=msgpack_unpacker:map_unpacker(Interface)})
|
||||
catch
|
||||
throw:Exception -> {error, Exception}
|
||||
end.
|
||||
|
||||
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
||||
%% unit tests
|
||||
|
@ -1,59 +0,0 @@
|
||||
-module(msgpack_gen).
|
||||
|
||||
-export([pack_uint/1, pack_int/1, pack_double/1, pack_raw/1]).
|
||||
|
||||
-spec pack_uint(non_neg_integer()) -> binary().
|
||||
%% positive fixnum
|
||||
pack_uint(N) when N < 128 ->
|
||||
<< 2#0:1, N:7 >>;
|
||||
%% uint 8
|
||||
pack_uint(N) when (N band 16#FF) ->
|
||||
<< 16#CC:8, N:8 >>;
|
||||
%% uint 16
|
||||
pack_uint(N) when (N band 16#FFFF) =:= N ->
|
||||
<< 16#CD:8, N:16/big-unsigned-integer-unit:1 >>;
|
||||
%% uint 32
|
||||
pack_uint(N) when (N band 16#FFFFFFFF) =:= N->
|
||||
<< 16#CE:8, N:32/big-unsigned-integer-unit:1 >>;
|
||||
%% uint 64
|
||||
pack_uint(N) ->
|
||||
<< 16#CF:8, N:64/big-unsigned-integer-unit:1 >>.
|
||||
|
||||
-spec pack_int(integer()) -> binary().
|
||||
%% negative fixnum
|
||||
pack_int(N) when N >= -32->
|
||||
<< 2#111:3, N:5 >>;
|
||||
%% int 8
|
||||
pack_int(N) when N > -128 ->
|
||||
<< 16#D0:8, N:8/big-signed-integer-unit:1 >>;
|
||||
%% int 16
|
||||
pack_int(N) when N > -32768 ->
|
||||
<< 16#D1:8, N:16/big-signed-integer-unit:1 >>;
|
||||
%% int 32
|
||||
pack_int(N) when (N band 16#FFFFFFFF) =:= N ->
|
||||
<< 16#D2:8, N:32/big-signed-integer-unit:1 >>;
|
||||
%% int 64
|
||||
pack_int(N) ->
|
||||
<< 16#D3:8, N:64/big-signed-integer-unit:1 >>.
|
||||
|
||||
-spec pack_double(float()) -> binary().
|
||||
%% 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) ->
|
||||
<< 16#CB:8, F:64/big-float-unit:1 >>.
|
||||
|
||||
|
||||
-spec pack_raw(binary()) -> binary().
|
||||
%% raw bytes
|
||||
pack_raw(Bin) ->
|
||||
case byte_size(Bin) of
|
||||
Len when Len < 32->
|
||||
<< 2#101:3, Len:5, Bin/binary >>;
|
||||
Len when Len < 16#10000 -> % 65536
|
||||
<< 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.
|
@ -1,259 +0,0 @@
|
||||
-module(msgpack_jiffy).
|
||||
|
||||
-export([unpack/1, pack/1]).
|
||||
|
||||
%% pack them all
|
||||
-spec pack(msgpack:object()) -> binary() | no_return().
|
||||
pack(I) when is_integer(I), I < 0 ->
|
||||
msgpack_gen:pack_int(I);
|
||||
pack(I) when is_integer(I) ->
|
||||
msgpack_gen:pack_uint(I);
|
||||
pack(F) when is_float(F) ->
|
||||
msgpack_gen:pack_double(F);
|
||||
pack(nil) ->
|
||||
<< 16#C0:8 >>;
|
||||
pack(true) ->
|
||||
<< 16#C3:8 >>;
|
||||
pack(false) ->
|
||||
<< 16#C2:8 >>;
|
||||
pack(Bin) when is_binary(Bin) ->
|
||||
msgpack_gen:pack_raw(Bin);
|
||||
pack({Map}) ->
|
||||
pack_map(Map);
|
||||
pack(List) when is_list(List) ->
|
||||
pack_array(List);
|
||||
pack(Other) ->
|
||||
throw({badarg, Other}).
|
||||
|
||||
%% unpack them all
|
||||
-spec unpack(Bin::binary()) -> {msgpack:object(), binary()} | no_return().
|
||||
%% ATOMS
|
||||
unpack(<<16#C0, Rest/binary>>) ->
|
||||
{nil, Rest};
|
||||
unpack(<<16#C2, Rest/binary>>) ->
|
||||
{false, Rest};
|
||||
unpack(<<16#C3, Rest/binary>>) ->
|
||||
{true, Rest};
|
||||
|
||||
%% Floats
|
||||
unpack(<<16#CA, V:32/float-unit:1, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
unpack(<<16#CB, V:64/float-unit:1, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
|
||||
%% Unsigned integers
|
||||
unpack(<<16#CC, V:8/unsigned-integer, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
unpack(<<16#CD, V:16/big-unsigned-integer-unit:1, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
unpack(<<16#CE, V:32/big-unsigned-integer-unit:1, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
unpack(<<16#CF, V:64/big-unsigned-integer-unit:1, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
|
||||
%% Signed integers
|
||||
unpack(<<16#D0, V:8/signed-integer, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
unpack(<<16#D1, V:16/big-signed-integer-unit:1, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
unpack(<<16#D2, V:32/big-signed-integer-unit:1, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
unpack(<<16#D3, V:64/big-signed-integer-unit:1, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
|
||||
%% Raw bytes
|
||||
unpack(<<16#DA, L:16/unsigned-integer-unit:1, V:L/binary, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
unpack(<<16#DB, L:32/unsigned-integer-unit:1, V:L/binary, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
|
||||
%% Arrays
|
||||
unpack(<<16#DC, L:16/big-unsigned-integer-unit:1, Rest/binary>>) ->
|
||||
unpack_array(Rest, L, []);
|
||||
unpack(<<16#DD, L:32/big-unsigned-integer-unit:1, Rest/binary>>) ->
|
||||
unpack_array(Rest, L, []);
|
||||
%% Maps
|
||||
unpack(<<16#DE, L:16/big-unsigned-integer-unit:1, Rest/binary>>) ->
|
||||
unpack_map(Rest, L, []);
|
||||
unpack(<<16#DF, L:32/big-unsigned-integer-unit:1, Rest/binary>>) ->
|
||||
unpack_map(Rest, L, []);
|
||||
|
||||
%% Tag-encoded lengths (kept last, for speed)
|
||||
unpack(<<0:1, V:7, Rest/binary>>) ->
|
||||
{V, Rest}; % positive int
|
||||
unpack(<<2#111:3, V:5, Rest/binary>>) ->
|
||||
{V - 2#100000, Rest}; % negative int
|
||||
unpack(<<2#101:3, L:5, V:L/binary, Rest/binary>>) ->
|
||||
{V, Rest}; % raw bytes
|
||||
unpack(<<2#1001:4, L:4, Rest/binary>>) ->
|
||||
unpack_array(Rest, L, []); % array
|
||||
unpack(<<2#1000:4, L:4, Rest/binary>>) ->
|
||||
unpack_map(Rest, L, []); % map
|
||||
|
||||
%% Invalid data
|
||||
unpack(<<F, R/binary>>) when F==16#C1;
|
||||
F==16#C4; F==16#C5; F==16#C6; F==16#C7; F==16#C8; F==16#C9;
|
||||
F==16#D4; F==16#D5; F==16#D6; F==16#D7; F==16#D8; F==16#D9 ->
|
||||
throw({badarg, <<F, R/binary>>});
|
||||
%% Incomplete data (we've covered every complete/invalid case; anything left is incomplete)
|
||||
unpack(_) ->
|
||||
throw(incomplete).
|
||||
|
||||
|
||||
-spec pack_array([msgpack:object()]) -> binary() | no_return().
|
||||
|
||||
%% list
|
||||
pack_array([]) ->
|
||||
<< 2#1001:4, 0:4/integer-unit:1 >>;
|
||||
|
||||
pack_array([A]) ->
|
||||
<< 2#1001:4, 1:4/integer-unit:1, (pack(A))/binary >>;
|
||||
|
||||
pack_array([A, B]) ->
|
||||
<< 2#1001:4, 2:4/integer-unit:1, (pack(A))/binary, (pack(B))/binary >>;
|
||||
|
||||
pack_array([A, B, C]) ->
|
||||
<< 2#1001:4, 3:4/integer-unit:1, (pack(A))/binary, (pack(B))/binary, (pack(C))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D]) ->
|
||||
<< 2#1001:4, 4:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E]) ->
|
||||
<< 2#1001:4, 5:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary,
|
||||
(pack(E))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F]) ->
|
||||
<< 2#1001:4, 6:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary,
|
||||
(pack(E))/binary, (pack(F))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G]) ->
|
||||
<< 2#1001:4, 7:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary,
|
||||
(pack(E))/binary, (pack(F))/binary, (pack(G))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H]) ->
|
||||
<< 2#1001:4, 8:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary,
|
||||
(pack(E))/binary, (pack(F))/binary, (pack(G))/binary, (pack(H))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H, I]) ->
|
||||
<< 2#1001:4, 9:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary,
|
||||
(pack(E))/binary, (pack(F))/binary, (pack(G))/binary, (pack(H))/binary,
|
||||
(pack(I))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H, I, J]) ->
|
||||
<< 2#1001:4, 10:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary,
|
||||
(pack(E))/binary, (pack(F))/binary, (pack(G))/binary, (pack(H))/binary,
|
||||
(pack(I))/binary, (pack(J))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H, I, J, K]) ->
|
||||
<< 2#1001:4, 11:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary,
|
||||
(pack(E))/binary, (pack(F))/binary, (pack(G))/binary, (pack(H))/binary,
|
||||
(pack(I))/binary, (pack(J))/binary, (pack(K))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H, I, J, K, L]) ->
|
||||
<< 2#1001:4, 12:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary,
|
||||
(pack(E))/binary, (pack(F))/binary, (pack(G))/binary, (pack(H))/binary,
|
||||
(pack(I))/binary, (pack(J))/binary, (pack(K))/binary, (pack(L))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H, I, J, K, L, M]) ->
|
||||
<< 2#1001:4, 13:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary,
|
||||
(pack(E))/binary, (pack(F))/binary, (pack(G))/binary, (pack(H))/binary,
|
||||
(pack(I))/binary, (pack(J))/binary, (pack(K))/binary, (pack(L))/binary,
|
||||
(pack(M))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H, I, J, K, L, M, N]) ->
|
||||
<< 2#1001:4, 14:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary,
|
||||
(pack(E))/binary, (pack(F))/binary, (pack(G))/binary, (pack(H))/binary,
|
||||
(pack(I))/binary, (pack(J))/binary, (pack(K))/binary, (pack(L))/binary,
|
||||
(pack(M))/binary, (pack(N))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H, I, J, K, L, M, N, O]) ->
|
||||
<< 2#1001:4, 15:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary,
|
||||
(pack(E))/binary, (pack(F))/binary, (pack(G))/binary, (pack(H))/binary,
|
||||
(pack(I))/binary, (pack(J))/binary, (pack(K))/binary, (pack(L))/binary,
|
||||
(pack(M))/binary, (pack(N))/binary, (pack(O))/binary >>;
|
||||
|
||||
pack_array(L) ->
|
||||
case length(L) of
|
||||
Len when Len < 16#10000 -> % 65536
|
||||
<<16#DC:8, Len:16/big-unsigned-integer-unit:1, (<< <<(pack(E))/binary>> || E <- L >>)/binary>>;
|
||||
Len ->
|
||||
<<16#DD:8, Len:32/big-unsigned-integer-unit:1, (<< <<(pack(E))/binary>> || E <- L >>)/binary>>
|
||||
end.
|
||||
|
||||
-spec unpack_array(binary(), non_neg_integer(), [msgpack:object()]) -> {[msgpack:object()], binary()} | no_return().
|
||||
unpack_array(Bin, 0, Acc) ->
|
||||
{lists:reverse(Acc), Bin};
|
||||
|
||||
unpack_array(Bin, Len, Acc) ->
|
||||
{Term, Rest} = unpack(Bin),
|
||||
unpack_array(Rest, Len-1, [Term|Acc]).
|
||||
|
||||
-spec pack_map(M::msgpack:msgpack_map()) -> binary() | no_return().
|
||||
pack_map([{Ka, Va}])->
|
||||
<< 2#1000:4, 1:4/integer-unit:1,
|
||||
(pack(Ka))/binary, (pack(Va))/binary >>;
|
||||
|
||||
pack_map([{Ka, Va}, {Kb, Vb}])->
|
||||
<< 2#1000:4, 2:4/integer-unit:1,
|
||||
(pack(Ka))/binary, (pack(Va))/binary,
|
||||
(pack(Kb))/binary, (pack(Vb))/binary >>;
|
||||
|
||||
pack_map([{Ka, Va}, {Kb, Vb}, {Kc, Vc}])->
|
||||
<< 2#1000:4, 3:4/integer-unit:1,
|
||||
(pack(Ka))/binary, (pack(Va))/binary,
|
||||
(pack(Kb))/binary, (pack(Vb))/binary,
|
||||
(pack(Kc))/binary, (pack(Vc))/binary >>;
|
||||
|
||||
pack_map([{Ka, Va}, {Kb, Vb}, {Kc, Vc}, {Kd, Vd}])->
|
||||
<< 2#1000:4, 4:4/integer-unit:1,
|
||||
(pack(Ka))/binary, (pack(Va))/binary,
|
||||
(pack(Kb))/binary, (pack(Vb))/binary,
|
||||
(pack(Kc))/binary, (pack(Vc))/binary,
|
||||
(pack(Kd))/binary, (pack(Vd))/binary >>;
|
||||
|
||||
pack_map(M)->
|
||||
case length(M) of
|
||||
Len when Len < 16 ->
|
||||
<<2#1000:4, Len:4/integer-unit:1,
|
||||
(<< <<(pack(K))/binary, (pack(V))/binary>> || {K, V} <- M >>)/binary>>;
|
||||
Len when Len < 16#10000 -> % 65536
|
||||
<<16#DE:8, Len:16/big-unsigned-integer-unit:1,
|
||||
(<< <<(pack(K))/binary, (pack(V))/binary>> || {K, V} <- M >>)/binary>>;
|
||||
Len ->
|
||||
<<16#DF:8, Len:32/big-unsigned-integer-unit:1,
|
||||
(<< <<(pack(K))/binary, (pack(V))/binary>> || {K, V} <- M >>)/binary>>
|
||||
end.
|
||||
|
||||
%% Users SHOULD NOT send too long list: this uses lists:reverse/1
|
||||
-spec unpack_map(binary(), non_neg_integer(), msgpack:msgpack_map()) ->
|
||||
{msgpack:msgpack_map(), binary()} | no_return().
|
||||
unpack_map(Bin, 0, Acc) ->
|
||||
{{lists:reverse(Acc)}, Bin};
|
||||
unpack_map(Bin, Len, Acc) ->
|
||||
{Key, Rest} = unpack(Bin),
|
||||
{Value, Rest2} = unpack(Rest),
|
||||
unpack_map(Rest2, Len-1, [{Key,Value}|Acc]).
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
map_test()->
|
||||
Ints = lists:seq(0, 65),
|
||||
Map = {[ {X, X*2} || X <- Ints ] ++ [{<<"hage">>, 324}, {43542, [nil, true, false]}]},
|
||||
{ok, Map2} = msgpack:unpack(msgpack:pack(Map)),
|
||||
?assertEqual(Map, Map2),
|
||||
{ok, Empty} = msgpack:unpack(msgpack:pack({[]})),
|
||||
?assertEqual({[]}, Empty),
|
||||
ok.
|
||||
-endif.
|
@ -1,265 +0,0 @@
|
||||
-module(msgpack_jsx).
|
||||
|
||||
-export([unpack/1, pack/1]).
|
||||
|
||||
%% pack them all
|
||||
-spec pack(msgpack:object()) -> binary() | no_return().
|
||||
pack(I) when is_integer(I), I < 0 ->
|
||||
msgpack_gen:pack_int(I);
|
||||
pack(I) when is_integer(I) ->
|
||||
msgpack_gen:pack_uint(I);
|
||||
pack(F) when is_float(F) ->
|
||||
msgpack_gen:pack_double(F);
|
||||
pack(nil) ->
|
||||
<< 16#C0:8 >>;
|
||||
pack(true) ->
|
||||
<< 16#C3:8 >>;
|
||||
pack(false) ->
|
||||
<< 16#C2:8 >>;
|
||||
pack(Bin) when is_binary(Bin) ->
|
||||
msgpack_gen:pack_raw(Bin);
|
||||
pack([{}] = Map) ->
|
||||
pack_map(Map);
|
||||
pack([{_,_} | _] = Map) ->
|
||||
pack_map(Map);
|
||||
pack(List) when is_list(List) ->
|
||||
pack_array(List);
|
||||
pack(Other) ->
|
||||
throw({badarg, Other}).
|
||||
|
||||
%% unpack them all
|
||||
-spec unpack(Bin::binary()) -> {msgpack:object(), binary()} | no_return().
|
||||
%% ATOMS
|
||||
unpack(<<16#C0, Rest/binary>>) ->
|
||||
{nil, Rest};
|
||||
unpack(<<16#C2, Rest/binary>>) ->
|
||||
{false, Rest};
|
||||
unpack(<<16#C3, Rest/binary>>) ->
|
||||
{true, Rest};
|
||||
|
||||
%% Floats
|
||||
unpack(<<16#CA, V:32/float-unit:1, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
unpack(<<16#CB, V:64/float-unit:1, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
|
||||
%% Unsigned integers
|
||||
unpack(<<16#CC, V:8/unsigned-integer, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
unpack(<<16#CD, V:16/big-unsigned-integer-unit:1, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
unpack(<<16#CE, V:32/big-unsigned-integer-unit:1, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
unpack(<<16#CF, V:64/big-unsigned-integer-unit:1, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
|
||||
%% Signed integers
|
||||
unpack(<<16#D0, V:8/signed-integer, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
unpack(<<16#D1, V:16/big-signed-integer-unit:1, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
unpack(<<16#D2, V:32/big-signed-integer-unit:1, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
unpack(<<16#D3, V:64/big-signed-integer-unit:1, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
|
||||
%% Raw bytes
|
||||
unpack(<<16#DA, L:16/unsigned-integer-unit:1, V:L/binary, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
unpack(<<16#DB, L:32/unsigned-integer-unit:1, V:L/binary, Rest/binary>>) ->
|
||||
{V, Rest};
|
||||
|
||||
%% Arrays
|
||||
unpack(<<16#DC, L:16/big-unsigned-integer-unit:1, Rest/binary>>) ->
|
||||
unpack_array(Rest, L, []);
|
||||
unpack(<<16#DD, L:32/big-unsigned-integer-unit:1, Rest/binary>>) ->
|
||||
unpack_array(Rest, L, []);
|
||||
%% Maps
|
||||
unpack(<<16#DE, L:16/big-unsigned-integer-unit:1, Rest/binary>>) ->
|
||||
unpack_map(Rest, L, []);
|
||||
unpack(<<16#DF, L:32/big-unsigned-integer-unit:1, Rest/binary>>) ->
|
||||
unpack_map(Rest, L, []);
|
||||
|
||||
%% Tag-encoded lengths (kept last, for speed)
|
||||
unpack(<<0:1, V:7, Rest/binary>>) ->
|
||||
{V, Rest}; % positive int
|
||||
unpack(<<2#111:3, V:5, Rest/binary>>) ->
|
||||
{V - 2#100000, Rest}; % negative int
|
||||
unpack(<<2#101:3, L:5, V:L/binary, Rest/binary>>) ->
|
||||
{V, Rest}; % raw bytes
|
||||
unpack(<<2#1001:4, L:4, Rest/binary>>) ->
|
||||
unpack_array(Rest, L, []); % array
|
||||
unpack(<<2#1000:4, L:4, Rest/binary>>) ->
|
||||
unpack_map(Rest, L, []); % map
|
||||
|
||||
% Invalid data
|
||||
unpack(<<F, R/binary>>) when F==16#C1;
|
||||
F==16#C4; F==16#C5; F==16#C6; F==16#C7; F==16#C8; F==16#C9;
|
||||
F==16#D4; F==16#D5; F==16#D6; F==16#D7; F==16#D8; F==16#D9 ->
|
||||
throw({badarg, <<F, R/binary>>});
|
||||
% Incomplete data (we've covered every complete/invalid case; anything left is incomplete)
|
||||
unpack(_) ->
|
||||
throw(incomplete).
|
||||
|
||||
|
||||
-spec pack_array([msgpack:object()]) -> binary() | no_return().
|
||||
|
||||
%% list
|
||||
pack_array([]) ->
|
||||
<< 2#1001:4, 0:4/integer-unit:1 >>;
|
||||
|
||||
pack_array([A]) ->
|
||||
<< 2#1001:4, 1:4/integer-unit:1, (pack(A))/binary >>;
|
||||
|
||||
pack_array([A, B]) ->
|
||||
<< 2#1001:4, 2:4/integer-unit:1, (pack(A))/binary, (pack(B))/binary >>;
|
||||
|
||||
pack_array([A, B, C]) ->
|
||||
<< 2#1001:4, 3:4/integer-unit:1, (pack(A))/binary, (pack(B))/binary, (pack(C))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D]) ->
|
||||
<< 2#1001:4, 4:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E]) ->
|
||||
<< 2#1001:4, 5:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary,
|
||||
(pack(E))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F]) ->
|
||||
<< 2#1001:4, 6:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary,
|
||||
(pack(E))/binary, (pack(F))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G]) ->
|
||||
<< 2#1001:4, 7:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary,
|
||||
(pack(E))/binary, (pack(F))/binary, (pack(G))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H]) ->
|
||||
<< 2#1001:4, 8:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary,
|
||||
(pack(E))/binary, (pack(F))/binary, (pack(G))/binary, (pack(H))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H, I]) ->
|
||||
<< 2#1001:4, 9:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary,
|
||||
(pack(E))/binary, (pack(F))/binary, (pack(G))/binary, (pack(H))/binary,
|
||||
(pack(I))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H, I, J]) ->
|
||||
<< 2#1001:4, 10:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary,
|
||||
(pack(E))/binary, (pack(F))/binary, (pack(G))/binary, (pack(H))/binary,
|
||||
(pack(I))/binary, (pack(J))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H, I, J, K]) ->
|
||||
<< 2#1001:4, 11:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary,
|
||||
(pack(E))/binary, (pack(F))/binary, (pack(G))/binary, (pack(H))/binary,
|
||||
(pack(I))/binary, (pack(J))/binary, (pack(K))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H, I, J, K, L]) ->
|
||||
<< 2#1001:4, 12:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary,
|
||||
(pack(E))/binary, (pack(F))/binary, (pack(G))/binary, (pack(H))/binary,
|
||||
(pack(I))/binary, (pack(J))/binary, (pack(K))/binary, (pack(L))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H, I, J, K, L, M]) ->
|
||||
<< 2#1001:4, 13:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary,
|
||||
(pack(E))/binary, (pack(F))/binary, (pack(G))/binary, (pack(H))/binary,
|
||||
(pack(I))/binary, (pack(J))/binary, (pack(K))/binary, (pack(L))/binary,
|
||||
(pack(M))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H, I, J, K, L, M, N]) ->
|
||||
<< 2#1001:4, 14:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary,
|
||||
(pack(E))/binary, (pack(F))/binary, (pack(G))/binary, (pack(H))/binary,
|
||||
(pack(I))/binary, (pack(J))/binary, (pack(K))/binary, (pack(L))/binary,
|
||||
(pack(M))/binary, (pack(N))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H, I, J, K, L, M, N, O]) ->
|
||||
<< 2#1001:4, 15:4/integer-unit:1,
|
||||
(pack(A))/binary, (pack(B))/binary, (pack(C))/binary, (pack(D))/binary,
|
||||
(pack(E))/binary, (pack(F))/binary, (pack(G))/binary, (pack(H))/binary,
|
||||
(pack(I))/binary, (pack(J))/binary, (pack(K))/binary, (pack(L))/binary,
|
||||
(pack(M))/binary, (pack(N))/binary, (pack(O))/binary >>;
|
||||
|
||||
pack_array(L) ->
|
||||
case length(L) of
|
||||
Len when Len < 16#10000 -> % 65536
|
||||
<<16#DC:8, Len:16/big-unsigned-integer-unit:1, (<< <<(pack(E))/binary>> || E <- L >>)/binary>>;
|
||||
Len ->
|
||||
<<16#DD:8, Len:32/big-unsigned-integer-unit:1, (<< <<(pack(E))/binary>> || E <- L >>)/binary>>
|
||||
end.
|
||||
|
||||
-spec unpack_array(binary(), non_neg_integer(), [msgpack:object()]) -> {[msgpack:object()], binary()} | no_return().
|
||||
unpack_array(Bin, 0, Acc) ->
|
||||
{lists:reverse(Acc), Bin};
|
||||
unpack_array(Bin, Len, Acc) ->
|
||||
{Term, Rest} = unpack(Bin),
|
||||
unpack_array(Rest, Len-1, [Term|Acc]).
|
||||
|
||||
-spec pack_map(M::msgpack:msgpack_map()) -> binary() | no_return().
|
||||
pack_map([{}])->
|
||||
<< 2#1000:4, 0:4/integer-unit:1, <<>>/binary >>;
|
||||
|
||||
pack_map([{Ka, Va}])->
|
||||
<< 2#1000:4, 1:4/integer-unit:1,
|
||||
(pack(Ka))/binary, (pack(Va))/binary >>;
|
||||
|
||||
pack_map([{Ka, Va}, {Kb, Vb}])->
|
||||
<< 2#1000:4, 2:4/integer-unit:1,
|
||||
(pack(Ka))/binary, (pack(Va))/binary,
|
||||
(pack(Kb))/binary, (pack(Vb))/binary >>;
|
||||
|
||||
pack_map([{Ka, Va}, {Kb, Vb}, {Kc, Vc}])->
|
||||
<< 2#1000:4, 3:4/integer-unit:1,
|
||||
(pack(Ka))/binary, (pack(Va))/binary,
|
||||
(pack(Kb))/binary, (pack(Vb))/binary,
|
||||
(pack(Kc))/binary, (pack(Vc))/binary >>;
|
||||
|
||||
pack_map([{Ka, Va}, {Kb, Vb}, {Kc, Vc}, {Kd, Vd}])->
|
||||
<< 2#1000:4, 4:4/integer-unit:1,
|
||||
(pack(Ka))/binary, (pack(Va))/binary,
|
||||
(pack(Kb))/binary, (pack(Vb))/binary,
|
||||
(pack(Kc))/binary, (pack(Vc))/binary,
|
||||
(pack(Kd))/binary, (pack(Vd))/binary >>;
|
||||
|
||||
pack_map(M)->
|
||||
case length(M) of
|
||||
Len when Len < 16 ->
|
||||
<<2#1000:4, Len:4/integer-unit:1,
|
||||
(<< <<(pack(K))/binary, (pack(V))/binary>> || {K, V} <- M >>)/binary>>;
|
||||
Len when Len < 16#10000 -> % 65536
|
||||
<<16#DE:8, Len:16/big-unsigned-integer-unit:1,
|
||||
(<< <<(pack(K))/binary, (pack(V))/binary>> || {K, V} <- M >>)/binary>>;
|
||||
Len ->
|
||||
<<16#DF:8, Len:32/big-unsigned-integer-unit:1,
|
||||
(<< <<(pack(K))/binary, (pack(V))/binary>> || {K, V} <- M >>)/binary>>
|
||||
end.
|
||||
|
||||
% Users SHOULD NOT send too long list: this uses lists:reverse/1
|
||||
-spec unpack_map(binary(), non_neg_integer(), msgpack:msgpack_map()) ->
|
||||
{msgpack:msgpack_map(), binary()} | no_return().
|
||||
unpack_map(Bin, 0, []) ->
|
||||
{[{}], Bin};
|
||||
unpack_map(Bin, 0, Acc) ->
|
||||
{lists:reverse(Acc), Bin};
|
||||
unpack_map(Bin, Len, Acc) ->
|
||||
{Key, Rest} = unpack(Bin),
|
||||
{Value, Rest2} = unpack(Rest),
|
||||
unpack_map(Rest2, Len-1, [{Key,Value}|Acc]).
|
||||
|
||||
-ifdef(TEST).
|
||||
-include_lib("eunit/include/eunit.hrl").
|
||||
map_test()->
|
||||
Ints = lists:seq(0, 65),
|
||||
Map = [ {X, X*2} || X <- Ints ] ++ [{<<"hage">>, 324}, {43542, [nil, true, false]}],
|
||||
{ok, Map2} = msgpack:unpack(msgpack:pack(Map, [jsx]), [jsx]),
|
||||
?assertEqual(Map, Map2),
|
||||
{ok, Empty} = msgpack:unpack(msgpack:pack([{}], [jsx]), [jsx]),
|
||||
?assertEqual([{}], Empty),
|
||||
ok.
|
||||
-endif.
|
237
src/msgpack_packer.erl
Normal file
237
src/msgpack_packer.erl
Normal file
@ -0,0 +1,237 @@
|
||||
%%
|
||||
%% MessagePack for Erlang
|
||||
%%
|
||||
%% Copyright (C) 2009-2013 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.
|
||||
%%
|
||||
-module(msgpack_packer).
|
||||
|
||||
-export([pack/2]).
|
||||
|
||||
-include("msgpack.hrl").
|
||||
|
||||
%% pack them all
|
||||
-spec pack(msgpack:object(), option()) -> binary().
|
||||
pack(I, _) when is_integer(I) andalso I < 0 ->
|
||||
pack_int(I);
|
||||
pack(I, _) when is_integer(I) ->
|
||||
pack_uint(I);
|
||||
pack(F, _) when is_float(F) ->
|
||||
pack_double(F);
|
||||
pack(nil, _) ->
|
||||
<< 16#C0:8 >>;
|
||||
pack(true, _) ->
|
||||
<< 16#C3:8 >>;
|
||||
pack(false, _) ->
|
||||
<< 16#C2:8 >>;
|
||||
pack(Bin, _) when is_binary(Bin) ->
|
||||
pack_raw(Bin);
|
||||
|
||||
%% jiffy interface
|
||||
pack({Map}, Opt = ?OPTION{interface=jiffy}) ->
|
||||
pack_map(Map, Opt);
|
||||
|
||||
%% jsx interface
|
||||
pack(Map, Opt = ?OPTION{interface=jsx}) when Map =:= [{}]->
|
||||
pack_map([], Opt);
|
||||
pack([{_,_}|_] = Map, Opt = ?OPTION{interface=jsx}) ->
|
||||
pack_map(Map, Opt);
|
||||
|
||||
pack(List, Opt) when is_list(List) ->
|
||||
pack_array(List, Opt);
|
||||
pack(Other, _) ->
|
||||
throw({badarg, Other}).
|
||||
|
||||
-spec pack_int(integer()) -> binary().
|
||||
%% negative fixnum
|
||||
pack_int(N) when N >= -32->
|
||||
<< 2#111:3, N:5 >>;
|
||||
%% int 8
|
||||
pack_int(N) when N > -128 ->
|
||||
<< 16#D0:8, N:8/big-signed-integer-unit:1 >>;
|
||||
%% int 16
|
||||
pack_int(N) when N > -32768 ->
|
||||
<< 16#D1:8, N:16/big-signed-integer-unit:1 >>;
|
||||
%% int 32
|
||||
pack_int(N) when (N band 16#FFFFFFFF) =:= N ->
|
||||
<< 16#D2:8, N:32/big-signed-integer-unit:1 >>;
|
||||
%% int 64
|
||||
pack_int(N) ->
|
||||
<< 16#D3:8, N:64/big-signed-integer-unit:1 >>.
|
||||
|
||||
-spec pack_uint(non_neg_integer()) -> binary().
|
||||
%% positive fixnum
|
||||
pack_uint(N) when N < 128 ->
|
||||
<< 2#0:1, N:7 >>;
|
||||
%% uint 8
|
||||
pack_uint(N) when (N band 16#FF) =:= N ->
|
||||
<< 16#CC:8, N:8 >>;
|
||||
%% uint 16
|
||||
pack_uint(N) when (N band 16#FFFF) =:= N ->
|
||||
<< 16#CD:8, N:16/big-unsigned-integer-unit:1 >>;
|
||||
%% uint 32
|
||||
pack_uint(N) when (N band 16#FFFFFFFF) =:= N->
|
||||
<< 16#CE:8, N:32/big-unsigned-integer-unit:1 >>;
|
||||
%% uint 64
|
||||
pack_uint(N) ->
|
||||
<< 16#CF:8, N:64/big-unsigned-integer-unit:1 >>.
|
||||
|
||||
|
||||
-spec pack_double(float()) -> binary().
|
||||
%% 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) ->
|
||||
<< 16#CB:8, F:64/big-float-unit:1 >>.
|
||||
|
||||
|
||||
-spec pack_raw(binary()) -> binary().
|
||||
%% raw bytes
|
||||
pack_raw(Bin) ->
|
||||
case byte_size(Bin) of
|
||||
Len when Len < 32->
|
||||
<< 2#101:3, Len:5, Bin/binary >>;
|
||||
Len when Len < 16#10000 -> % 65536
|
||||
<< 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.
|
||||
|
||||
-spec pack_array([msgpack:object()], list()) -> binary() | no_return().
|
||||
pack_array([], _) ->
|
||||
<< 2#1001:4, 0:4/integer-unit:1 >>;
|
||||
|
||||
pack_array([A], Opt) ->
|
||||
<< 2#1001:4, 1:4/integer-unit:1, (pack(A, Opt))/binary >>;
|
||||
|
||||
pack_array([A, B], Opt) ->
|
||||
<< 2#1001:4, 2:4/integer-unit:1, (pack(A, Opt))/binary, (pack(B, Opt))/binary >>;
|
||||
|
||||
pack_array([A, B, C], Opt) ->
|
||||
<< 2#1001:4, 3:4/integer-unit:1, (pack(A, Opt))/binary, (pack(B, Opt))/binary, (pack(C, Opt))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D], Opt) ->
|
||||
<< 2#1001:4, 4:4/integer-unit:1,
|
||||
(pack(A, Opt))/binary, (pack(B, Opt))/binary, (pack(C, Opt))/binary, (pack(D, Opt))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E], Opt) ->
|
||||
<< 2#1001:4, 5:4/integer-unit:1,
|
||||
(pack(A, Opt))/binary, (pack(B, Opt))/binary, (pack(C, Opt))/binary, (pack(D, Opt))/binary,
|
||||
(pack(E, Opt))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F], Opt) ->
|
||||
<< 2#1001:4, 6:4/integer-unit:1,
|
||||
(pack(A, Opt))/binary, (pack(B, Opt))/binary, (pack(C, Opt))/binary, (pack(D, Opt))/binary,
|
||||
(pack(E, Opt))/binary, (pack(F, Opt))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G], Opt) ->
|
||||
<< 2#1001:4, 7:4/integer-unit:1,
|
||||
(pack(A, Opt))/binary, (pack(B, Opt))/binary, (pack(C, Opt))/binary, (pack(D, Opt))/binary,
|
||||
(pack(E, Opt))/binary, (pack(F, Opt))/binary, (pack(G, Opt))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H], Opt) ->
|
||||
<< 2#1001:4, 8:4/integer-unit:1,
|
||||
(pack(A, Opt))/binary, (pack(B, Opt))/binary, (pack(C, Opt))/binary, (pack(D, Opt))/binary,
|
||||
(pack(E, Opt))/binary, (pack(F, Opt))/binary, (pack(G, Opt))/binary, (pack(H, Opt))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H, I], Opt) ->
|
||||
<< 2#1001:4, 9:4/integer-unit:1,
|
||||
(pack(A, Opt))/binary, (pack(B, Opt))/binary, (pack(C, Opt))/binary, (pack(D, Opt))/binary,
|
||||
(pack(E, Opt))/binary, (pack(F, Opt))/binary, (pack(G, Opt))/binary, (pack(H, Opt))/binary,
|
||||
(pack(I, Opt))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H, I, J], Opt) ->
|
||||
<< 2#1001:4, 10:4/integer-unit:1,
|
||||
(pack(A, Opt))/binary, (pack(B, Opt))/binary, (pack(C, Opt))/binary, (pack(D, Opt))/binary,
|
||||
(pack(E, Opt))/binary, (pack(F, Opt))/binary, (pack(G, Opt))/binary, (pack(H, Opt))/binary,
|
||||
(pack(I, Opt))/binary, (pack(J, Opt))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H, I, J, K], Opt) ->
|
||||
<< 2#1001:4, 11:4/integer-unit:1,
|
||||
(pack(A, Opt))/binary, (pack(B, Opt))/binary, (pack(C, Opt))/binary, (pack(D, Opt))/binary,
|
||||
(pack(E, Opt))/binary, (pack(F, Opt))/binary, (pack(G, Opt))/binary, (pack(H, Opt))/binary,
|
||||
(pack(I, Opt))/binary, (pack(J, Opt))/binary, (pack(K, Opt))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H, I, J, K, L], Opt) ->
|
||||
<< 2#1001:4, 12:4/integer-unit:1,
|
||||
(pack(A, Opt))/binary, (pack(B, Opt))/binary, (pack(C, Opt))/binary, (pack(D, Opt))/binary,
|
||||
(pack(E, Opt))/binary, (pack(F, Opt))/binary, (pack(G, Opt))/binary, (pack(H, Opt))/binary,
|
||||
(pack(I, Opt))/binary, (pack(J, Opt))/binary, (pack(K, Opt))/binary, (pack(L, Opt))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H, I, J, K, L, M], Opt) ->
|
||||
<< 2#1001:4, 13:4/integer-unit:1,
|
||||
(pack(A, Opt))/binary, (pack(B, Opt))/binary, (pack(C, Opt))/binary, (pack(D, Opt))/binary,
|
||||
(pack(E, Opt))/binary, (pack(F, Opt))/binary, (pack(G, Opt))/binary, (pack(H, Opt))/binary,
|
||||
(pack(I, Opt))/binary, (pack(J, Opt))/binary, (pack(K, Opt))/binary, (pack(L, Opt))/binary,
|
||||
(pack(M, Opt))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H, I, J, K, L, M, N], Opt) ->
|
||||
<< 2#1001:4, 14:4/integer-unit:1,
|
||||
(pack(A, Opt))/binary, (pack(B, Opt))/binary, (pack(C, Opt))/binary, (pack(D, Opt))/binary,
|
||||
(pack(E, Opt))/binary, (pack(F, Opt))/binary, (pack(G, Opt))/binary, (pack(H, Opt))/binary,
|
||||
(pack(I, Opt))/binary, (pack(J, Opt))/binary, (pack(K, Opt))/binary, (pack(L, Opt))/binary,
|
||||
(pack(M, Opt))/binary, (pack(N, Opt))/binary >>;
|
||||
|
||||
pack_array([A, B, C, D, E, F, G, H, I, J, K, L, M, N, O], Opt) ->
|
||||
<< 2#1001:4, 15:4/integer-unit:1,
|
||||
(pack(A, Opt))/binary, (pack(B, Opt))/binary, (pack(C, Opt))/binary, (pack(D, Opt))/binary,
|
||||
(pack(E, Opt))/binary, (pack(F, Opt))/binary, (pack(G, Opt))/binary, (pack(H, Opt))/binary,
|
||||
(pack(I, Opt))/binary, (pack(J, Opt))/binary, (pack(K, Opt))/binary, (pack(L, Opt))/binary,
|
||||
(pack(M, Opt))/binary, (pack(N, Opt))/binary, (pack(O, Opt))/binary >>;
|
||||
|
||||
pack_array(L, Opt) ->
|
||||
case length(L) of
|
||||
Len when Len < 16#10000 -> % 65536
|
||||
<<16#DC:8, Len:16/big-unsigned-integer-unit:1, (<< <<(pack(E, Opt))/binary>> || E <- L >>)/binary>>;
|
||||
Len ->
|
||||
<<16#DD:8, Len:32/big-unsigned-integer-unit:1, (<< <<(pack(E, Opt))/binary>> || E <- L >>)/binary>>
|
||||
end.
|
||||
|
||||
-spec pack_map(msgpack:msgpack_map(), list(option())) -> binary() | no_return().
|
||||
pack_map([{Ka, Va}], Opt)->
|
||||
<< 2#1000:4, 1:4/integer-unit:1,
|
||||
(pack(Ka, Opt))/binary, (pack(Va, Opt))/binary >>;
|
||||
|
||||
pack_map([{Ka, Va}, {Kb, Vb}], Opt)->
|
||||
<< 2#1000:4, 2:4/integer-unit:1,
|
||||
(pack(Ka, Opt))/binary, (pack(Va, Opt))/binary,
|
||||
(pack(Kb, Opt))/binary, (pack(Vb, Opt))/binary >>;
|
||||
|
||||
pack_map([{Ka, Va}, {Kb, Vb}, {Kc, Vc}], Opt)->
|
||||
<< 2#1000:4, 3:4/integer-unit:1,
|
||||
(pack(Ka, Opt))/binary, (pack(Va, Opt))/binary,
|
||||
(pack(Kb, Opt))/binary, (pack(Vb, Opt))/binary,
|
||||
(pack(Kc, Opt))/binary, (pack(Vc, Opt))/binary >>;
|
||||
|
||||
pack_map([{Ka, Va}, {Kb, Vb}, {Kc, Vc}, {Kd, Vd}], Opt)->
|
||||
<< 2#1000:4, 4:4/integer-unit:1,
|
||||
(pack(Ka, Opt))/binary, (pack(Va, Opt))/binary,
|
||||
(pack(Kb, Opt))/binary, (pack(Vb, Opt))/binary,
|
||||
(pack(Kc, Opt))/binary, (pack(Vc, Opt))/binary,
|
||||
(pack(Kd, Opt))/binary, (pack(Vd, Opt))/binary >>;
|
||||
|
||||
pack_map(M, Opt)->
|
||||
case length(M) of
|
||||
Len when Len < 16 ->
|
||||
<<2#1000:4, Len:4/integer-unit:1,
|
||||
(<< <<(pack(K, Opt))/binary, (pack(V, Opt))/binary>> || {K, V} <- M >>)/binary>>;
|
||||
Len when Len < 16#10000 -> % 65536
|
||||
<<16#DE:8, Len:16/big-unsigned-integer-unit:1,
|
||||
(<< <<(pack(K, Opt))/binary, (pack(V, Opt))/binary>> || {K, V} <- M >>)/binary>>;
|
||||
Len ->
|
||||
<<16#DF:8, Len:32/big-unsigned-integer-unit:1,
|
||||
(<< <<(pack(K, Opt))/binary, (pack(V, Opt))/binary>> || {K, V} <- M >>)/binary>>
|
||||
end.
|
146
src/msgpack_unpacker.erl
Normal file
146
src/msgpack_unpacker.erl
Normal file
@ -0,0 +1,146 @@
|
||||
%%
|
||||
%% MessagePack for Erlang
|
||||
%%
|
||||
%% Copyright (C) 2009-2013 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.
|
||||
%%
|
||||
|
||||
-module(msgpack_unpacker).
|
||||
|
||||
-export([unpack_stream/2, map_unpacker/1]).
|
||||
|
||||
-include("msgpack.hrl").
|
||||
|
||||
-export([unpack_map_jiffy/4, unpack_map_jsx/4]).
|
||||
|
||||
%% unpack them all
|
||||
-spec unpack_stream(Bin::binary(), msgpack_option()) -> {msgpack:object(), binary()} | no_return().
|
||||
%% ATOMS
|
||||
unpack_stream(<<16#C0, Rest/binary>>, _) ->
|
||||
{nil, Rest};
|
||||
unpack_stream(<<16#C2, Rest/binary>>, _) ->
|
||||
{false, Rest};
|
||||
unpack_stream(<<16#C3, Rest/binary>>, _) ->
|
||||
{true, Rest};
|
||||
|
||||
%% Floats
|
||||
unpack_stream(<<16#CA, V:32/float-unit:1, Rest/binary>>, _) ->
|
||||
{V, Rest};
|
||||
unpack_stream(<<16#CB, V:64/float-unit:1, Rest/binary>>, _) ->
|
||||
{V, Rest};
|
||||
|
||||
%% Unsigned integers
|
||||
unpack_stream(<<16#CC, V:8/unsigned-integer, Rest/binary>>, _) ->
|
||||
{V, Rest};
|
||||
unpack_stream(<<16#CD, V:16/big-unsigned-integer-unit:1, Rest/binary>>, _) ->
|
||||
{V, Rest};
|
||||
unpack_stream(<<16#CE, V:32/big-unsigned-integer-unit:1, Rest/binary>>, _) ->
|
||||
{V, Rest};
|
||||
unpack_stream(<<16#CF, V:64/big-unsigned-integer-unit:1, Rest/binary>>, _) ->
|
||||
{V, Rest};
|
||||
|
||||
%% Signed integers
|
||||
unpack_stream(<<16#D0, V:8/signed-integer, Rest/binary>>, _) ->
|
||||
{V, Rest};
|
||||
unpack_stream(<<16#D1, V:16/big-signed-integer-unit:1, Rest/binary>>, _) ->
|
||||
{V, Rest};
|
||||
unpack_stream(<<16#D2, V:32/big-signed-integer-unit:1, Rest/binary>>, _) ->
|
||||
{V, Rest};
|
||||
unpack_stream(<<16#D3, V:64/big-signed-integer-unit:1, Rest/binary>>, _) ->
|
||||
{V, Rest};
|
||||
|
||||
%% Raw bytes
|
||||
unpack_stream(<<16#DA, L:16/unsigned-integer-unit:1, V:L/binary, Rest/binary>>, _) ->
|
||||
{V, Rest};
|
||||
unpack_stream(<<16#DB, L:32/unsigned-integer-unit:1, V:L/binary, Rest/binary>>, _) ->
|
||||
{V, Rest};
|
||||
|
||||
%% Arrays
|
||||
unpack_stream(<<16#DC, L:16/big-unsigned-integer-unit:1, Rest/binary>>, Opt) ->
|
||||
unpack_array(Rest, L, [], Opt);
|
||||
unpack_stream(<<16#DD, L:32/big-unsigned-integer-unit:1, Rest/binary>>, Opt) ->
|
||||
unpack_array(Rest, L, [], Opt);
|
||||
%% Maps
|
||||
unpack_stream(<<16#DE, L:16/big-unsigned-integer-unit:1, Rest/binary>>, Opt) ->
|
||||
Unpacker = Opt?OPTION.map_unpack_fun,
|
||||
Unpacker(Rest, L, [], Opt);
|
||||
|
||||
unpack_stream(<<16#DF, L:32/big-unsigned-integer-unit:1, Rest/binary>>, Opt) ->
|
||||
Unpacker = Opt?OPTION.map_unpack_fun,
|
||||
Unpacker(Rest, L, [], Opt);
|
||||
|
||||
%% Tag-encoded lengths (kept last, for speed)
|
||||
%% positive int
|
||||
unpack_stream(<<0:1, V:7, Rest/binary>>, _) -> {V, Rest};
|
||||
|
||||
%% negative int
|
||||
unpack_stream(<<2#111:3, V:5, Rest/binary>>, _) -> {V - 2#100000, Rest};
|
||||
|
||||
%% raw bytes
|
||||
unpack_stream(<<2#101:3, L:5, V:L/binary, Rest/binary>>, _) -> {V, Rest};
|
||||
|
||||
%% array
|
||||
unpack_stream(<<2#1001:4, L:4, Rest/binary>>, Opt) ->
|
||||
unpack_array(Rest, L, [], Opt);
|
||||
|
||||
%% map
|
||||
unpack_stream(<<2#1000:4, L:4, Rest/binary>>, Opt) ->
|
||||
Unpacker = Opt?OPTION.map_unpack_fun,
|
||||
Unpacker(Rest, L, [], Opt);
|
||||
|
||||
%% Invalid data
|
||||
unpack_stream(<<F, R/binary>>, _) when F==16#C1;
|
||||
F==16#C4; F==16#C5; F==16#C6; F==16#C7; F==16#C8; F==16#C9;
|
||||
F==16#D4; F==16#D5; F==16#D6; F==16#D7; F==16#D8; F==16#D9 ->
|
||||
throw({badarg, <<F, R/binary>>});
|
||||
%% Incomplete data (we've covered every complete/invalid case; anything left is incomplete)
|
||||
unpack_stream(_, _) ->
|
||||
throw(incomplete).
|
||||
|
||||
-spec unpack_array(binary(), non_neg_integer(), [msgpack:object()], msgpack_option()) ->
|
||||
{[msgpack:object()], binary()} | no_return().
|
||||
unpack_array(Bin, 0, Acc, _) ->
|
||||
{lists:reverse(Acc), Bin};
|
||||
unpack_array(Bin, Len, Acc, Opt) ->
|
||||
{Term, Rest} = unpack_stream(Bin, Opt),
|
||||
unpack_array(Rest, Len-1, [Term|Acc], Opt).
|
||||
|
||||
map_unpacker(jiffy) ->
|
||||
fun ?MODULE:unpack_map_jiffy/4;
|
||||
map_unpacker(jsx) ->
|
||||
fun ?MODULE:unpack_map_jsx/4.
|
||||
|
||||
|
||||
%% Users SHOULD NOT send too long list: this uses lists:reverse/1
|
||||
-spec unpack_map_jiffy(binary(), non_neg_integer(),
|
||||
msgpack:msgpack_map(), msgpack_option()) ->
|
||||
{msgpack:msgpack_map(), binary()} | no_return().
|
||||
unpack_map_jiffy(Bin, 0, Acc, _) ->
|
||||
{{lists:reverse(Acc)}, Bin};
|
||||
unpack_map_jiffy(Bin, Len, Acc, Opt) ->
|
||||
{Key, Rest} = unpack_stream(Bin, Opt),
|
||||
{Value, Rest2} = unpack_stream(Rest, Opt),
|
||||
unpack_map_jiffy(Rest2, Len-1, [{Key,Value}|Acc], Opt).
|
||||
|
||||
-spec unpack_map_jsx(binary(), non_neg_integer(),
|
||||
msgpack:msgpack_map(), msgpack_option()) ->
|
||||
{msgpack:msgpack_map(), binary()} | no_return().
|
||||
unpack_map_jsx(Bin, 0, [], _) ->
|
||||
{[{}], Bin};
|
||||
unpack_map_jsx(Bin, 0, Acc, _) ->
|
||||
{lists:reverse(Acc), Bin};
|
||||
unpack_map_jsx(Bin, Len, Acc, Opt) ->
|
||||
{Key, Rest} = unpack_stream(Bin, Opt),
|
||||
{Value, Rest2} = unpack_stream(Rest, Opt),
|
||||
unpack_map_jsx(Rest2, Len-1, [{Key,Value}|Acc], Opt).
|
@ -35,19 +35,19 @@ benchmark0_test()->
|
||||
Data=[test_data() || _ <- lists:seq(0, ?CNT)],
|
||||
S=?debugTime(" serialize", msgpack:pack(Data, [jiffy])),
|
||||
{ok, Data}=?debugTime("deserialize", msgpack:unpack(S, [jiffy])),
|
||||
?debugFmt("for ~p KB test data(msgpack_jiffy).", [byte_size(S) div 1024]).
|
||||
?debugFmt("for ~p KB test data(jiffy).", [byte_size(S) div 1024]).
|
||||
|
||||
benchmark1_test()->
|
||||
Data=[test_data() || _ <- lists:seq(0, ?CNT)],
|
||||
S=?debugTime(" serialize", msgpack:pack(Data, [jsx])),
|
||||
{ok, Data}=?debugTime("deserialize", msgpack:unpack(S, [jsx])),
|
||||
?debugFmt("for ~p KB test data(msgpack_jsx).", [byte_size(S) div 1024]).
|
||||
?debugFmt("for ~p KB test data(jsx).", [byte_size(S) div 1024]).
|
||||
|
||||
benchmark2_test()->
|
||||
Data=[test_data() || _ <- lists:seq(0, ?CNT)],
|
||||
S=?debugTime(" serialize", msgpack_nif:pack(Data)),
|
||||
{ok, Data}=?debugTime("deserialize", msgpack_nif:unpack(S)),
|
||||
?debugFmt("for ~p KB test data(msgpack_nif).", [byte_size(S) div 1024]).
|
||||
?debugFmt("for ~p KB test data(nif).", [byte_size(S) div 1024]).
|
||||
|
||||
benchmark3_test()->
|
||||
Data=[test_data() || _ <- lists:seq(0, ?CNT)],
|
||||
@ -93,7 +93,7 @@ multirunner(What, Pack, Unpack) ->
|
||||
benchmark_p0_test_() ->
|
||||
{timeout, 600,
|
||||
?_assertEqual(ok,
|
||||
multirunner("msgpack_jiffy",
|
||||
multirunner("jiffy",
|
||||
fun(Data) ->
|
||||
msgpack:pack(Data, [jiffy])
|
||||
end,
|
||||
@ -104,7 +104,7 @@ benchmark_p0_test_() ->
|
||||
benchmark_p1_test_() ->
|
||||
{timeout, 600,
|
||||
?_assertEqual(ok,
|
||||
multirunner("msgpack_jsx",
|
||||
multirunner("jsx",
|
||||
fun(Data) ->
|
||||
msgpack:pack(Data, [jsx])
|
||||
end,
|
||||
@ -115,7 +115,7 @@ benchmark_p1_test_() ->
|
||||
benchmark_p2_test_() ->
|
||||
{timeout, 600,
|
||||
?_assertEqual(ok,
|
||||
multirunner("msgpack_nif",
|
||||
multirunner("nif",
|
||||
fun(Data) ->
|
||||
msgpack_nif:pack(Data)
|
||||
end,
|
||||
|
Loading…
Reference in New Issue
Block a user