Skip to content

Commit 78b6651

Browse files
committed
New options style
1 parent 43b48f6 commit 78b6651

8 files changed

Lines changed: 216 additions & 212 deletions

File tree

README.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -67,6 +67,7 @@ OldHam = msgpack:pack(Spam, [{spec, old}]),
6767
### `{allow_atom, none|pack}`
6868

6969
Only in packing. Atoms are packed as binaries. Default value is `pack`.
70+
Otherwise, any term including atoms throws badarg.
7071

7172
### `{known_atoms, [atom()]}`
7273

@@ -75,6 +76,8 @@ a binary is encoded as a binary. In unpacking, msgpacked binaries are
7576
decoded as atoms with `erlang:binary_to_existing_atom/2` with encoding
7677
`utf8`. Default value is an empty list.
7778

79+
Even if `allow_atom` is `none`, known atoms are packed.
80+
7881
### `{unpack_str, as_binary|as_list}`
7982

8083
A switch to choose decoded term style of `str` type when *unpacking*.

include/msgpack.hrl

Lines changed: 0 additions & 90 deletions
This file was deleted.

src/msgpack.erl

Lines changed: 53 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
%%
22
%% MessagePack for Erlang
33
%%
4-
%% Copyright (C) 2009-2013 UENISHI Kota
4+
%% Copyright (C) 2009-2016 UENISHI Kota
55
%%
66
%% Licensed under the Apache License, Version 2.0 (the "License");
77
%% you may not use this file except in compliance with the License.
@@ -45,10 +45,32 @@
4545

4646
-include("msgpack.hrl").
4747

48-
%% for export
49-
-export_type([object/0, msgpack_map/0, options/0]).
48+
-export_type([object/0, msgpack_map/0, options/0, ext_packer/0, ext_unpacker/0]).
5049
-type object() :: msgpack_term().
51-
-type options() :: msgpack_list_options().
50+
51+
-type options() ::
52+
[{spec, new|old} |
53+
{allow_atom, none|pack} |
54+
{known_atoms, [atom()]} |
55+
{unpack_str, as_binary|as_list} |
56+
{validate_string, boolean()} |
57+
{pack_str, from_binary|from_list|none} |
58+
{map_format, map|jiffy|jsx} |
59+
{ext, {msgpack:ext_packer(), msgpack:ext_unpacker()} | module()}].
60+
61+
-type opt_record() :: ?OPTION{}.
62+
-export_type([opt_record/0]).
63+
64+
%% @doc ext_packer that packs only tuples with length > 2
65+
-type ext_packer() :: fun((tuple(), msgpack:options()) ->
66+
{ok, {Type::byte(), Data::binary()}} |
67+
{error, any()}).
68+
-type ext_unpacker() ::
69+
fun((byte(), binary(), msgpack:options()) ->
70+
{ok, msgpack_term()} | {error, any()})
71+
| fun((byte(), binary()) ->
72+
{ok, msgpack_term()} | {error, any()}).
73+
5274

5375
-spec term_to_binary(term()) -> binary().
5476
term_to_binary(Term) ->
@@ -114,39 +136,42 @@ unpack_stream(Bin, Opts0) when is_binary(Bin) ->
114136
unpack_stream(Other, _) -> {error, {badarg, Other}}.
115137

116138
%% @private
117-
-spec parse_options(msgpack:options()) -> msgpack_option().
139+
-spec parse_options(msgpack:options()) -> ?OPTION{}.
118140

119141
parse_options(Opt) ->
120142
parse_options(Opt, ?OPTION{original_list=Opt}).
121143

122144
%% @private
123-
-spec parse_options(msgpack:options(), msgpack_option()) -> msgpack_option().
145+
-spec parse_options(msgpack:options(), ?OPTION{}) -> ?OPTION{}.
124146
parse_options([], Opt) -> Opt;
125147

