Compare commits
13 Commits
4663a0f57e
..
runner
| Author | SHA1 | Date | |
|---|---|---|---|
| 3b4acaac6e | |||
| c2ccd39c39 | |||
| 1229471ce0 | |||
| fc5c9f2d3d | |||
| 67fc399b31 | |||
| ed8c08bf62 | |||
| 3421d3dca3 | |||
| 0e5ac7f68f | |||
| c5a968cca3 | |||
| dc460ddd75 | |||
| 23856166fd | |||
| 82f10b76c5 | |||
| cd6f7b5751 |
@@ -1,11 +1,24 @@
|
|||||||
{application,gmserialization,
|
{application,gmserialization,
|
||||||
[{description,"Serialization of data for the Gajumaru"},
|
[{description,"Serialization helpers for the Gajumaru."},
|
||||||
{vsn,"0.1.2"},
|
{vsn,"0.1.2"},
|
||||||
{registered,[]},
|
{registered,[]},
|
||||||
{applications,[kernel,stdlib,crypto,base58]},
|
{applications,[kernel,stdlib,crypto,base58]},
|
||||||
{env,[]},
|
{env,[]},
|
||||||
{modules,[gmser_api_encoder,gmser_chain_objects,
|
{modules,[base58,timing,enacl_eqc,enacl_ext_eqc,enacl,enacl_ext,
|
||||||
|
enacl_nif,enacl_SUITE,pc,pc_compilation,pc_port_env,
|
||||||
|
pc_port_specs,pc_prv_clean,pc_prv_compile,pc_util,
|
||||||
|
base58,timing,enacl_eqc,enacl_ext_eqc,enacl,enacl_ext,
|
||||||
|
enacl_nif,enacl_SUITE,gmser_api_encoder,
|
||||||
|
gmser_chain_objects,gmser_contract_code,
|
||||||
|
gmser_delegation,gmser_id,gmser_rlp,gmserialization,
|
||||||
|
gmser_api_encoder_tests,gmser_chain_objects_tests,
|
||||||
|
gmser_contract_code_tests,gmser_delegation_tests,
|
||||||
|
gmser_rlp_tests,pc,pc_compilation,pc_port_env,
|
||||||
|
pc_port_specs,pc_prv_clean,pc_prv_compile,pc_util,
|
||||||
|
gmser_api_encoder,gmser_chain_objects,
|
||||||
gmser_contract_code,gmser_delegation,gmser_id,
|
gmser_contract_code,gmser_delegation,gmser_id,
|
||||||
gmser_rlp,gmserialization]},
|
gmser_rlp,gmserialization,gmser_api_encoder_tests,
|
||||||
|
gmser_chain_objects_tests,gmser_contract_code_tests,
|
||||||
|
gmser_delegation_tests,gmser_rlp_tests]},
|
||||||
{licenses,[]},
|
{licenses,[]},
|
||||||
{links,[]}]}.
|
{links,[]}]}.
|
||||||
|
|||||||
+1
-4
@@ -4,7 +4,4 @@
|
|||||||
{git,
|
{git,
|
||||||
"https://git.qpq.swiss/QPQ-AG/erl-base58.git",
|
"https://git.qpq.swiss/QPQ-AG/erl-base58.git",
|
||||||
{ref, "e6aa62eeae3d4388311401f06e4b939bf4e94b9c"}}},
|
{ref, "e6aa62eeae3d4388311401f06e4b939bf4e94b9c"}}},
|
||||||
{enacl,
|
{eblake2, "1.0.0"}]}.
|
||||||
{git,
|
|
||||||
"https://git.qpq.swiss/QPQ-AG/enacl.git",
|
|
||||||
{ref, "4eb7ec70084ba7c87b1af8797c4c4e90c84f95a2"}}}]}.
|
|
||||||
|
|||||||
+2
-4
@@ -2,7 +2,5 @@
|
|||||||
{git,"https://git.qpq.swiss/QPQ-AG/erl-base58.git",
|
{git,"https://git.qpq.swiss/QPQ-AG/erl-base58.git",
|
||||||
{ref,"e6aa62eeae3d4388311401f06e4b939bf4e94b9c"}},
|
{ref,"e6aa62eeae3d4388311401f06e4b939bf4e94b9c"}},
|
||||||
0},
|
0},
|
||||||
{<<"enacl">>,
|
{<<"eblake2">>,
|
||||||
{git,"https://git.qpq.swiss/QPQ-AG/enacl.git",
|
{pkg,<<"eblake2">>,<<"1.0.0">>},0}].
|
||||||
{ref,"4eb7ec70084ba7c87b1af8797c4c4e90c84f95a2"}},
|
|
||||||
0}].
|
|
||||||
|
|||||||
@@ -1,443 +0,0 @@
|
|||||||
-module(gmser_dyn).
|
|
||||||
|
|
||||||
-export([ encode/1
|
|
||||||
, encode/2
|
|
||||||
, encode_typed/2
|
|
||||||
, encode_typed/3
|
|
||||||
, decode/1
|
|
||||||
, decode/2 ]).
|
|
||||||
|
|
||||||
-export([ serialize/1
|
|
||||||
, serialize/2
|
|
||||||
, serialize_typed/2
|
|
||||||
, serialize_typed/3
|
|
||||||
, deserialize/1
|
|
||||||
, deserialize/2 ]).
|
|
||||||
|
|
||||||
-export([ register_types/1
|
|
||||||
, registered_types/0
|
|
||||||
, revert_to_default_types/0
|
|
||||||
, dynamic_types/0 ]).
|
|
||||||
|
|
||||||
-import(gmserialization, [ decode_field/2 ]).
|
|
||||||
|
|
||||||
-define(VSN, 1).
|
|
||||||
|
|
||||||
-include_lib("kernel/include/logger.hrl").
|
|
||||||
|
|
||||||
-ifdef(TEST).
|
|
||||||
-compile([export_all, nowarn_export_all]).
|
|
||||||
-include_lib("eunit/include/eunit.hrl").
|
|
||||||
-endif.
|
|
||||||
|
|
||||||
serialize(Term) -> rlp_encode(encode(Term)).
|
|
||||||
serialize(Term, Types) -> rlp_encode(encode(Term, Types)).
|
|
||||||
serialize_typed(Type, Term) -> rlp_encode(encode_typed(Type, Term)).
|
|
||||||
serialize_typed(Type, Term, Types) -> rlp_encode(encode_typed(Type, Term, Types)).
|
|
||||||
|
|
||||||
deserialize(Binary) -> decode(rlp_decode(Binary)).
|
|
||||||
deserialize(Binary, Types) -> decode(rlp_decode(Binary), Types).
|
|
||||||
|
|
||||||
|
|
||||||
encode(Term) ->
|
|
||||||
encode(Term, registered_types()).
|
|
||||||
|
|
||||||
encode(Term, Types) ->
|
|
||||||
encode(Term, vsn(Types), Types).
|
|
||||||
|
|
||||||
encode(Term, Vsn, Types) ->
|
|
||||||
[ encode_basic(int, 0)
|
|
||||||
, encode_basic(int, Vsn)
|
|
||||||
, encode_(Term, Vsn, Types) ].
|
|
||||||
|
|
||||||
encode_typed(Type, Term) ->
|
|
||||||
encode_typed(Type, Term, registered_types()).
|
|
||||||
|
|
||||||
encode_typed(Type, Term, Types) ->
|
|
||||||
encode_typed(Type, Term, vsn(Types), Types).
|
|
||||||
|
|
||||||
encode_typed(Type, Term, Vsn, Types) ->
|
|
||||||
[ encode_basic(int, 0)
|
|
||||||
, encode_basic(int, Vsn)
|
|
||||||
, encode_typed_(Type, Term, Vsn, Types) ].
|
|
||||||
|
|
||||||
decode(Fields) ->
|
|
||||||
decode(Fields, registered_types()).
|
|
||||||
|
|
||||||
decode(Fields0, Types) ->
|
|
||||||
case decode_tag_and_vsn(Fields0) of
|
|
||||||
{0, Vsn, Fields} ->
|
|
||||||
[Val] = decode_(Fields, Vsn, Types, []),
|
|
||||||
Val;
|
|
||||||
Other ->
|
|
||||||
error({illegal_serialization, Other})
|
|
||||||
end.
|
|
||||||
|
|
||||||
decode_tag_and_vsn([TagBin, VsnBin | Fields]) ->
|
|
||||||
{decode_basic(int, TagBin),
|
|
||||||
decode_basic(int, VsnBin),
|
|
||||||
Fields}.
|
|
||||||
|
|
||||||
dynamic_types() ->
|
|
||||||
#{ vsn => ?VSN
|
|
||||||
, codes =>
|
|
||||||
#{ 248 => int
|
|
||||||
, 249 => binary
|
|
||||||
, 250 => bool
|
|
||||||
, 251 => list
|
|
||||||
, 252 => map
|
|
||||||
, 253 => tuple
|
|
||||||
, 254 => id
|
|
||||||
, 255 => label }
|
|
||||||
, rev =>
|
|
||||||
#{ int => 248
|
|
||||||
, binary => 249
|
|
||||||
, bool => 250
|
|
||||||
, list => 251
|
|
||||||
, map => 252
|
|
||||||
, tuple => 253
|
|
||||||
, id => 254
|
|
||||||
, label => 255}
|
|
||||||
, templates =>
|
|
||||||
#{ int => int
|
|
||||||
, binary => binary
|
|
||||||
, bool => bool
|
|
||||||
, list => list
|
|
||||||
, map => map
|
|
||||||
, tuple => tuple
|
|
||||||
, id => id
|
|
||||||
, label => label
|
|
||||||
}
|
|
||||||
}.
|
|
||||||
|
|
||||||
vsn(Types) ->
|
|
||||||
maps:get(vsn, Types, ?VSN).
|
|
||||||
|
|
||||||
register_types(Types) when is_map(Types) ->
|
|
||||||
Codes = maps:get(codes, Types, #{}),
|
|
||||||
Rev = rev_codes(Codes),
|
|
||||||
Templates = maps:get(templates, Types, #{}),
|
|
||||||
#{codes := Codes0, rev := Rev0, templates := Templates0} =
|
|
||||||
dynamic_types(),
|
|
||||||
Merged = #{ codes => maps:merge(Codes0, Codes)
|
|
||||||
, rev => maps:merge(Rev0, Rev)
|
|
||||||
, templates => maps:merge(Templates0, Templates) },
|
|
||||||
assert_sizes(Merged),
|
|
||||||
assert_mappings(Merged),
|
|
||||||
persistent_term:put({?MODULE, types}, Merged).
|
|
||||||
|
|
||||||
revert_to_default_types() ->
|
|
||||||
persistent_term:put({?MODULE, types}, dynamic_types()).
|
|
||||||
|
|
||||||
assert_sizes(#{codes := Codes, rev := Rev, templates := Ts} = Types) ->
|
|
||||||
assert_sizes(map_size(Codes), map_size(Rev), map_size(Ts), Types).
|
|
||||||
|
|
||||||
assert_sizes(Sz, Sz, Sz, _) ->
|
|
||||||
ok;
|
|
||||||
assert_sizes(Sz, RSz, Sz, Types) when RSz =/= Sz ->
|
|
||||||
%% Wrong size reverse mapping must mean duplicate mappings
|
|
||||||
%% We auto-generate the reverse-mappings, so we know there aren't
|
|
||||||
%% too many of them
|
|
||||||
?LOG_ERROR("Reverse mapping size doesn't match codes size", []),
|
|
||||||
Codes = maps:get(codes, Types),
|
|
||||||
CodeVals = maps:values(Codes),
|
|
||||||
Duplicates = CodeVals -- lists:usort(CodeVals),
|
|
||||||
error({duplicate_mappings, Duplicates, Types});
|
|
||||||
assert_sizes(Sz, _, TSz, Types) when Sz > TSz ->
|
|
||||||
?LOG_ERROR("More codes than templates", []),
|
|
||||||
Tags = maps:keys(maps:get(rev, Types)),
|
|
||||||
Templates = maps:get(templates, Types),
|
|
||||||
Missing = [T || T <- Tags,
|
|
||||||
not is_map_key(T, Templates)],
|
|
||||||
error({missing_mappings, Missing, Types});
|
|
||||||
assert_sizes(Sz, _, TSz, Types) when TSz > Sz ->
|
|
||||||
%% More mappings than codes. May not be horrible.
|
|
||||||
%% We check that all codes have mappings elsewhere.
|
|
||||||
?LOG_WARNING("More templates than codes in ~p", [Types]),
|
|
||||||
ok.
|
|
||||||
|
|
||||||
assert_mappings(#{rev := Rev, templates := Ts} = Types) ->
|
|
||||||
Tags = maps:keys(Rev),
|
|
||||||
case [T || T <- Tags,
|
|
||||||
not is_map_key(T, Ts)] of
|
|
||||||
[] ->
|
|
||||||
ok;
|
|
||||||
Missing ->
|
|
||||||
?LOG_ERROR("Missing templates for ~p", [Missing]),
|
|
||||||
error({missing_templates, Missing, Types})
|
|
||||||
end.
|
|
||||||
|
|
||||||
rev_codes(Codes) ->
|
|
||||||
L = maps:to_list(Codes),
|
|
||||||
maps:from_list([{V, K} || {K, V} <- L]).
|
|
||||||
|
|
||||||
registered_types() ->
|
|
||||||
persistent_term:get({?MODULE, types}, dynamic_types()).
|
|
||||||
|
|
||||||
template(TagOrCode, Vsn, Types) ->
|
|
||||||
{Tag, Template} = get_template(TagOrCode, Types),
|
|
||||||
{Tag, dyn_template_(Template, Vsn)}.
|
|
||||||
|
|
||||||
get_template(Code, #{codes := Codes, templates := Ts}) when is_integer(Code) ->
|
|
||||||
Tag = maps:get(Code, Codes),
|
|
||||||
{Tag, maps:get(Tag, Ts)};
|
|
||||||
get_template(Tag, #{templates := Ts}) when is_atom(Tag) ->
|
|
||||||
{Tag, maps:get(Tag, Ts)}.
|
|
||||||
|
|
||||||
dyn_template_(F, Vsn) ->
|
|
||||||
if is_function(F, 0) -> F();
|
|
||||||
is_function(F, 1) -> F(Vsn);
|
|
||||||
true -> F
|
|
||||||
end.
|
|
||||||
|
|
||||||
decode_(Fields, Vsn, Types, Acc) ->
|
|
||||||
{_Tag, Term, Rest} = decode_field_(Fields, Vsn, Types),
|
|
||||||
Acc1 = [Term | Acc],
|
|
||||||
case Rest of
|
|
||||||
[] ->
|
|
||||||
lists:reverse(Acc1);
|
|
||||||
_ ->
|
|
||||||
decode_(Rest, Vsn, Types, Acc1)
|
|
||||||
end.
|
|
||||||
|
|
||||||
decode_field_([H|T], Vsn, Types) ->
|
|
||||||
{CodeBin, Field, Rest} =
|
|
||||||
case H of
|
|
||||||
[C, F] -> {C, F, T};
|
|
||||||
C when is_binary(C) -> {C, hd(T), tl(T)}
|
|
||||||
end,
|
|
||||||
Code = decode_basic(int, CodeBin),
|
|
||||||
{Tag, Template} = template(Code, Vsn, Types),
|
|
||||||
%% [Fld|Rest] = Fields,
|
|
||||||
Val = decode_from_template(Template, Field, Vsn, Types),
|
|
||||||
{Tag, Val, Rest}.
|
|
||||||
|
|
||||||
encode_(Term, Vsn, Types) ->
|
|
||||||
encode_(Term, true, Vsn, Types).
|
|
||||||
|
|
||||||
encode_(Term, Emit, Vsn, Types) ->
|
|
||||||
{Tag, Template} = auto_template(Term),
|
|
||||||
Enc = encode_from_template(Template, Term, Vsn, Types),
|
|
||||||
if Emit ->
|
|
||||||
[emit_code(Tag, Types), Enc];
|
|
||||||
true ->
|
|
||||||
Enc
|
|
||||||
end.
|
|
||||||
|
|
||||||
encode_typed_(Code, Term, Vsn, #{codes := Codes} = Types) when is_map_key(Code, Codes) ->
|
|
||||||
{_Tag, Template} = template(Code, Vsn, Types),
|
|
||||||
[encode_basic(int, Code), encode_from_template(Template, Term, Vsn, Types)];
|
|
||||||
encode_typed_(Tag, Term, Vsn, #{templates := Ts} = Types) when is_map_key(Tag, Ts) ->
|
|
||||||
Template = maps:get(Tag, Ts),
|
|
||||||
[emit_code(Tag, Types), encode_from_template(Template, Term, Vsn, Types)];
|
|
||||||
encode_typed_(MaybeTemplate, Term, Vsn, Types) ->
|
|
||||||
encode_maybe_template(MaybeTemplate, Term, Vsn, Types).
|
|
||||||
|
|
||||||
encode_maybe_template(Pat, Term, Vsn, Types) when is_list(Pat);
|
|
||||||
is_tuple(Pat);
|
|
||||||
is_map(Pat) ->
|
|
||||||
{Tag, _} = auto_template(Pat),
|
|
||||||
[emit_code(Tag, Types),
|
|
||||||
encode_from_template(Pat, Term, Vsn, Types)];
|
|
||||||
encode_maybe_template(Other, Term, _Vsn, _Types) ->
|
|
||||||
error({illegal_template, Other, Term}).
|
|
||||||
|
|
||||||
auto_template({id,Tag,V}) when Tag == account
|
|
||||||
; Tag == name
|
|
||||||
; Tag == commitment
|
|
||||||
; Tag == contract
|
|
||||||
; Tag == channel
|
|
||||||
; Tag == associate_chain
|
|
||||||
; Tag == entry ->
|
|
||||||
if is_binary(V) -> {id, id};
|
|
||||||
true ->
|
|
||||||
%% close, but no cigar
|
|
||||||
{tuple, tuple}
|
|
||||||
end;
|
|
||||||
auto_template(T) ->
|
|
||||||
if is_map(T) -> {map, map};
|
|
||||||
is_list(T) -> {list, list};
|
|
||||||
is_tuple(T) -> {tuple, tuple};
|
|
||||||
is_binary(T) -> {binary, binary};
|
|
||||||
is_boolean(T) -> {bool, bool};
|
|
||||||
is_atom(T) -> {label, label}; % binary_to_existing_atom()
|
|
||||||
is_integer(T),
|
|
||||||
T >= 0 -> {int, int};
|
|
||||||
true ->
|
|
||||||
error(invalid_type)
|
|
||||||
end.
|
|
||||||
|
|
||||||
decode_from_template(list, Fld, Vsn, Types) ->
|
|
||||||
decode_(Fld, Vsn, Types, []);
|
|
||||||
decode_from_template(map, Fld, Vsn, Types) ->
|
|
||||||
TupleFields = [F || F <- Fld],
|
|
||||||
Items = [decode_from_template(tuple, T, Vsn, Types)
|
|
||||||
|| T <- TupleFields],
|
|
||||||
maps:from_list(Items);
|
|
||||||
decode_from_template(tuple, Fld, Vsn, Types) ->
|
|
||||||
Items = decode_(Fld, Vsn, Types, []),
|
|
||||||
list_to_tuple(Items);
|
|
||||||
decode_from_template([Type], Fields, Vsn, Types) ->
|
|
||||||
[decode_from_template(Type, F, Vsn, Types)
|
|
||||||
|| F <- Fields];
|
|
||||||
decode_from_template(Type, V, Vsn, Types) when is_list(Type), is_list(V) ->
|
|
||||||
decode_fields(Type, V, Vsn, Types);
|
|
||||||
decode_from_template(Type, V, Vsn, Types) when is_tuple(Type), is_list(V) ->
|
|
||||||
Zipped = lists:zip(tuple_to_list(Type), V),
|
|
||||||
Items = [decode_from_template(T1, V1, Vsn, Types) || {T1, V1} <- Zipped],
|
|
||||||
list_to_tuple(Items);
|
|
||||||
decode_from_template(Type, Fld, _, _) when Type == int
|
|
||||||
; Type == binary
|
|
||||||
; Type == bool
|
|
||||||
; Type == id
|
|
||||||
; Type == label ->
|
|
||||||
decode_basic(Type, Fld).
|
|
||||||
|
|
||||||
encode_from_template(Type, V, Vsn, Types) ->
|
|
||||||
encode_from_template(Type, V, true, Vsn, Types).
|
|
||||||
|
|
||||||
encode_from_template(list, L, _, Vsn, Types) when is_list(L) ->
|
|
||||||
[encode_(V, Vsn, Types) || V <- L];
|
|
||||||
encode_from_template(map, M, _, Vsn, Types) when is_map(M) ->
|
|
||||||
[encode_({K,V}, false, Vsn, Types)
|
|
||||||
|| {K, V} <- lists:sort(maps:to_list(M))];
|
|
||||||
encode_from_template(tuple, T, _, Vsn, Types) when is_tuple(T) ->
|
|
||||||
[encode_(V, Vsn, Types) || V <- tuple_to_list(T)];
|
|
||||||
encode_from_template(T, V, _, Vsn, Types) when tuple_size(T) =:= tuple_size(V) ->
|
|
||||||
Zipped = lists:zip(tuple_to_list(T), tuple_to_list(V)),
|
|
||||||
[encode_from_template(T1, V1, false, Vsn, Types) || {T1, V1} <- Zipped];
|
|
||||||
encode_from_template([Type], List, _, Vsn, Types) ->
|
|
||||||
[encode_from_template(Type, V, false, Vsn, Types) || V <- List];
|
|
||||||
encode_from_template(Type, List, _, Vsn, Types) when is_list(Type), is_list(List) ->
|
|
||||||
encode_fields(Type, List, Vsn, Types);
|
|
||||||
encode_from_template(Type, V, _, _, _Types) when Type == id
|
|
||||||
; Type == binary
|
|
||||||
; Type == bool
|
|
||||||
; Type == int
|
|
||||||
; Type == label ->
|
|
||||||
encode_basic(Type, V);
|
|
||||||
encode_from_template(Type, V, _, _, _) ->
|
|
||||||
error({illegal, Type, V}).
|
|
||||||
|
|
||||||
|
|
||||||
%% Basically, dynamically encoding a statically defined object
|
|
||||||
encode_fields([{Field, Type}|TypesLeft],
|
|
||||||
[{Field, Val}|FieldsLeft], Vsn, Types) ->
|
|
||||||
[ encode_from_template(Type, Val, Vsn, Types)
|
|
||||||
| encode_fields(TypesLeft, FieldsLeft, Vsn, Types)];
|
|
||||||
encode_fields([{_Field, Type}|TypesLeft],
|
|
||||||
[Val |FieldsLeft], Vsn, Types) ->
|
|
||||||
%% Not sure if we want to try this ...
|
|
||||||
[ encode_from_template(Type, Val, Vsn, Types)
|
|
||||||
| encode_fields(TypesLeft, FieldsLeft, Vsn, Types)];
|
|
||||||
encode_fields([Type|TypesLeft],
|
|
||||||
[Val |FieldsLeft], Vsn, Types) when is_atom(Type) ->
|
|
||||||
%% Not sure about this either ...
|
|
||||||
[ encode_from_template(Type, Val, Vsn, Types)
|
|
||||||
| encode_fields(TypesLeft, FieldsLeft, Vsn, Types)];
|
|
||||||
encode_fields([], [], _, _) ->
|
|
||||||
[].
|
|
||||||
|
|
||||||
decode_fields([{Tag, Type}|TypesLeft],
|
|
||||||
[Field |FieldsLeft], Vsn, Types) ->
|
|
||||||
|
|
||||||
[ {Tag, decode_from_template(Type, Field, Vsn, Types)}
|
|
||||||
| decode_fields(TypesLeft, FieldsLeft, Vsn, Types)];
|
|
||||||
decode_fields([], [], _, _) ->
|
|
||||||
[].
|
|
||||||
|
|
||||||
emit_code(Tag, #{rev := Tags}) ->
|
|
||||||
encode_basic(int, maps:get(Tag, Tags)).
|
|
||||||
|
|
||||||
decode_basic(label, Fld) ->
|
|
||||||
binary_to_existing_atom(decode_basic(binary, Fld), utf8);
|
|
||||||
decode_basic(Type, Fld) ->
|
|
||||||
gmserialization:decode_field(Type, Fld).
|
|
||||||
|
|
||||||
encode_basic(label, A) when is_atom(A) ->
|
|
||||||
encode_basic(binary, atom_to_binary(A, utf8));
|
|
||||||
encode_basic(Type, Fld) ->
|
|
||||||
gmserialization:encode_field(Type, Fld).
|
|
||||||
|
|
||||||
rlp_decode(Bin) ->
|
|
||||||
gmser_rlp:decode(Bin).
|
|
||||||
|
|
||||||
rlp_encode(Fields) ->
|
|
||||||
gmser_rlp:encode(Fields).
|
|
||||||
|
|
||||||
|
|
||||||
-ifdef(TEST).
|
|
||||||
|
|
||||||
trace() ->
|
|
||||||
dbg:tracer(),
|
|
||||||
dbg:tpl(?MODULE, x),
|
|
||||||
dbg:p(all, [c]).
|
|
||||||
|
|
||||||
notrace() ->
|
|
||||||
dbg:ctpl('_'),
|
|
||||||
dbg:stop().
|
|
||||||
|
|
||||||
round_trip_test_() ->
|
|
||||||
[?_test(t_round_trip(T)) ||
|
|
||||||
T <- t_sample_types()
|
|
||||||
].
|
|
||||||
|
|
||||||
t_sample_types() ->
|
|
||||||
[ 5
|
|
||||||
, <<"a">>
|
|
||||||
, [1,2,3]
|
|
||||||
, {<<"a">>,1}
|
|
||||||
, #{<<"a">> => 1}
|
|
||||||
, [#{1 => <<"c">>, [17] => true}]
|
|
||||||
, true
|
|
||||||
].
|
|
||||||
|
|
||||||
user_types_test_() ->
|
|
||||||
{foreach,
|
|
||||||
fun() ->
|
|
||||||
revert_to_default_types()
|
|
||||||
end,
|
|
||||||
fun(_) ->
|
|
||||||
revert_to_default_types()
|
|
||||||
end,
|
|
||||||
[ ?_test(t_reg_typed_tuple())
|
|
||||||
, ?_test(t_reg_chain_objects_array())
|
|
||||||
]}.
|
|
||||||
|
|
||||||
t_round_trip(T) ->
|
|
||||||
?debugVal(T),
|
|
||||||
?assertMatch({T, T}, {T, decode(encode(T))}).
|
|
||||||
|
|
||||||
t_reg_typed_tuple() ->
|
|
||||||
Type = {int, int, int},
|
|
||||||
MyTypes = #{ codes => #{ 1001 => int_tup3 }
|
|
||||||
, templates => #{ int_tup3 => Type }
|
|
||||||
},
|
|
||||||
register_types(MyTypes),
|
|
||||||
GoodTerm = {2,3,4},
|
|
||||||
?debugFmt("Type: ~p, GoodTerm = ~p", [Type, GoodTerm]),
|
|
||||||
Enc = encode_typed(int_tup3, GoodTerm),
|
|
||||||
GoodTerm = decode(Enc),
|
|
||||||
t_bad_typed_encode(int_tup3, {1,2,<<"a">>}, {illegal,int,<<"a">>}),
|
|
||||||
t_bad_typed_encode(int_tup3, {1,2,3,4}, {illegal, {int,int,int}, {1,2,3,4}}).
|
|
||||||
|
|
||||||
t_bad_typed_encode(Type, Term, Error) ->
|
|
||||||
try encode_typed(Type, Term),
|
|
||||||
error({expected_error, Error})
|
|
||||||
catch
|
|
||||||
error:Error ->
|
|
||||||
ok
|
|
||||||
end.
|
|
||||||
|
|
||||||
t_reg_chain_objects_array() ->
|
|
||||||
Template = [{foo, {int, binary}}, {bar, [{int, int}]}, {baz, {int}}],
|
|
||||||
?debugFmt("Template = ~p", [Template]),
|
|
||||||
MyTypes = #{ codes => #{ 1002 => coa }
|
|
||||||
, templates => #{ coa => Template } },
|
|
||||||
register_types(MyTypes),
|
|
||||||
Values = [{foo, {1, <<"foo">>}}, {bar, [{1, 2}, {3, 4}, {5, 6}]}, {baz, {1}}],
|
|
||||||
?debugFmt("Values = ~p", [Values]),
|
|
||||||
Enc = encode_typed(coa, Values),
|
|
||||||
Values = decode(Enc).
|
|
||||||
|
|
||||||
-endif.
|
|
||||||
@@ -10,11 +10,9 @@
|
|||||||
-vsn("0.1.2").
|
-vsn("0.1.2").
|
||||||
|
|
||||||
-export([ decode_fields/2
|
-export([ decode_fields/2
|
||||||
, decode_field/2
|
|
||||||
, deserialize/5
|
, deserialize/5
|
||||||
, deserialize_tag_and_vsn/1
|
, deserialize_tag_and_vsn/1
|
||||||
, encode_fields/2
|
, encode_fields/2
|
||||||
, encode_field/2
|
|
||||||
, serialize/4 ]).
|
, serialize/4 ]).
|
||||||
|
|
||||||
%%%===================================================================
|
%%%===================================================================
|
||||||
@@ -25,8 +23,6 @@
|
|||||||
, fields/0
|
, fields/0
|
||||||
]).
|
]).
|
||||||
|
|
||||||
-export_type([ encodable_term/0 ]).
|
|
||||||
|
|
||||||
-type template() :: [{field_name(), type()}].
|
-type template() :: [{field_name(), type()}].
|
||||||
-type field_name() :: atom().
|
-type field_name() :: atom().
|
||||||
-type type() :: 'int'
|
-type type() :: 'int'
|
||||||
|
|||||||
Reference in New Issue
Block a user