1 |
|
%%============================================================================== |
2 |
|
%% Copyright 2014 Erlang Solutions Ltd. |
3 |
|
%% |
4 |
|
%% Licensed under the Apache License, Version 2.0 (the "License"); |
5 |
|
%% you may not use this file except in compliance with the License. |
6 |
|
%% You may obtain a copy of the License at |
7 |
|
%% |
8 |
|
%% http://www.apache.org/licenses/LICENSE-2.0 |
9 |
|
%% |
10 |
|
%% Unless required by applicable law or agreed to in writing, software |
11 |
|
%% distributed under the License is distributed on an "AS IS" BASIS, |
12 |
|
%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
13 |
|
%% See the License for the specific language governing permissions and |
14 |
|
%% limitations under the License. |
15 |
|
%%============================================================================== |
16 |
|
-module(mongoose_api_json). |
17 |
|
|
18 |
|
-behaviour(mongoose_api_format). |
19 |
|
|
20 |
|
%% mongoose_api_format callbacks |
21 |
|
-export([serialize/1, |
22 |
|
deserialize/1]). |
23 |
|
|
24 |
|
%%-------------------------------------------------------------------- |
25 |
|
%% mongoose_api_format callbacks |
26 |
|
%%-------------------------------------------------------------------- |
27 |
|
deserialize(Json) -> |
28 |
32 |
try jiffy:decode(Json, [return_maps]) of |
29 |
|
Data -> |
30 |
31 |
{ok, do_deserialize(Data)} |
31 |
|
catch _:_ -> |
32 |
1 |
{error, unprocessable} |
33 |
|
end. |
34 |
|
|
35 |
|
serialize(Data) -> |
36 |
568 |
do_serialize(Data). |
37 |
|
|
38 |
|
%%-------------------------------------------------------------------- |
39 |
|
%% internal functions |
40 |
|
%%-------------------------------------------------------------------- |
41 |
|
do_deserialize(#{} = Map) -> |
42 |
62 |
maps:to_list(maps:map(fun(_K, V) -> do_deserialize(V) end, Map)); |
43 |
|
do_deserialize(NotAMap) -> |
44 |
31 |
NotAMap. |
45 |
|
|
46 |
|
do_serialize(Data) -> |
47 |
568 |
jiffy:encode(prepare_struct(Data)). |
48 |
|
|
49 |
|
prepare_struct({Key, Value}) -> |
50 |
706 |
#{prepare_key(Key) => prepare_struct(Value)}; |
51 |
|
prepare_struct([]) -> |
52 |
1 |
[]; |
53 |
|
prepare_struct(List) when is_list(List) -> |
54 |
28669 |
case is_proplist(List) of |
55 |
|
true -> |
56 |
28614 |
maps:from_list([{prepare_key(K), prepare_struct(V)} || {K, V} <- List]); |
57 |
|
false -> |
58 |
55 |
[prepare_struct(Element) || Element <- List] |
59 |
|
end; |
60 |
|
prepare_struct(List) when is_list(List) -> |
61 |
:-( |
try unicode:characters_to_binary(List) of |
62 |
:-( |
Bin when is_binary(Bin) -> Bin; |
63 |
:-( |
_ -> List %% Items in List are not valid unicode codepoints |
64 |
|
catch |
65 |
:-( |
error:badarg -> List %% List is not a list of characters |
66 |
|
end; |
67 |
|
prepare_struct(Other) -> |
68 |
94840 |
Other. |
69 |
|
|
70 |
|
prepare_key(Key) when is_integer(Key) -> |
71 |
24924 |
integer_to_binary(Key); |
72 |
|
prepare_key(Key) when is_list(Key); is_binary(Key) -> |
73 |
21382 |
case unicode:characters_to_binary(Key) of |
74 |
21382 |
Bin when is_binary(Bin) -> Bin |
75 |
|
end; |
76 |
|
prepare_key(Key) -> |
77 |
76982 |
Key. |
78 |
|
|
79 |
|
is_proplist(List) -> |
80 |
28669 |
is_proplist(List, sets:new()). |
81 |
|
|
82 |
|
is_proplist([], _Keys) -> |
83 |
28614 |
true; |
84 |
|
is_proplist([{Key, _} | Tail], Keys) -> |
85 |
122682 |
case sets:is_element(Key, Keys) of |
86 |
|
true -> |
87 |
50 |
false; |
88 |
|
false -> |
89 |
122632 |
is_proplist(Tail, sets:add_element(Key, Keys)) |
90 |
|
end; |
91 |
|
is_proplist(_Other, _Keys) -> |
92 |
5 |
false. |