| 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_meta_flags). |
| 17 |
|
|
| 18 |
|
|
| 19 |
|
-export([as_map/2]). |
| 20 |
|
-export([decode/1]). |
| 21 |
|
-export([encode/1]). |
| 22 |
|
-export_type([flag/0]). |
| 23 |
|
|
| 24 |
|
|
| 25 |
|
-type flag() :: base64 |
| 26 |
|
| cas |
| 27 |
|
| {cas_expected, mcd:uint32()} |
| 28 |
|
| flags |
| 29 |
|
| {flags, mcd:uint32()} |
| 30 |
|
| hit |
| 31 |
|
| invalidate |
| 32 |
|
| key_as_token |
| 33 |
|
| last_accessed |
| 34 |
|
| {mode, binary()} |
| 35 |
|
| {vivify, mcd:uint32()} |
| 36 |
|
| {opaque, binary()} |
| 37 |
|
| noreply |
| 38 |
|
| {remaining, mcd:uint32()} |
| 39 |
|
| size |
| 40 |
|
| ttl |
| 41 |
|
| {ttl, mcd:uint32()} |
| 42 |
|
| {set_ttl, mcd:uint32()} |
| 43 |
|
| stale |
| 44 |
|
| dont_bump_lru |
| 45 |
|
| value |
| 46 |
|
| already_winning |
| 47 |
|
| won. |
| 48 |
|
|
| 49 |
|
|
| 50 |
|
-spec decode(binary()) -> [flag()]. |
| 51 |
|
|
| 52 |
|
|
| 53 |
|
decode(<<>>) -> |
| 54 |
37 |
[]; |
| 55 |
|
|
| 56 |
|
decode(Encoded) -> |
| 57 |
100 |
lists:map( |
| 58 |
|
fun demarshal/1, |
| 59 |
|
string:split( |
| 60 |
|
string:trim(Encoded), |
| 61 |
|
whitespace(), |
| 62 |
|
all)). |
| 63 |
|
|
| 64 |
|
|
| 65 |
|
-spec encode([flag()]) -> iolist(). |
| 66 |
|
|
| 67 |
|
encode(Decoded) -> |
| 68 |
93 |
lists:join( |
| 69 |
|
" ", |
| 70 |
|
lists:map(fun marshal/1, Decoded)). |
| 71 |
|
|
| 72 |
|
|
| 73 |
|
whitespace() -> |
| 74 |
100 |
" ". |
| 75 |
|
|
| 76 |
|
|
| 77 |
7 |
demarshal(<<"C", Token/bytes>>) -> ?FUNCTION_NAME(cas_expected, Token); |
| 78 |
4 |
demarshal(<<"D", Token/bytes>>) -> ?FUNCTION_NAME(delta, Token); |
| 79 |
3 |
demarshal(<<"F", Token/bytes>>) -> ?FUNCTION_NAME(flags, Token); |
| 80 |
3 |
demarshal(<<"I">>) -> invalidate; |
| 81 |
5 |
demarshal(<<"J", Token/bytes>>) -> ?FUNCTION_NAME(initial, Token); |
| 82 |
12 |
demarshal(<<"M", Token/bytes>>) -> {mode, Token}; |
| 83 |
10 |
demarshal(<<"N", Token/bytes>>) -> ?FUNCTION_NAME(vivify, Token); |
| 84 |
5 |
demarshal(<<"O", Token/bytes>>) -> {opaque, Token}; |
| 85 |
1 |
demarshal(<<"R", Token/bytes>>) -> ?FUNCTION_NAME(remaining, Token); |
| 86 |
19 |
demarshal(<<"T", Token/bytes>>) -> ?FUNCTION_NAME(set_ttl, Token); |
| 87 |
:-( |
demarshal(<<"W">>) -> won; |
| 88 |
:-( |
demarshal(<<"X">>) -> stale; |
| 89 |
:-( |
demarshal(<<"Z">>) -> already_winning; |
| 90 |
3 |
demarshal(<<"b">>) -> base64; |
| 91 |
7 |
demarshal(<<"c">>) -> cas; |
| 92 |
6 |
demarshal(<<"c", Token/bytes>>) -> ?FUNCTION_NAME(cas, Token); |
| 93 |
3 |
demarshal(<<"f">>) -> flags; |
| 94 |
1 |
demarshal(<<"h">>) -> hit; |
| 95 |
5 |
demarshal(<<"h", Token/bytes>>) -> ?FUNCTION_NAME(hit, Token); |
| 96 |
4 |
demarshal(<<"k", Token/bytes>>) -> {key, Token}; |
| 97 |
:-( |
demarshal(<<"k">>) -> key; |
| 98 |
1 |
demarshal(<<"l">>) -> last_accessed; |
| 99 |
3 |
demarshal(<<"l", Token/bytes>>) -> ?FUNCTION_NAME(last_accessed, Token); |
| 100 |
2 |
demarshal(<<"q">>) -> noreply; |
| 101 |
12 |
demarshal(<<"s">>) -> size; |
| 102 |
10 |
demarshal(<<"s", Size/bytes>>) -> {size, binary_to_integer(Size)}; |
| 103 |
14 |
demarshal(<<"t">>) -> ttl; |
| 104 |
7 |
demarshal(<<"t", Token/bytes>>) -> ?FUNCTION_NAME(ttl, Token); |
| 105 |
1 |
demarshal(<<"u">>) -> dont_bump_lru; |
| 106 |
26 |
demarshal(<<"v">>) -> value. |
| 107 |
|
|
| 108 |
|
|
| 109 |
70 |
demarshal(Flag, Token) -> {Flag, binary_to_integer(Token)}. |
| 110 |
|
|
| 111 |
|
|
| 112 |
2 |
marshal(base64) -> "b"; |
| 113 |
7 |
marshal(cas) -> "c"; |
| 114 |
1 |
marshal(dont_bump_lru) -> "u"; |
| 115 |
2 |
marshal(flags) -> "f"; |
| 116 |
1 |
marshal(hit) -> "h"; |
| 117 |
2 |
marshal(invalidate) -> "I"; |
| 118 |
1 |
marshal(key) -> "k"; |
| 119 |
1 |
marshal(last_accessed) -> "l"; |
| 120 |
2 |
marshal(noreply) -> "q"; |
| 121 |
11 |
marshal(size) -> "s"; |
| 122 |
11 |
marshal(ttl) -> "t"; |
| 123 |
23 |
marshal(value) -> "v"; |
| 124 |
6 |
marshal({cas, Token}) -> ?FUNCTION_NAME("c", Token); |
| 125 |
7 |
marshal({cas_expected, Token}) -> ?FUNCTION_NAME("C", Token); |
| 126 |
4 |
marshal({delta, Token}) -> ?FUNCTION_NAME("D", Token); |
| 127 |
2 |
marshal({flags, Token}) -> ?FUNCTION_NAME("F", Token); |
| 128 |
5 |
marshal({hit, Token}) -> ?FUNCTION_NAME("h", Token); |
| 129 |
5 |
marshal({initial, Token}) -> ?FUNCTION_NAME("J", Token); |
| 130 |
2 |
marshal({key, Token}) -> ["k", Token]; |
| 131 |
3 |
marshal({last_accessed, Token}) -> ?FUNCTION_NAME("l", Token); |
| 132 |
11 |
marshal({mode, Token}) -> ["M", Token]; |
| 133 |
4 |
marshal({opaque, Token}) -> ["O", Token]; |
| 134 |
1 |
marshal({remaining, Token}) -> ?FUNCTION_NAME("R", Token); |
| 135 |
10 |
marshal({size, Token}) -> ?FUNCTION_NAME("s", Token); |
| 136 |
16 |
marshal({set_ttl, Token}) -> ?FUNCTION_NAME("T", Token); |
| 137 |
7 |
marshal({ttl, Token}) -> ?FUNCTION_NAME("t", Token); |
| 138 |
10 |
marshal({vivify, Token}) -> ?FUNCTION_NAME("N", Token). |
| 139 |
|
|
| 140 |
|
|
| 141 |
76 |
marshal(Flag, Token) -> [Flag, integer_to_binary(Token)]. |
| 142 |
|
|
| 143 |
|
|
| 144 |
|
as_map(Meta, Flags) -> |
| 145 |
48 |
maps:merge( |
| 146 |
|
defaults(Meta), |
| 147 |
|
lists:foldl( |
| 148 |
|
fold(Meta), |
| 149 |
|
#{}, |
| 150 |
|
Flags)). |
| 151 |
|
|
| 152 |
|
|
| 153 |
|
defaults(set) -> |
| 154 |
19 |
#{mode => set}; |
| 155 |
|
|
| 156 |
|
defaults(arithmetic) -> |
| 157 |
16 |
#{initial => 0, delta => 1, mode => increment}; |
| 158 |
|
|
| 159 |
|
defaults(_) -> |
| 160 |
13 |
#{}. |
| 161 |
|
|
| 162 |
|
|
| 163 |
|
fold(set) -> |
| 164 |
19 |
fun |
| 165 |
|
({mode = K, <<"E">>}, A) -> |
| 166 |
1 |
A#{K => add}; |
| 167 |
|
|
| 168 |
|
({mode = K, <<"A">>}, A) -> |
| 169 |
1 |
A#{K => append}; |
| 170 |
|
|
| 171 |
|
({mode = K, <<"P">>}, A) -> |
| 172 |
1 |
A#{K => prepend}; |
| 173 |
|
|
| 174 |
|
({mode = K, <<"R">>}, A) -> |
| 175 |
2 |
A#{K => replace}; |
| 176 |
|
|
| 177 |
|
({mode = K, <<"S">>}, A) -> |
| 178 |
1 |
A#{K => set}; |
| 179 |
|
|
| 180 |
|
({mode, _} = Arg, _) -> |
| 181 |
1 |
error(badarg, [Arg]); |
| 182 |
|
|
| 183 |
|
({K, V}, A) -> |
| 184 |
13 |
A#{K => V}; |
| 185 |
|
|
| 186 |
|
(K, A) -> |
| 187 |
2 |
A#{K => true} |
| 188 |
|
end; |
| 189 |
|
|
| 190 |
|
fold(arithmetic) -> |
| 191 |
16 |
fun |
| 192 |
|
({mode = K, V}, A) when V == <<"I">>; V == <<"+">> -> |
| 193 |
:-( |
A#{K => increment}; |
| 194 |
|
|
| 195 |
|
({mode = K, V}, A) when V == <<"D">>; V == <<"-">> -> |
| 196 |
2 |
A#{K => decrement}; |
| 197 |
|
|
| 198 |
|
({K, V}, A) -> |
| 199 |
21 |
A#{K => V}; |
| 200 |
|
|
| 201 |
|
(K, A) -> |
| 202 |
19 |
A#{K => true} |
| 203 |
|
end; |
| 204 |
|
|
| 205 |
|
fold(_) -> |
| 206 |
13 |
fun |
| 207 |
|
({K, V}, A) -> |
| 208 |
4 |
A#{K => V}; |
| 209 |
|
|
| 210 |
|
(K, A) -> |
| 211 |
21 |
A#{K => true} |
| 212 |
|
end. |