WIP add 'items', fix some layout issues
This commit is contained in:
parent
bff07885fb
commit
6563ef9de7
@ -87,7 +87,8 @@ decode_tag_and_vsn([TagBin, VsnBin | Fields]) ->
|
|||||||
dynamic_types() ->
|
dynamic_types() ->
|
||||||
#{ vsn => ?VSN
|
#{ vsn => ?VSN
|
||||||
, codes =>
|
, codes =>
|
||||||
#{ 248 => int
|
#{ 247 => negint
|
||||||
|
, 248 => int
|
||||||
, 249 => binary
|
, 249 => binary
|
||||||
, 250 => bool
|
, 250 => bool
|
||||||
, 251 => list
|
, 251 => list
|
||||||
@ -96,7 +97,8 @@ dynamic_types() ->
|
|||||||
, 254 => id
|
, 254 => id
|
||||||
, 255 => label}
|
, 255 => label}
|
||||||
, rev =>
|
, rev =>
|
||||||
#{ int => 248
|
#{ negint => 247
|
||||||
|
, int => 248
|
||||||
, binary => 249
|
, binary => 249
|
||||||
, bool => 250
|
, bool => 250
|
||||||
, list => 251
|
, list => 251
|
||||||
@ -107,7 +109,8 @@ dynamic_types() ->
|
|||||||
, labels => #{}
|
, labels => #{}
|
||||||
, rev_labels => #{}
|
, rev_labels => #{}
|
||||||
, templates =>
|
, templates =>
|
||||||
#{ int => int
|
#{ negint => negint
|
||||||
|
, int => int
|
||||||
, binary => binary
|
, binary => binary
|
||||||
, bool => bool
|
, bool => bool
|
||||||
, list => list
|
, list => list
|
||||||
@ -175,27 +178,37 @@ encode_(Term, Vsn, Types) ->
|
|||||||
|
|
||||||
encode_(Term, Emit, Vsn, Types) ->
|
encode_(Term, Emit, Vsn, Types) ->
|
||||||
{Tag, Template} = auto_template(Term),
|
{Tag, Template} = auto_template(Term),
|
||||||
Enc = encode_from_template(Template, Term, Vsn, Types),
|
|
||||||
if Emit ->
|
if Emit ->
|
||||||
[emit_code(Tag, Types), Enc];
|
[emit_code(Tag, Types),
|
||||||
|
encode_from_template(Template, Term, false, true, Vsn, Types)];
|
||||||
true ->
|
true ->
|
||||||
Enc
|
encode_from_template(Template, Term, false, true, Vsn, Types)
|
||||||
|
end.
|
||||||
|
%% if Emit ->
|
||||||
|
%% [emit_code(Tag, Types), Enc];
|
||||||
|
%% true ->
|
||||||
|
%% Enc
|
||||||
|
%% end.
|
||||||
|
|
||||||
|
encode_typed_(Type, Term, Vsn, #{codes := Codes, rev := Rev} = Types) ->
|
||||||
|
case (is_map_key(Type, Codes) orelse is_map_key(Type, Rev)) of
|
||||||
|
true ->
|
||||||
|
encode_typed_(Type, Term, true, true, Vsn, Types);
|
||||||
|
false ->
|
||||||
|
encode_maybe_template(Type, Term, Vsn, Types)
|
||||||
end.
|
end.
|
||||||
|
|
||||||
encode_typed_(Type, Term, Vsn, Types) ->
|
encode_typed_(any, Term, _, _, Vsn, Types) ->
|
||||||
encode_typed_(Type, Term, true, Vsn, Types).
|
|
||||||
|
|
||||||
encode_typed_(any, Term, _, Vsn, Types) ->
|
|
||||||
encode_(Term, true, Vsn, Types);
|
encode_(Term, true, Vsn, Types);
|
||||||
encode_typed_(Code, Term, Emit, Vsn, #{codes := Codes} = Types) when is_map_key(Code, Codes) ->
|
encode_typed_(Code, Term, Emit, IsDyn, Vsn, #{codes := Codes} = Types) when is_map_key(Code, Codes) ->
|
||||||
{_Tag, Template} = template(Code, Vsn, Types),
|
{_Tag, Template} = template(Code, Vsn, Types),
|
||||||
maybe_emit(Emit, Code, encode_from_template(Template, Term, false, Vsn, Types));
|
maybe_emit(Emit, Code, encode_from_template(Template, Term, false, IsDyn, Vsn, Types));
|
||||||
encode_typed_(Tag, Term, Emit, Vsn, #{templates := Ts, rev := Rev} = Types)
|
encode_typed_(Tag, Term, Emit, IsDyn, Vsn, #{templates := Ts, rev := Rev} = Types)
|
||||||
when is_map_key(Tag, Ts) ->
|
when is_map_key(Tag, Ts) ->
|
||||||
Template = dyn_template_(maps:get(Tag, Ts), Vsn),
|
Template = dyn_template_(maps:get(Tag, Ts), Vsn),
|
||||||
Code = maps:get(Tag, Rev),
|
Code = maps:get(Tag, Rev),
|
||||||
maybe_emit(Emit, Code, encode_from_template(Template, Term, false, Vsn, Types));
|
maybe_emit(Emit, Code, encode_from_template(Template, Term, false, IsDyn, Vsn, Types));
|
||||||
encode_typed_(MaybeTemplate, Term, _, Vsn, Types) ->
|
encode_typed_(MaybeTemplate, Term, _, _, Vsn, Types) ->
|
||||||
encode_maybe_template(MaybeTemplate, Term, Vsn, Types).
|
encode_maybe_template(MaybeTemplate, Term, Vsn, Types).
|
||||||
|
|
||||||
maybe_emit(true, Code, Enc) ->
|
maybe_emit(true, Code, Enc) ->
|
||||||
@ -203,12 +216,18 @@ maybe_emit(true, Code, Enc) ->
|
|||||||
maybe_emit(false, _, Enc) ->
|
maybe_emit(false, _, Enc) ->
|
||||||
Enc.
|
Enc.
|
||||||
|
|
||||||
|
encode_maybe_template(#{items := _} = Type, Term, Vsn, Types) ->
|
||||||
|
case is_map(Term) of
|
||||||
|
true ->
|
||||||
|
[emit_code(map, Types), encode_from_template(Type, Term, true, true, Vsn, Types)];
|
||||||
|
false ->
|
||||||
|
error({invalid, Type, Term})
|
||||||
|
end;
|
||||||
encode_maybe_template(Pat, Term, Vsn, Types) when is_list(Pat);
|
encode_maybe_template(Pat, Term, Vsn, Types) when is_list(Pat);
|
||||||
is_tuple(Pat);
|
is_tuple(Pat) ->
|
||||||
is_map(Pat) ->
|
|
||||||
{Tag, _} = auto_template(Pat),
|
{Tag, _} = auto_template(Pat),
|
||||||
[emit_code(Tag, Types),
|
[emit_code(Tag, Types),
|
||||||
encode_from_template(Pat, Term, true, Vsn, Types)];
|
encode_from_template(Pat, Term, true, true, Vsn, Types)];
|
||||||
encode_maybe_template(Other, Term, _Vsn, _Types) ->
|
encode_maybe_template(Other, Term, _Vsn, _Types) ->
|
||||||
error({illegal_template, Other, Term}).
|
error({illegal_template, Other, Term}).
|
||||||
|
|
||||||
@ -233,10 +252,19 @@ auto_template(T) ->
|
|||||||
is_atom(T) -> {label, label}; % binary_to_existing_atom()
|
is_atom(T) -> {label, label}; % binary_to_existing_atom()
|
||||||
is_integer(T),
|
is_integer(T),
|
||||||
T >= 0 -> {int, int};
|
T >= 0 -> {int, int};
|
||||||
|
is_integer(T),
|
||||||
|
T < 0 -> {negint, negint};
|
||||||
true ->
|
true ->
|
||||||
error(invalid_type)
|
error({invalid_type, T})
|
||||||
end.
|
end.
|
||||||
|
|
||||||
|
decode_from_template(#{items := Items}, Fld, Vsn, Types) when is_list(Fld) ->
|
||||||
|
Zipped = lists:zip(Items, Fld),
|
||||||
|
lists:foldl(
|
||||||
|
fun({{K, Type}, V}, Map) ->
|
||||||
|
maps:is_key(K, Map) andalso error(badarg, duplicate_field),
|
||||||
|
Map#{K => decode_from_template(Type, V, Vsn, Types)}
|
||||||
|
end, #{}, Zipped);
|
||||||
decode_from_template(list, Fld, Vsn, Types) ->
|
decode_from_template(list, Fld, Vsn, Types) ->
|
||||||
decode_(Fld, Vsn, Types, []);
|
decode_(Fld, Vsn, Types, []);
|
||||||
decode_from_template(map, Fld, Vsn, Types) ->
|
decode_from_template(map, Fld, Vsn, Types) ->
|
||||||
@ -245,7 +273,8 @@ decode_from_template(map, Fld, Vsn, Types) ->
|
|||||||
|| T <- TupleFields],
|
|| T <- TupleFields],
|
||||||
maps:from_list(Items);
|
maps:from_list(Items);
|
||||||
decode_from_template(tuple, Fld, Vsn, Types) ->
|
decode_from_template(tuple, Fld, Vsn, Types) ->
|
||||||
Items = decode_(Fld, Vsn, Types, []),
|
Items = [decode_field_(F, Vsn, Types) || F <- Fld],
|
||||||
|
%% Items = decode_(Fld, Vsn, Types, []),
|
||||||
list_to_tuple(Items);
|
list_to_tuple(Items);
|
||||||
decode_from_template([Type], Fields, Vsn, Types) ->
|
decode_from_template([Type], Fields, Vsn, Types) ->
|
||||||
[decode_from_template(Type, F, Vsn, Types)
|
[decode_from_template(Type, F, Vsn, Types)
|
||||||
@ -260,6 +289,7 @@ decode_from_template(label, [C], _, #{rev_labels := RLbls}) ->
|
|||||||
Code = decode_basic(int, C),
|
Code = decode_basic(int, C),
|
||||||
maps:get(Code, RLbls);
|
maps:get(Code, RLbls);
|
||||||
decode_from_template(Type, Fld, _, Types) when Type == int
|
decode_from_template(Type, Fld, _, Types) when Type == int
|
||||||
|
; Type == negint
|
||||||
; Type == binary
|
; Type == binary
|
||||||
; Type == bool
|
; Type == bool
|
||||||
; Type == id
|
; Type == id
|
||||||
@ -267,31 +297,38 @@ decode_from_template(Type, Fld, _, Types) when Type == int
|
|||||||
decode_basic(Type, Fld, Types).
|
decode_basic(Type, Fld, Types).
|
||||||
|
|
||||||
encode_from_template(Type, V, Vsn, Types) ->
|
encode_from_template(Type, V, Vsn, Types) ->
|
||||||
encode_from_template(Type, V, true, Vsn, Types).
|
encode_from_template(Type, V, true, true, Vsn, Types).
|
||||||
|
|
||||||
encode_from_template(any, V, _, Vsn, Types) ->
|
encode_from_template(any, V, _Emit, _IsDyn, Vsn, Types) ->
|
||||||
encode_(V, true, Vsn, Types);
|
encode_(V, true, Vsn, Types);
|
||||||
encode_from_template(list, L, _, Vsn, Types) when is_list(L) ->
|
encode_from_template(list, L, _, _IsDyn, Vsn, Types) when is_list(L) ->
|
||||||
assert_type(is_list(L), list, L),
|
assert_type(is_list(L), list, L),
|
||||||
[encode_(V, Vsn, Types) || V <- L];
|
[encode_(V, Vsn, Types) || V <- L];
|
||||||
encode_from_template(map, M, _, Vsn, Types) ->
|
encode_from_template(#{items := Items}, M, _, IsDyn, Vsn, Types) ->
|
||||||
assert_type(is_map(M), map, M),
|
assert_type(is_map(M), map, M),
|
||||||
[encode_({K,V}, false, Vsn, Types)
|
lists:map(
|
||||||
|
fun({K, Type}) ->
|
||||||
|
V = maps:get(K, M),
|
||||||
|
encode_from_template({any,Type}, {K,V}, true, IsDyn, Vsn, Types)
|
||||||
|
end, Items);
|
||||||
|
encode_from_template(map, M, _, IsDyn, Vsn, Types) ->
|
||||||
|
assert_type(is_map(M), map, M),
|
||||||
|
[encode_from_template({any,any}, {K,V}, false, IsDyn, Vsn, Types)
|
||||||
|| {K, V} <- lists:sort(maps:to_list(M))];
|
|| {K, V} <- lists:sort(maps:to_list(M))];
|
||||||
encode_from_template(tuple, T, Emit, Vsn, Types) ->
|
encode_from_template(tuple, T, Emit, _IsDyn, Vsn, Types) ->
|
||||||
assert_type(is_tuple(T), tuple, T),
|
assert_type(is_tuple(T), tuple, T),
|
||||||
[encode_(V, Emit, Vsn, Types) || V <- tuple_to_list(T)];
|
[encode_(V, true, Vsn, Types) || V <- tuple_to_list(T)];
|
||||||
encode_from_template(T, V, Emit, Vsn, Types) when is_tuple(T) ->
|
encode_from_template(T, V, Emit, IsDyn, Vsn, Types) when is_tuple(T) ->
|
||||||
assert_type(is_tuple(V), T, V),
|
assert_type(is_tuple(V), T, V),
|
||||||
assert_type(tuple_size(T) =:= tuple_size(V), T, V),
|
assert_type(tuple_size(T) =:= tuple_size(V), T, V),
|
||||||
Zipped = lists:zip(tuple_to_list(T), tuple_to_list(V)),
|
Zipped = lists:zip(tuple_to_list(T), tuple_to_list(V)),
|
||||||
[encode_from_template(T1, V1, Emit, Vsn, Types) || {T1, V1} <- Zipped];
|
[encode_from_template(T1, V1, Emit, IsDyn, Vsn, Types) || {T1, V1} <- Zipped];
|
||||||
encode_from_template([Type] = T, List, Emit, Vsn, Types) ->
|
encode_from_template([Type] = T, List, Emit, IsDyn, Vsn, Types) ->
|
||||||
assert_type(is_list(List), T, List),
|
assert_type(is_list(List), T, List),
|
||||||
[encode_from_template(Type, V, Emit, Vsn, Types) || V <- List];
|
[encode_from_template(Type, V, Emit, IsDyn, Vsn, Types) || V <- List];
|
||||||
encode_from_template(Type, List, Emit, Vsn, Types) when is_list(Type), is_list(List) ->
|
encode_from_template(Type, List, Emit, IsDyn, Vsn, Types) when is_list(Type), is_list(List) ->
|
||||||
encode_fields(Type, List, Emit, Vsn, Types);
|
encode_fields(Type, List, Emit, IsDyn, Vsn, Types);
|
||||||
encode_from_template(label, V, Emit, _, Types) ->
|
encode_from_template(label, V, Emit, _, _, Types) ->
|
||||||
assert_type(is_atom(V), label, V),
|
assert_type(is_atom(V), label, V),
|
||||||
case find_cached_label(V, Types) of
|
case find_cached_label(V, Types) of
|
||||||
error ->
|
error ->
|
||||||
@ -299,14 +336,15 @@ encode_from_template(label, V, Emit, _, Types) ->
|
|||||||
{ok, Code} when is_integer(Code) ->
|
{ok, Code} when is_integer(Code) ->
|
||||||
[encode_basic(int, Code)]
|
[encode_basic(int, Code)]
|
||||||
end;
|
end;
|
||||||
encode_from_template(Type, V, Emit, _, Types) when Type == id
|
encode_from_template(Type, V, Emit, _, _, Types) when Type == id
|
||||||
; Type == binary
|
; Type == binary
|
||||||
; Type == bool
|
; Type == bool
|
||||||
; Type == int
|
; Type == int
|
||||||
|
; Type == negint
|
||||||
; Type == label ->
|
; Type == label ->
|
||||||
encode_basic(Type, V, Emit, Types);
|
encode_basic(Type, V, Emit, Types);
|
||||||
encode_from_template(Type, V, Emit, Vsn, Types) ->
|
encode_from_template(Type, V, Emit, IsDyn, Vsn, Types) ->
|
||||||
encode_typed_(Type, V, Emit, Vsn, Types).
|
encode_typed_(Type, V, Emit, IsDyn, Vsn, Types).
|
||||||
%% error({illegal, Type, V}).
|
%% error({illegal, Type, V}).
|
||||||
|
|
||||||
assert_type(true, _, _) -> ok;
|
assert_type(true, _, _) -> ok;
|
||||||
@ -315,18 +353,18 @@ assert_type(_, Type, V) -> error({illegal, Type, V}).
|
|||||||
|
|
||||||
%% Basically, dynamically encoding a statically defined object
|
%% Basically, dynamically encoding a statically defined object
|
||||||
encode_fields([{Field, Type}|TypesLeft],
|
encode_fields([{Field, Type}|TypesLeft],
|
||||||
[{Field, Val}|FieldsLeft], Emit, Vsn, Types) ->
|
[{Field, Val}|FieldsLeft], Emit, IsDyn, Vsn, Types) ->
|
||||||
[ encode_from_template(Type, Val, Emit, Vsn, Types)
|
[ encode_from_template(Type, Val, Emit, IsDyn, Vsn, Types)
|
||||||
| encode_fields(TypesLeft, FieldsLeft, Emit, Vsn, Types)];
|
| encode_fields(TypesLeft, FieldsLeft, Emit, IsDyn, Vsn, Types)];
|
||||||
encode_fields([{_Field, _Type} = FT|_TypesLeft],
|
encode_fields([{_Field, _Type} = FT|_TypesLeft],
|
||||||
[Val |_FieldsLeft], _Emit, _Vsn, _Types) ->
|
[Val |_FieldsLeft], _Emit, _IsDyn, _Vsn, _Types) ->
|
||||||
error({illegal_field, FT, Val});
|
error({illegal_field, FT, Val});
|
||||||
encode_fields([Type|TypesLeft],
|
encode_fields([Type|TypesLeft],
|
||||||
[Val |FieldsLeft], Emit, Vsn, Types) when is_atom(Type) ->
|
[Val |FieldsLeft], Emit, IsDyn, Vsn, Types) when is_atom(Type) ->
|
||||||
%% Not sure about this ...
|
%% Not sure about this ...
|
||||||
[ encode_from_template(Type, Val, Emit, Vsn, Types)
|
[ encode_from_template(Type, Val, Emit, IsDyn, Vsn, Types)
|
||||||
| encode_fields(TypesLeft, FieldsLeft, Emit, Vsn, Types)];
|
| encode_fields(TypesLeft, FieldsLeft, Emit, IsDyn, Vsn, Types)];
|
||||||
encode_fields([], [], _, _, _) ->
|
encode_fields([], [], _, _, _, _) ->
|
||||||
[].
|
[].
|
||||||
|
|
||||||
decode_fields([{Tag, Type}|TypesLeft],
|
decode_fields([{Tag, Type}|TypesLeft],
|
||||||
@ -352,9 +390,14 @@ decode_basic(Type, V, _) ->
|
|||||||
|
|
||||||
decode_basic(label, Fld) ->
|
decode_basic(label, Fld) ->
|
||||||
binary_to_existing_atom(decode_basic(binary, Fld), utf8);
|
binary_to_existing_atom(decode_basic(binary, Fld), utf8);
|
||||||
|
decode_basic(negint, Fld) ->
|
||||||
|
I = gmserialization:decode_field(int, Fld),
|
||||||
|
-I;
|
||||||
decode_basic(Type, Fld) ->
|
decode_basic(Type, Fld) ->
|
||||||
gmserialization:decode_field(Type, Fld).
|
gmserialization:decode_field(Type, Fld).
|
||||||
|
|
||||||
|
encode_basic(negint, I, _, Types) when is_integer(I), I < 0 ->
|
||||||
|
[emit_code(negint, Types), gmserialization:encode_field(int, -I)];
|
||||||
encode_basic(Tag, V, true, Types) ->
|
encode_basic(Tag, V, true, Types) ->
|
||||||
[emit_code(Tag, Types), encode_basic(Tag, V)];
|
[emit_code(Tag, Types), encode_basic(Tag, V)];
|
||||||
encode_basic(Tag, V, false, _) ->
|
encode_basic(Tag, V, false, _) ->
|
||||||
@ -536,6 +579,7 @@ round_trip_test_() ->
|
|||||||
|
|
||||||
t_sample_types() ->
|
t_sample_types() ->
|
||||||
[ 5
|
[ 5
|
||||||
|
, -5
|
||||||
, <<"a">>
|
, <<"a">>
|
||||||
, [1,2,3]
|
, [1,2,3]
|
||||||
, {<<"a">>,1}
|
, {<<"a">>,1}
|
||||||
@ -560,6 +604,11 @@ user_types_test_() ->
|
|||||||
, ?_test(t_reg_label_cache2())
|
, ?_test(t_reg_label_cache2())
|
||||||
]}.
|
]}.
|
||||||
|
|
||||||
|
dynamic_types_test_() ->
|
||||||
|
[ ?_test(revert_to_default_types())
|
||||||
|
, ?_test(typed_map())
|
||||||
|
].
|
||||||
|
|
||||||
t_round_trip(T) ->
|
t_round_trip(T) ->
|
||||||
?debugVal(T),
|
?debugVal(T),
|
||||||
?assertMatch({T, T}, {T, decode(encode(T))}).
|
?assertMatch({T, T}, {T, decode(encode(T))}).
|
||||||
@ -645,7 +694,11 @@ t_reg_label_cache2() ->
|
|||||||
Tup = {'1', '1'},
|
Tup = {'1', '1'},
|
||||||
Enc = gmser_dyn:encode_typed(lbl_tup2, Tup),
|
Enc = gmser_dyn:encode_typed(lbl_tup2, Tup),
|
||||||
[<<0>>,<<1>>,[<<3,235>>,[[<<49>>],[<<49>>]]]] = Enc,
|
[<<0>>,<<1>>,[<<3,235>>,[[<<49>>],[<<49>>]]]] = Enc,
|
||||||
Tup = gmser_dyn:decode(Enc).
|
_Tup = gmser_dyn:decode(Enc).
|
||||||
|
|
||||||
|
typed_map() ->
|
||||||
|
Term = #{a => 13, {key,1} => [a]},
|
||||||
|
Enc = encode_typed(#{items => [{a,int},{{key,1},[label]}]}, Term),
|
||||||
|
?assertEqual(Term, decode(Enc)).
|
||||||
|
|
||||||
-endif.
|
-endif.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user