_site/cover/mcd_protocol_meta.COVER.html

1 %% Copyright (c) 2022 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(mcd_protocol_meta).
17
18
19 -export([decode/2]).
20 -export([encode/1]).
21 -include("mcd.hrl").
22
23
24 decode(debug_reply = Command, Remainder) ->
25 1 [CommandLine, Encoded] = string:split(Remainder, ?RN),
26 1 {mcd_re:run(
27 #{meta => Command,
28 subject => CommandLine,
29 re => "(?<key>[^\\s]+) (?<internal>(\\w+=\\w+ ?)+)",
30 mapping => #{internal => fun decode_meta_debug_internal/1}}),
31 Encoded};
32
33 decode(Command, Remainder) when Command == head;
34 Command == not_stored;
35 Command == exists;
36 Command == not_found ->
37 30 [Flags, Encoded] = string:split(Remainder, ?RN),
38 30 {#{meta => Command, flags => mcd_meta_flags:decode(Flags)}, Encoded};
39
40 decode(Command, Remainder) when Command == debug;
41 Command == get;
42 Command == arithmetic;
43 Command == delete ->
44 41 [CommandLine, Encoded] = split(Remainder),
45 41 {re_run(
46 #{meta => Command,
47 subject => CommandLine,
48 re => [key, flags],
49 mapping => #{flags => fun mcd_meta_flags:decode/1}}),
50 Encoded};
51
52 decode(set = Command, Remainder) ->
53 25 [CommandLine, DataLine] = split(Remainder),
54 25 data_line(
55 re_run(
56 #{meta => Command,
57 subject => CommandLine,
58 re => [key, datalen, flags],
59 mapping => #{datalen => fun erlang:binary_to_integer/1,
60 flags => fun mcd_meta_flags:decode/1}}),
61 DataLine);
62
63 decode(Command, Remainder) when Command == no_op; Command == no_op_reply ->
64 7 [<<>>, Encoded] = split(Remainder),
65 7 {#{meta => Command}, Encoded};
66
67 decode(value = Command, Remainder) ->
68 19 [CommandLine, DataLine] = split(Remainder),
69 19 data_line(
70 re_run(
71 #{meta => Command,
72 subject => CommandLine,
73 re => [datalen, flags],
74 mapping => #{datalen => fun erlang:binary_to_integer/1,
75 flags => fun mcd_meta_flags:decode/1}}),
76 DataLine).
77
78
79 decode_meta_debug_internal(Encoded) ->
80 1 {match, Matches} = re:run(Encoded,
81 "(?<k>\\w+)=(?<v>\\w+)\s?",
82 [global,
83 {capture, all_names, binary}]),
84 1 [list_to_tuple(Match) || Match <- Matches].
85
86
87 encode(#{meta := set = Meta,
88 flags := Flags,
89 key := Key,
90 data := Data}) ->
91 22 [command(Meta),
92 " ",
93 Key,
94 " ",
95 integer_to_binary(iolist_size(Data)),
96 encode_flags(Flags),
97 ?RN,
98 Data,
99 ?RN];
100
101 encode(#{meta := value, data := Data} = Arg) when is_integer(Data) ->
102 10 ?FUNCTION_NAME(Arg#{data := integer_to_binary(Data)});
103
104 encode(#{meta := value = Meta,
105 flags := Flags,
106 data := Data}) ->
107 19 [command(Meta),
108 " ",
109 integer_to_binary(iolist_size(Data)),
110 encode_flags(Flags),
111 ?RN,
112 Data,
113 ?RN];
114
115 encode(#{meta := Meta, flags := Flags, key := Key})
116 when Meta == debug;
117 Meta == get;
118 Meta == arithmetic;
119 Meta == delete ->
120 35 [command(Meta),
121 " ",
122 Key,
123 encode_flags(Flags),
124 ?RN];
125
126 encode(#{meta := Meta, key := Key})
127 when Meta == debug; Meta == get; Meta == debug ->
128
:-(
[command(Meta), " ", Key, ?RN];
129
130 encode(#{meta := debug_reply = Meta, key := Key, internal := KV}) ->
131 1 [command(Meta), " ", Key, [[" ", K, "=", V] || {K, V} <- KV], ?RN];
132
133 encode(#{meta := Meta, flags := Flags}) ->
134 12 [command(Meta), encode_flags(Flags), ?RN];
135
136 encode(#{meta := Meta}) ->
137 25 [command(Meta), ?RN].
138
139
140 encode_flags([]) ->
141 17 [];
142 encode_flags(Flags) ->
143 71 [" ", mcd_meta_flags:encode(Flags)].
144
145
146 command(no_op) ->
147 3 "mn";
148 command(no_op_reply) ->
149 3 "MN";
150 command(miss) ->
151 1 "EN";
152 command(value) ->
153 19 "VA";
154 command(not_stored) ->
155 3 "NS";
156 command(not_found) ->
157 3 "NF";
158 command(head) ->
159 21 "HD";
160 command(exists) ->
161 3 "EX";
162 command(debug_reply) ->
163 1 "ME";
164 command(debug) ->
165 2 "me";
166 command(get) ->
167 13 "mg";
168 command(arithmetic) ->
169 17 "ma";
170 command(set) ->
171 22 "ms";
172 command(delete) ->
173 3 "md".
174
175
176 re_run(#{re := L} = Arg) when is_list(L) ->
177 85 mcd_re:run(
178 Arg#{re := lists:join(
179 "\\s*",
180 lists:map(
181 fun re/1,
182 L))}).
183
184 re(key = Arg) ->
185 66 ?FUNCTION_NAME(Arg, "[^\\s]+");
186
187 re(flags = Arg) ->
188 85 ?FUNCTION_NAME(Arg, "(\\w\\w*(\\s+\\w\\w*)*)?");
189
190 re(datalen = Arg) ->
191 44 ?FUNCTION_NAME(Arg, "\\d+").
192
193 re(Name, Expression) ->
194 195 io_lib:format("(?<~p>~s)", [Name, Expression]).
195
196
197 split(S) ->
198 92 string:split(S, ?RN).
199
200
201 data_line(#{datalen := Length} = Decoded, DataLine) ->
202 44 case DataLine of
203 <<Data:Length/bytes, ?RN, Encoded/bytes>> ->
204 44 {maps:without([datalen], Decoded#{data => Data}), Encoded};
205 _ ->
206
:-(
partial
207 end.
Line Hits Source