-
Notifications
You must be signed in to change notification settings - Fork 20
/
thoas.erl
151 lines (137 loc) · 4.72 KB
/
thoas.erl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
-module(thoas).
-export([
decode/1, decode/2, encode/1, encode/2, encode_to_iodata/1,
encode_to_iodata/2
]).
-export_type([
decode_error/0, decode_options/0, encode_options/0, json_term/0,
input_term/0
]).
-type decode_options() :: #{
strings => reference | copy,
keys => reference | copy | to_existing_atom | to_atom
}.
-type encode_options() :: #{
escape => json | unicode | html | javascript
}.
-type json_term() ::
integer() |
float() |
binary() |
boolean() |
'null' |
list(json_term()) |
#{
binary() => json_term(),
atom() => json_term()
}.
-type input_term() ::
integer() |
float() |
binary() |
atom() |
calendar:datetime() |
calendar:date() |
list(input_term()) |
list({binary() | atom(), input_term()}) |
#{ binary() | atom() => input_term() }.
-type decode_error() ::
unexpected_end_of_input |
{unexpected_byte, binary(), integer()} |
{unexpected_sequence, binary(), integer()}.
%% Decode JSON into Erlang terms.
%%
-spec decode(iodata()) -> {ok, json_term()} | {error, decode_error()}.
decode(Json) ->
decode(Json, #{}).
%% Decode JSON into Erlang terms.
%%
%% # Options
%%
%% Decoding of keys and string values can be controlled with the options
%% `strings` and `keys` respectively. They control how the values are decoded
%% into the final Erlang term structure.
%%
%% - Option values common to both `strings` and `keys`
%% - `reference` (default) - when possible thoas tries to create a
%% sub-binary into the original
%% - `copy` - always copies the sub-binary. This option is especially useful
%% when parts of the decoded data will be stored for a long time (in ETS
%% or some process state) to avoid keeping the reference to the original
%% data
%%
%% - Option values unique to `keys`
%% - `to_existing_atom` - convert keys to atoms if the atom already exists
%% - `to_atom` - convert all keys to new or existing atoms. **Caution:** only
%% use this if you know you need it, since atoms are not garbage
%% collected and there is a hard limit on the amount that can be created.
%% Should preferably only be used if the input data is trusted, or in
%% short running VM sessions
%%
-spec decode(iodata(), decode_options()) ->
{ok, json_term()} | {error, decode_error()}.
decode(Json, Options) when is_map(Options) ->
Binary = iolist_to_binary(Json),
thoas_decode:decode(Binary, Options).
%% Encode Erlang terms into JSON.
%%
%% Throws on invalid input.
%%
-spec encode(input_term()) -> binary().
encode(Term) ->
encode(Term, #{}).
%% Encode Erlang terms into JSON.
%%
%% Throws on invalid input.
%%
%% # Options
%%
%% - `escape`
%% - `json` (default) - the regular JSON escaping as defined by RFC 7159.
%% - `javascript` - additionally escapes the LINE SEPARATOR (U+2028) and
%% PARAGRAPH SEPARATOR (U+2029) characters to make the produced JSON valid
%% JavaScript.
%% - `html` - similar to `javascript_safe`, but also escapes the / character
%% to prevent XSS.
%% - `unicode` - escapes all non-ascii characters.
%%
-spec encode(input_term(), encode_options()) -> binary().
encode(Input, Options) when is_map(Options) ->
iolist_to_binary(thoas_encode:encode(Input, Options)).
%% Encode Erlang terms into JSON as iodata.
%%
%% This function should be preferred to encode/2, if the generated JSON will be
%% handed over to one of the IO functions or sent over the socket. The Erlang
%% runtime is able to leverage vectorised writes and avoid allocating a continuous
%% buffer for the whole resulting string, lowering memory use and increasing
%% performance.
%%
%% Throws on invalid input.
%%
-spec encode_to_iodata(input_term()) -> iodata().
encode_to_iodata(Term) ->
encode_to_iodata(Term, #{}).
%% Encode Erlang terms into JSON as iodata.
%%
%% This function should be preferred to encode/2, if the generated JSON will be
%% handed over to one of the IO functions or sent over the socket. The Erlang
%% runtime is able to leverage vectorised writes and avoid allocating a continuous
%% buffer for the whole resulting string, lowering memory use and increasing
%% performance.
%%
%% Throws on invalid input.
%%
%% # Options
%%
%% - `escape`
%% - `json` (default) - the regular JSON escaping as defined by RFC 7159.
%% - `javascript` - additionally escapes the LINE SEPARATOR (U+2028) and
%% PARAGRAPH SEPARATOR (U+2029) characters to make the produced JSON valid
%% JavaScript.
%% - `html` - similar to `javascript_safe`, but also escapes the / character
%% to prevent XSS.
%% - `unicode` - escapes all non-ascii characters.
%%
-spec encode_to_iodata(input_term(), encode_options()) -> iodata().
encode_to_iodata(Input, Options) ->
thoas_encode:encode(Input, Options).