_site/cover/resp_codec.COVER.html

1 %% Copyright (c) 2023 Peter Morgan <peter.james.morgan@gmail.com>
2 %%
3 %% Licensed under the Apache License, Version 2.0 (the "License");
4 %% you may not use this file except in compliance with the License.
5 %% You may obtain a copy of the License at
6 %%
7 %% http://www.apache.org/licenses/LICENSE-2.0
8 %%
9 %% Unless required by applicable law or agreed to in writing, software
10 %% distributed under the License is distributed on an "AS IS" BASIS,
11 %% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 %% See the License for the specific language governing permissions and
13 %% limitations under the License.
14
15
16 -module(resp_codec).
17
18
19 -export([decode/1]).
20 -export([encode/1]).
21 -on_load(init/0).
22
23
24 init() ->
25 1 {ok, Types} = file:consult(filename:join(resp:priv_dir(), "type.terms")),
26 1 persistent_term:put(
27 types(),
28 lists:foldl(
29 fun
30 ({K, V}, #{encode := Encode, decode := Decode} = A) ->
31 15 A#{encode := Encode#{V => K}, decode := Decode#{K => V}}
32 end,
33 #{encode => #{}, decode => #{}},
34 Types)).
35
36
37 type(Codec, K) ->
38 166 case persistent_term:get(types()) of
39 #{Codec := #{K := V}} ->
40 166 V;
41
42 _ ->
43
:-(
error(badarg, [Codec, K])
44 end.
45
46
47 types() ->
48 167 [?MODULE, ?FUNCTION_NAME].
49
50
51 -spec decode(binary()) -> {resp:tv(), binary()} | partial.
52
53 decode(<<Type:8, Encoded/bytes>>) ->
54 83 ?FUNCTION_NAME(type(?FUNCTION_NAME, Type), Encoded).
55
56
57 decode(Type, <<"-1\r\n", Remainder/bytes>>) when Type == bulk;
58 Type == array ->
59 2 {{Type, null}, Remainder};
60
61 decode(Type, <<"\r\n", Remainder/bytes>>) when Type == null ->
62 1 {null, Remainder};
63
64 decode(Type, <<"inf\r\n", Remainder/bytes>>) when Type == double ->
65 1 {{double, inf}, Remainder};
66
67 decode(Type, <<"-inf\r\n", Remainder/bytes>>) when Type == double ->
68 1 {{double, ninf}, Remainder};
69
70 decode(Type, Encoded) ->
71 78 case split(Encoded) of
72 [Value, Remainder] when Type == integer; Type == big_number ->
73 22 {{Type, binary_to_integer(Value)}, Remainder};
74
75 [Value, Remainder] when Type == double ->
76 4 try
77 4 {{Type, binary_to_float(Value)}, Remainder}
78
79 catch error:badarg ->
80 1 {{Type, binary_to_integer(Value)}, Remainder}
81 end;
82
83 [Value, Remainder] when Type == array;
84 Type == set;
85 Type == bulk;
86 Type == map;
87 Type == attribute;
88 Type == push;
89 Type == verbatim_string;
90 Type == blob_error ->
91 28 ?FUNCTION_NAME(Type, binary_to_integer(Value), Remainder);
92
93 [<<"t">>, Remainder] when Type == boolean ->
94 3 {{Type, true}, Remainder};
95
96 [<<"f">>, Remainder] when Type == boolean ->
97 2 {{Type, false}, Remainder};
98
99 [Value, Remainder] ->
100 19 {{Type, Value}, Remainder};
101
102 _ ->
103
:-(
partial
104 end.
105
106
107 decode(Type, Count, Encoded) when Type == array;
108 Type == push;
109 Type == set;
110 Type == attribute;
111 Type == map ->
112 15 ?FUNCTION_NAME(Type, Count, Encoded, []);
113
114 decode(verbatim_string = Type, Length, Encoded) ->
115 1 case Encoded of
116 <<FormatValue:Length/bytes, "\r\n", Remainder/bytes>> ->
117 1 <<Format:3/bytes, ":", Value/bytes>> = FormatValue,
118 1 {{Type, {binary_to_existing_atom(Format), Value}}, Remainder};
119
120 _ ->
121
:-(
partial
122 end;
123
124 decode(Type, Length, Encoded) when Type == bulk; Type == blob_error ->
125 12 case Encoded of
126 <<Value:Length/bytes, "\r\n", Remainder/bytes>> ->
127 12 {{Type, Value}, Remainder};
128
129 _ ->
130
:-(
partial
131 end.
132
133
134 decode(Type, 0, Remainder, A) when Type == map;
135 Type == attribute;
136 Type == set;
137 Type == push;
138 Type == array ->
139 15 {{Type, lists:reverse(A)}, Remainder};
140
141 decode(Type, N, Encoded, A) when Type == map; Type == attribute ->
142 5 case decode(Encoded) of
143 {K, R0} ->
144 5 case decode(R0) of
145 {V, R1} ->
146 5 ?FUNCTION_NAME(Type, N - 1, R1, [{K, V} | A]);
147
148 partial ->
149
:-(
partial
150 end;
151
152 partial ->
153
:-(
partial
154 end;
155
156 decode(Type, N, Encoded, A) when Type == array;
157 Type == push;
158 Type == set ->
159 34 case decode(Encoded) of
160 {Decoded, Remainder} ->
161 34 ?FUNCTION_NAME(Type, N - 1, Remainder, [Decoded | A]);
162
163 partial ->
164
:-(
partial
165 end.
166
167
168 -spec encode(resp:tv()) -> iodata().
169
170 encode(null = Type) ->
171 1 [type(?FUNCTION_NAME, Type), crlf()];
172
173 encode({verbatim_string = Type, {Format, Value}})
174 when Format == txt; Format == mkd ->
175 1 [type(?FUNCTION_NAME, Type),
176 integer_to_binary(iolist_size(Value) + 4),
177 crlf(),
178 atom_to_binary(Format),
179 ":",
180 Value,
181 crlf()];
182
183 encode({string = Type, Value}) ->
184 15 [type(?FUNCTION_NAME, Type), Value, crlf()];
185
186 encode({error = Type, Value}) ->
187 4 [type(?FUNCTION_NAME, Type), Value, crlf()];
188
189 encode({boolean = Type, Value}) ->
190 5 [type(?FUNCTION_NAME, Type),
191 case Value of
192 3 true -> "t";
193 2 false -> "f"
194 end,
195 crlf()];
196
197 encode({Type, Value}) when Type == integer; Type == big_number ->
198 22 [type(?FUNCTION_NAME, Type), integer_to_binary(Value), crlf()];
199
200 encode({double = Type, inf}) ->
201 1 [type(?FUNCTION_NAME, Type), "inf", crlf()];
202
203 encode({double = Type, ninf}) ->
204 1 [type(?FUNCTION_NAME, Type), "-inf", crlf()];
205
206 encode({double = Type, Value}) when is_float(Value) ->
207 3 [type(?FUNCTION_NAME, Type), float_to_list(Value, [short]), crlf()];
208
209 encode({double = Type, Value}) when is_integer(Value) ->
210 1 [type(?FUNCTION_NAME, Type), integer_to_list(Value), crlf()];
211
212 encode({bulk = Type, null}) ->
213 1 [type(?FUNCTION_NAME, Type), "-1", crlf()];
214
215 encode({Type, Value}) when Type == bulk;
216 Type == blob_error ->
217 12 [type(?FUNCTION_NAME, Type),
218 integer_to_binary(iolist_size(Value)),
219 crlf(),
220 Value,
221 crlf()];
222
223 encode({array = Type, null}) ->
224 1 [type(?FUNCTION_NAME, Type), "-1", crlf()];
225
226 encode({Type, L}) when Type == map; Type == attribute ->
227 3 [type(?FUNCTION_NAME, Type),
228 integer_to_list(length(L)),
229 crlf(),
230 5 [[encode(K), encode(V)] || {K, V} <- L]];
231
232 encode({Type, L}) when Type == array;
233 Type == push;
234 Type == set ->
235 12 [type(?FUNCTION_NAME, Type),
236 integer_to_list(length(L)),
237 crlf(),
238 34 [encode(Element) || Element <- L]].
239
240
241 split(Encoded) ->
242 78 binary:split(Encoded, crlf()).
243
244
245 crlf() ->
246 174 <<"\r\n">>.
Line Hits Source