_site/cover/msmp_field_optional_metadata.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(msmp_field_optional_metadata).
17
18
19 -feature(maybe_expr, enable).
20
21
22 -export([decode/1]).
23 -export_type([metadata/0]).
24 -export_type([tag/0]).
25 -import(scran_bits, [into_boolean/0]).
26 -import(scran_bytes, [take/1]).
27 -import(scran_combinator, [map_parser/2]).
28 -import(scran_combinator, [map_result/2]).
29 -import(scran_combinator, [rest/0]).
30 -import(scran_multi, [count/2]).
31 -import(scran_multi, [many1/1]).
32 -import(scran_result, [into_map/1]).
33 -import(scran_result, [kv/2]).
34 -import(scran_sequence, [followed_with/2]).
35 -import(scran_sequence, [terminated/2]).
36 -include_lib("kernel/include/logger.hrl").
37 -on_load(on_load/0).
38
39
40 -type tag() :: unsignedness
41 | simple_primary_key
42 | column_charset
43 | geometry_type
44 | emum_and_set_column_charset
45 | default_charset
46 | column_name.
47
48 -type metadata() :: #{unsignedness => #{non_neg_integer() := boolean()},
49 default_charset => [non_neg_integer()],
50 column_name => [binary()],
51 simple_primary_key => [non_neg_integer()],
52 column_visibility => binary()}.
53
54 -spec decode([msmp_field:type()]) -> scran:parser(binary(), metadata()).
55
56 decode(ColTypes) ->
57 7 fun
58 (Input) ->
59 7 ?LOG_DEBUG(#{col_types => ColTypes, input => Input}),
60 7 (into_map(many1(tlv(ColTypes))))(Input)
61 end.
62
63
64 tlv(ColTypes) ->
65 7 fun
66 (Input) ->
67 32 ?LOG_DEBUG(#{col_types => ColTypes, input => Input}),
68
69 32 (followed_with(
70 map_result(
71 msmp_integer_fixed:decode(1),
72 fun lookup/1),
73 fun
74 (Tag) ->
75 25 map_parser(
76 take(msmp_integer_variable:decode()),
77 kv(Tag, value(Tag, ColTypes)))
78 end))(Input)
79 end.
80
81
82 value(unsignedness = Tag, ColTypes) ->
83 7 NumericColPositions = numeric_col_positions(ColTypes),
84
85 7 fun
86 (Input) ->
87 7 ?LOG_DEBUG(#{col_types => ColTypes,
88 tag => Tag,
89 numeric_col_positions => NumericColPositions,
90 7 input => Input}),
91
92 7 (into_map(
93 map_result(
94 terminated(
95 count(length(NumericColPositions), into_boolean()),
96 scran_bits:tag(padding(length(NumericColPositions)))),
97 fun
98 (Flags) ->
99 7 ?LOG_DEBUG(#{flags => Flags,
100 7 numeric_col_positions => NumericColPositions}),
101
102 7 lists:zip(NumericColPositions, Flags)
103 end)))(Input)
104 end;
105
106 value(Tag, ColTypes)
107 when Tag == simple_primary_key;
108 Tag == column_charset;
109 Tag == geometry_type;
110 Tag == emum_and_set_column_charset;
111 Tag == default_charset ->
112 8 fun
113 (Input) ->
114 8 ?LOG_DEBUG(#{tag => Tag,
115 col_types => ColTypes,
116 8 input => Input}),
117 8 (many1(msmp_integer_variable:decode()))(Input)
118 end;
119
120 value(column_name = Tag, ColTypes) ->
121 4 fun
122 (Input) ->
123 4 ?LOG_DEBUG(#{tag => Tag,
124 col_types => ColTypes,
125 4 input => Input}),
126 4 (many1(msmp_string_length_encoded:decode()))(Input)
127 end;
128
129 value(enum_str_value = Tag, ColTypes) ->
130 2 fun
131 (Input) ->
132 2 ?LOG_DEBUG(#{tag => Tag,
133 col_types => ColTypes,
134 2 input => Input}),
135 2 (many1(
136 count(
137 msmp_integer_variable:decode(),
138 msmp_string_length_encoded:decode())))(Input)
139 end;
140
141 value(Tag, ColTypes) ->
142 %% TODO remove this catch all for unhandled tlv
143 4 fun
144 (Input) ->
145 4 ?LOG_DEBUG(#{col_types => ColTypes,
146 tag => Tag,
147 4 input => Input}),
148
149 4 (rest())(Input)
150 end.
151
152
153 padding(N) when N rem 8 == 0 ->
154
:-(
<<>>;
155
156 padding(N) ->
157 7 <<0:(8 - N rem 8)>>.
158
159
160 numeric_col_positions(ColTypes) ->
161 7 lists:filtermap(
162 fun
163 ({Position, Type}) ->
164 29 case msmp_field:is_numeric_type(Type) of
165 true ->
166 13 {true, Position};
167
168 false ->
169 16 false
170 end
171 end,
172 pos_col_type(ColTypes)).
173
174
175 pos_col_type(ColTypes) ->
176 7 lists:zip(lists:seq(1, length(ColTypes)), ColTypes).
177
178
179 on_load() ->
180 1 persistent_term:put(
181 ?MODULE,
182 msmp_enum:priv_consult("optional-metadata-field-type.terms")).
183
184
185 lookup(FieldType) ->
186 25 maps:get(FieldType, types()).
187
188
189 types() ->
190 25 persistent_term:get(?MODULE).
Line Hits Source