126-
parse_options([jsx|TL], Opt0) ->
127-
Opt = Opt0?OPTION{interface=jsx,
128-
map_unpack_fun=msgpack_unpacker:map_unpacker(jsx)},
129-
parse_options(TL, Opt);
130-
parse_options([jiffy|TL], Opt0) ->
131-
Opt = Opt0?OPTION{interface=jiffy,
132-
map_unpack_fun=msgpack_unpacker:map_unpacker(jiffy)},
133-
parse_options(TL, Opt);
134-
parse_options([{format,Type}|TL], Opt0)
135-
when Type =:= jsx; Type =:= jiffy; Type =:= map->
136-
Opt = Opt0?OPTION{interface=Type,
137-
map_unpack_fun=msgpack_unpacker:map_unpacker(Type)},
138-
parse_options(TL, Opt);
148+
parse_options([{spec, Spec}|T], Opt0) when Spec =:= new orelse Spec =:= old ->
149+
parse_options(T, Opt0?OPTION{spec = Spec});
139150

140-
parse_options([{allow_atom,Type}|TL], Opt0) ->
151+
parse_options([{allow_atom,Type}|T], Opt0) ->
141152
Opt = case Type of
142153
none -> Opt0?OPTION{allow_atom=none};
143154
pack -> Opt0?OPTION{allow_atom=pack}
144155
end,
145-
parse_options(TL, Opt);
156+
parse_options(T, Opt);
146157

147-
parse_options([{enable_str,Bool}|TL], Opt0) ->
148-
Opt = Opt0?OPTION{enable_str=Bool},
149-
parse_options(TL, Opt);
158+
parse_options([{known_atoms, Atoms}|T], Opt0) when is_list(Atoms) ->
159+
parse_options(T, Opt0?OPTION{known_atoms=Atoms});
160+
161+
parse_options([{unpack_str, As}|T], Opt0) when As =:= as_binary orelse As =:= as_list ->
162+
%% TODO Choose function here
163+
parse_options(T, Opt0?OPTION{unpack_str=As});
164+
165+
parse_options([{pack_str, From}|T], Opt)
166+
when From =:= from_binary orelse From =:= from_list orelse From =:= none ->
167+
%% TODO Choose function here
168+
parse_options(T, Opt);
169+
170+
parse_options([{map_format,Type}|T], Opt0)
171+
when Type =:= jsx; Type =:= jiffy; Type =:= map ->
172+
Opt = Opt0?OPTION{map_format=Type,
173+
map_unpack_fun=msgpack_unpacker:map_unpacker(Type)},
174+
parse_options(T, Opt);
150175

151176
parse_options([{ext, Module}|TL], Opt0) when is_atom(Module) ->
152177
Opt = Opt0?OPTION{ext_packer=fun Module:pack_ext/2,
@@ -201,9 +226,9 @@ test_data()->
201226

202227
enable_str_test() ->
203228
?assertEqual(<<167:8, (<<"saitama">>)/binary >>,
204-
msgpack:pack(<<"saitama">>, [{enable_str, false}])),
229+
msgpack:pack(<<"saitama">>, [{spec,old}])),
205230
?assertEqual(<<196,7,115,97,105,116,97,109,97>>,
206-
msgpack:pack(<<"saitama">>, [{enable_str, true}])).
231+
msgpack:pack(<<"saitama">>, [{spec,new},{pack_str,from_binary}])).
207232

208233
basic_test()->
209234
Tests = test_data(),
@@ -240,9 +265,9 @@ other_test()->
240265
?assertEqual({error,incomplete},msgpack:unpack(<<>>)).
241266

242267
error_test()->
243-
?assertEqual({error,{badarg, atom}}, msgpack:pack(atom)),
268+
?assertEqual({error,{badarg, atom}}, msgpack:pack(atom, [{allow_atom, none}])),
244269
Term = {"hoge", "hage", atom},
245-
?assertEqual({error,{badarg, Term}}, msgpack:pack(Term)).
270+
?assertEqual({error,{badarg, Term}}, msgpack:pack(Term, [{allow_atom, none}])).
246271

247272
long_binary_test()->
248273
A = msgpack:pack(1),

