Skip to content

Commit 6edea40

Browse files
committed
Merge pull request #60 from msgpack/new-option-style
New option style
2 parents 675912e + 85a9945 commit 6edea40

8 files changed

Lines changed: 496 additions & 294 deletions

File tree

README.md

Lines changed: 89 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -4,10 +4,10 @@
44

55
[![Drone.io](https://drone.io/github.com/msgpack/msgpack-erlang/status.png)](https://drone.io/github.com/msgpack/msgpack-erlang)
66

7-
## prequisites for runtime
7+
## Prerequisites for runtime
88

9-
[Erlang/OTP](http://erlang.org/), >= 17.0
10-
Also based on [the new msgpack spec 232a0d](https://github.com/msgpack/msgpack/blob/232a0d14c6057000cc4a478f0dfbb5942ac54e9e/spec.md).
9+
[Erlang/OTP](http://erlang.org/), >= 17.0 Also based on
10+
[the new msgpack spec 0b8f5a](https://github.com/msgpack/msgpack/blob/0b8f5ac67cdd130f4d4d4fe6afb839b989fdb86a/spec.md).
1111

1212
## edit rebar.config to use in your application
1313

@@ -18,6 +18,14 @@ Also based on [the new msgpack spec 232a0d](https://github.com/msgpack/msgpack/b
1818
]}.
1919
```
2020

21+
Or as it is [now published at hex.pm](https://hex.pm/packages/msgpack), just
22+
23+
```erlang
24+
{deps, [msgpack]}.
25+
```
26+
27+
might work.
28+
2129
## Simple deserialization
2230

2331
```erlang
@@ -33,35 +41,95 @@ Ham = msgpack:pack(Spam),
3341
...
3442
```
3543

36-
## String type
44+
## Options, for packing and unpacking
3745

38-
Now this supports string type!
46+
### `{spec, new|old}`
47+
48+
Both for packing and unpacking. Default is `new`. Major difference
49+
between old and new spec is:
50+
51+
- raw family (`0xa0~0xbf`, `0xda`, `0xdb`) becomes new str family
52+
- `0xd9` is new as str8
53+
- new bin space (`0xc4, 0xc5, 0xc6` as bin8, bin16, bin32)
54+
- new ext space (`0xc7, 0xc8, 0xc9` as ext8, ext16, ext32)
55+
- new fixext space (`0xd4, 0xd5, 0xd6, 0xd7, 0xd8` as fixext1, fixext2, fixext4, fixext8, fixext16),
56+
57+
The default is new spec. Old spec mode does not handle these new types but
58+
returns error. To use
59+
[old spec](https://github.com/msgpack/msgpack/blob/master/spec-old.md)
60+
mode, this option is explicitly added.
3961

4062
```erlang
41-
Opt = [{enable_str, true}]
42-
{ok, "埼玉"} = msgpack:unpack(msgpack:pack("埼玉", Opt), Opt).
43-
=> {ok,[22524,29577]}
63+
OldHam = msgpack:pack(Spam, [{spec, old}]),
64+
{ok, Spam} = msgpack:unpack(OldHam, [{spec, old}]).
4465
```
4566

46-
There are several options for `msgpack:pack/2` and `msgpack:unpack/2` .
47-
See `msgpack:options()` in `msgpack.hrl`.
67+
### `{allow_atom, none|pack}`
4868

49-
## Map Style
69+
Only in packing. Atoms are packed as binaries. Default value is `pack`.
70+
Otherwise, any term including atoms throws badarg.
5071

51-
Since Erlang/OTP 17.0
72+
### `{known_atoms, [atom()]}`
73+
74+
Both in packing and unpacking. In packing, if an atom is in this list
75+
a binary is encoded as a binary. In unpacking, msgpacked binaries are
76+
decoded as atoms with `erlang:binary_to_existing_atom/2` with encoding
77+
`utf8`. Default value is an empty list.
78+
79+
Even if `allow_atom` is `none`, known atoms are packed.
80+
81+
### `{unpack_str, as_binary|as_list}`
82+
83+
A switch to choose decoded term style of `str` type when *unpacking*.
84+
Only available at new spec. Default is `as_list`.
5285

53-
```erlang
54-
msgpack:pack(#{ <<"key">> => <<"value">> }, [{format, map}]).
5586
```
87+
mode as_binary as_list
88+
-----------+------------+-------
89+
bin binary() binary()
90+
str binary() string()
91+
```
92+
93+
### `{validate_string, boolean()}`
5694

57-
Or use old jiffy/jsx style
95+
Only in unpacking, UTF-8 validation at unpacking from `str` type will
96+
be enabled. Default value is `false`.
97+
98+
### `{pack_str, from_binary|from_list|none}`
99+
100+
A switch to choose packing of `string()` when packing. Only available
101+
at new spec. Default is `from_list` for symmetry with `unpack_str`
102+
option.
103+
104+
```
105+
mode from_list from_binary none
106+
-----------+------------+--------------+-----------------
107+
binary() bin str*/bin bin
108+
string() str*/array array of int array of int
109+
list() array array array
110+
```
111+
112+
But the default option pays the cost of performance for symmetry. If
113+
the overhead of UTF-8 validation is unacceptable, choosing `none` as
114+
the option would be the best.
115+
116+
- \* Tries to pack as `str` if it is a valid `string()`.
117+
118+
### `{map_format, maps|jiffy|jsx}`
119+
120+
Both at packing and unpacking. Default value is `maps`.
58121

59122
```erlang
123+
msgpack:pack(#{ <<"key">> => <<"value">> }, []).
60124
msgpack:pack({[{<<"key">>, <<"value">>}]}, [{format, jiffy}]),
61125
msgpack:pack([{<<"key">>, <<"value">>}], [{format, jsx}]).
62126
```
63127

64-
## Ext type
128+
129+
### `{ext, {msgpack_ext_packer(), msgpack_ext_unpacker()}|module()}`
130+
131+
At both. The default behaviour in case of facing ext data at decoding
132+
is to ignore them as its length is known.
65133

66134
Now msgpack-erlang supports ext type. Now you can serialize everything
67135
with your original (de)serializer. That will enable us to handle
@@ -76,29 +144,17 @@ Opt = [{ext,{Packer,Unpacker}}],
76144
{ok, {ref, Ref}} = msgpack:unpack(msgpack:pack({ref, Ref}, Opt), Opt).
77145
```
78146

79-
This is still experimental feature, so I'm waiting for your feedback.
80-
81-
## Compatibility mode
82-
83-
To use as same with [old spec](https://github.com/msgpack/msgpack/blob/master/spec-old.md):
84-
85-
```erlang
86-
OldHam = msgpack:pack(Spam, [{enable_str,false}]),
87-
{ok, Spam} = msgpack:unpack(OldHam, [{enable_str,false}]).
88-
```
89-
90-
Since 0.2.3 now it's **false by default**.
91-
92-
## Further tests
93-
94-
See [msgpack-erlang-tests](http://github.com/kuenishi/msgpack-erlang-tests) for further tests
95-
96147
## License
97148

98149
Apache License 2.0
99150

100151
# Release Notes
101152

153+
## 0.5.0
154+
155+
- Renewed optional arguments to pack/unpack interface. This is
156+
incompatible change from 0.4 series.
157+
102158
## 0.4.0
103159

104160
- Deprecate `nil`

include/msgpack.hrl

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

src/msgpack.erl

Lines changed: 56 additions & 30 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,43 @@ 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+
parse_options(T, Opt0?OPTION{unpack_str=As});
163+
164+
parse_options([{validate_string, Bool}|T], Opt) when is_boolean(Bool) ->
165+
parse_options(T, Opt?OPTION{validate_string=Bool});
166+
167+
parse_options([{pack_str, From}|T], Opt)
168+
when From =:= from_binary orelse From =:= from_list orelse From =:= none ->
169+
parse_options(T, Opt?OPTION{pack_str=From});
170+
171+
parse_options([{map_format,Type}|T], Opt0)
172+
when Type =:= jsx; Type =:= jiffy; Type =:= map ->
173+
Opt = Opt0?OPTION{map_format=Type,
174+
map_unpack_fun=msgpack_unpacker:map_unpacker(Type)},
175+
parse_options(T, Opt);
150176

151177
parse_options([{ext, Module}|TL], Opt0) when is_atom(Module) ->
152178
Opt = Opt0?OPTION{ext_packer=fun Module:pack_ext/2,
@@ -200,10 +226,10 @@ test_data()->
200226
-endif.
201227

202228
enable_str_test() ->
203-
?assertEqual(<<167:8, (<<"saitama">>)/binary >>,
204-
msgpack:pack(<<"saitama">>, [{enable_str, false}])),
205-
?assertEqual(<<196,7,115,97,105,116,97,109,97>>,
206-
msgpack:pack(<<"saitama">>, [{enable_str, true}])).
229+
?assertEqual(<<167:8, "saitama">>,
230+
msgpack:pack(<<"saitama">>, [{spec,old}])),
231+
?assertEqual(<<2#101:3, 7:5, "saitama">>, %% binary becomes str8 from_binary
232+
msgpack:pack(<<"saitama">>, [{spec,new},{pack_str,from_binary}])).
207233

208234
basic_test()->
209235
Tests = test_data(),
@@ -240,9 +266,9 @@ other_test()->
240266
?assertEqual({error,incomplete},msgpack:unpack(<<>>)).
241267

242268
error_test()->
243-
?assertEqual({error,{badarg, atom}}, msgpack:pack(atom)),
269+
?assertEqual({error,{badarg, atom}}, msgpack:pack(atom, [{allow_atom, none}])),
244270
Term = {"hoge", "hage", atom},
245-
?assertEqual({error,{badarg, Term}}, msgpack:pack(Term)).
271+
?assertEqual({error,{badarg, Term}}, msgpack:pack(Term, [{allow_atom, none}])).
246272

247273
long_binary_test()->
248274
A = msgpack:pack(1),

0 commit comments

Comments
 (0)