src/msgpack.hrl

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
%%
2+
%% MessagePack for Erlang
3+
%%
4+
%% Copyright (C) 2009-2016 UENISHI Kota
5+
%%
6+
%% Licensed under the Apache License, Version 2.0 (the "License");
7+
%% you may not use this file except in compliance with the License.
8+
%% You may obtain a copy of the License at
9+
%%
10+
%% http://www.apache.org/licenses/LICENSE-2.0
11+
%%
12+
%% Unless required by applicable law or agreed to in writing, software
13+
%% distributed under the License is distributed on an "AS IS" BASIS,
14+
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15+
%% See the License for the specific language governing permissions and
16+
%% limitations under the License.
17+
%%
18+
19+
-type msgpack_map_jsx() :: [{msgpack_term(), msgpack_term()}] | [{}].
20+
-type msgpack_map_jiffy() :: {[{msgpack_term(), msgpack_term()}]}.
21+
-type msgpack_map() :: msgpack_map_jsx() | msgpack_map_jiffy() | map().
22+
23+
-type msgpack_map_unpacker() ::
24+
fun((binary(), non_neg_integer(), msgpack:opt_record()) ->
25+
{msgpack_map(), binary()} | no_return() ).
26+
27+
%% Erlang representation of msgpack data.
28+
-type msgpack_term() :: [msgpack_term()] | msgpack_map() |
29+
integer() | float() | boolean() | binary().
30+
31+
-type format_type() :: jsx|jiffy|map.
32+
33+
-define(DEFAULT_MAP_FORMAT, map).
34+
-define(DEFAULT_MAP_UNPACKER_FUN, fun msgpack_unpacker:unpack_map/3).
35+
36+
-record(options_v4, {
37+
spec = new :: new | old,
38+
allow_atom = pack :: none | pack, %% allows atom when packing
39+
known_atoms = [] :: [atom()],
40+
unpack_str = as_list :: as_binary | as_list,
41+
validate_string = false :: boolean(),
42+
pack_str = from_list :: from_binary | from_list | none,
43+
map_format = ?DEFAULT_MAP_FORMAT :: format_type(),
44+
map_unpack_fun = ?DEFAULT_MAP_UNPACKER_FUN :: msgpack_map_unpacker(),
45+
ext_packer = undefined :: msgpack:ext_packer() | undefined,
46+
ext_unpacker = undefined :: msgpack:ext_unpacker() | undefined,
47+
original_list = [] :: msgpack:options()
48+
}).
49+
50+
-define(OPTION, #options_v4).

src/msgpack_packer.erl

Lines changed: 25 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,7 @@
2424
-include_lib("eunit/include/eunit.hrl").
2525

2626
%% pack them all
27-
-spec pack(msgpack:object(), msgpack_option()) -> binary().
28-
27+
-spec pack(msgpack:object(), ?OPTION{}) -> binary().
2928
pack(I, _) when is_integer(I) andalso I < 0 ->
3029
pack_int(I);
3130
pack(I, _) when is_integer(I) ->
@@ -43,19 +42,26 @@ pack(Bin, Opt) when is_binary(Bin) ->
4342
handle_binary(Bin, Opt);
4443

4544
pack(Atom, ?OPTION{allow_atom=pack} = Opt) when is_atom(Atom) ->
46-
pack(erlang:atom_to_binary(Atom, unicode), Opt);
45+
handle_binary(erlang:atom_to_binary(Atom, utf8), Opt);
46+
pack(Atom, ?OPTION{known_atoms=Atoms} = Opt) when is_atom(Atom) ->
47+
case lists:member(Atom, Atoms) of
48+
true ->
49+
handle_binary(erlang:atom_to_binary(Atom, utf8), Opt);
50+
false ->
51+
handle_ext(Atom, Opt)
52+
end;
4753

4854
%% jiffy interface
49-
pack({Map}, Opt = ?OPTION{interface=jiffy}) when is_list(Map) ->
55+
pack({Map}, Opt = ?OPTION{map_format=jiffy}) when is_list(Map) ->
5056
pack_map(Map, Opt);
5157

5258
%% jsx interface
53-
pack(Map, Opt = ?OPTION{interface=jsx}) when Map =:= [{}]->
59+
pack(Map, Opt = ?OPTION{map_format=jsx}) when Map =:= [{}]->
5460
pack_map([], Opt);
55-
pack([{_,_}|_] = Map, Opt = ?OPTION{interface=jsx}) ->
61+
pack([{_,_}|_] = Map, Opt = ?OPTION{map_format=jsx}) ->
5662
pack_map(Map, Opt);
5763

58-
pack(List, ?OPTION{enable_str=true}=Opt) when is_list(List) ->
64+
pack(List, ?OPTION{spec=new, pack_str=from_list}=Opt) when is_list(List) ->
5965
try
6066
case lists:all(fun is_integer/1, List) of
6167
true ->
@@ -80,14 +86,14 @@ pack(List, Opt) when is_list(List) ->
8086
pack(Other, Opt) ->
8187
handle_ext(Other, Opt).
8288

83-
handle_binary(Bin, Opt) ->
84-
case Opt of
85-
#options_v3{enable_str=true} = Opt -> pack_raw2(Bin);
86-
#options_v3{enable_str=false} = Opt -> pack_raw(Bin);
87-
#options_v2{enable_str=true} = Opt -> pack_raw2(Bin);
88-
#options_v2{enable_str=false} = Opt -> pack_raw(Bin);
89-
#options_v1{} = Opt -> pack_raw(Bin)
90-
end.
89+
handle_binary(Bin, ?OPTION{spec=old}) ->
90+
pack_raw(Bin);
91+
handle_binary(Bin, ?OPTION{spec=new, pack_str=from_list}) ->
92+
pack_raw2(Bin);
93+
handle_binary(Bin, ?OPTION{spec=new, pack_str=from_binary} = Opt) ->
94+
pack_string(unicode:characters_to_list(Bin), Opt);
95+
handle_binary(Bin, ?OPTION{spec=new}) ->
96+
pack_raw2(Bin).
9197

9298
%% %% map interface
9399
handle_ext(Map, Opt) when is_map(Map) ->
@@ -187,7 +193,7 @@ pack_raw2(Bin) ->
187193
%% @doc String MAY be unicode. Or may be EUC-JP, SJIS, UTF-1024 or anything.
188194
%% EVERY implementation must show its binary length just after type indicator
189195
%% to skip the damn string if its unreadable.
190-
-spec pack_string(list(), msgpack_option()) -> binary() | {error, atom()}.
196+
-spec pack_string(list(), ?OPTION{}) -> binary() | {error, atom()}.
191197
pack_string(String, _Opt) ->
192198
case unicode:characters_to_binary(String) of
193199
{error, _Bin, _} -> {error, broken_unicode};
@@ -207,7 +213,7 @@ pack_string(String, _Opt) ->
207213
end
208214
end.
209215

210-
-spec pack_array([msgpack:object()], msgpack_option()) -> binary() | no_return().
216+
-spec pack_array([msgpack:object()], ?OPTION{}) -> binary() | no_return().
211217
pack_array([], _) ->
212218
<< 2#1001:4, 0:4/integer-unit:1 >>;
213219

@@ -299,7 +305,7 @@ pack_array(L, Opt) ->
299305
throw({badarg, L})
300306
end.
301307

302-
-spec pack_map(msgpack:msgpack_map(), msgpack_option()) -> binary() | no_return().
308+
-spec pack_map(msgpack:msgpack_map(), ?OPTION{}) -> binary() | no_return().
303309
pack_map([{Ka, Va}], Opt)->
304310
<< 2#1000:4, 1:4/integer-unit:1,
305311
(pack(Ka, Opt))/binary, (pack(Va, Opt))/binary >>;
@@ -337,7 +343,7 @@ pack_map(M, Opt)->
337343
throw({badarg, M})
338344
end.
339345

340-
-spec pack_ext(any(), msgpack_ext_packer(), msgpack:options()) -> {ok, binary()} | {error, any()}.
346+
-spec pack_ext(any(), msgpack:ext_packer(), msgpack:options()) -> {ok, binary()} | {error, any()}.
341347
pack_ext(Any, Packer, Opt) ->
342348
case Packer(Any, Opt) of
343349
{ok, {Type, Data}} when -16#80 =< Type andalso Type =< 16#7F ->

0 commit comments

Comments
 (0)