Add options for deserialization of missing labels
Some checks failed
Gajumaru Serialization Tests / tests (push) Failing after 49m16s
Some checks failed
Gajumaru Serialization Tests / tests (push) Failing after 49m16s
This commit is contained in:
parent
ba771836fb
commit
a949d166f6
18
README.md
18
README.md
@ -58,6 +58,24 @@ Labels correspond to (existing) atoms in Erlang.
|
||||
Decoding of a label results in a call to `binary_to_existing_atom/2`, so will
|
||||
fail if the corresponding atom does not already exist.
|
||||
|
||||
This behavior can be modified using the option `#{missing_labels => fail | create | convert}`,
|
||||
where `fail` is the default, as described above, `convert` means that missing atoms are
|
||||
converted to binaries, and `create` means that the atom is created dynamically.
|
||||
|
||||
The option can be passed e.g.:
|
||||
```erlang
|
||||
gmser_dyn:deserialize(Binary, set_opts(#{missing_labels => convert}))
|
||||
```
|
||||
|
||||
or
|
||||
```erlang
|
||||
gmser_dyn:deserialize(Binary, set_opts(#{missing_labels => convert}, Types))
|
||||
```
|
||||
|
||||
By calling `gmser_dyn:register_types/1`, after having added options to the type map,
|
||||
the options can be made to take effect automatically.
|
||||
|
||||
|
||||
It's possible to cache labels for more compact encoding.
|
||||
Note that when caching labels, the same cache mapping needs to be used on the
|
||||
decoder side.
|
||||
|
@ -17,6 +17,9 @@
|
||||
%% register a type schema, inspect existing schema
|
||||
-export([ register_types/1
|
||||
, registered_types/0
|
||||
, get_opts/1
|
||||
, set_opts/1
|
||||
, set_opts/2
|
||||
, types_from_list/1
|
||||
, revert_to_default_types/0
|
||||
, dynamic_types/0 ]).
|
||||
@ -121,6 +124,7 @@ dynamic_types() ->
|
||||
, id => id
|
||||
, label => label
|
||||
}
|
||||
, options => #{}
|
||||
}.
|
||||
|
||||
vsn(Types) ->
|
||||
@ -399,15 +403,29 @@ emit(0, _, _, Enc) ->
|
||||
emit_code(Tag, #{rev := Tags}) ->
|
||||
encode_basic(int, maps:get(Tag, Tags)).
|
||||
|
||||
decode_basic(Type, [Tag,V], #{codes := Codes}) ->
|
||||
decode_basic(Type, [Tag,V], #{codes := Codes} = Types) ->
|
||||
case decode_basic(int, Tag) of
|
||||
Code when map_get(Code, Codes) == Type ->
|
||||
decode_basic(Type, V);
|
||||
decode_basic_(Type, V, Types);
|
||||
_ ->
|
||||
error(illegal)
|
||||
end;
|
||||
decode_basic(Type, V, _) ->
|
||||
decode_basic(Type, V).
|
||||
decode_basic(Type, V, Types) ->
|
||||
decode_basic_(Type, V, Types).
|
||||
|
||||
decode_basic_(label, Fld, #{options := #{missing_labels := Opt}}) ->
|
||||
Bin = decode_basic(binary, Fld),
|
||||
case Opt of
|
||||
create -> binary_to_atom(Bin, utf8);
|
||||
fail -> binary_to_existing_atom(Bin, utf8);
|
||||
convert ->
|
||||
try binary_to_existing_atom(Bin, utf8)
|
||||
catch
|
||||
error:_ -> Bin
|
||||
end
|
||||
end;
|
||||
decode_basic_(label, Fld, _) ->
|
||||
decode_basic(label, Fld).
|
||||
|
||||
decode_basic(label, Fld) ->
|
||||
binary_to_existing_atom(decode_basic(binary, Fld), utf8);
|
||||
@ -473,6 +491,15 @@ register_type(Code, Tag, Template) when is_integer(Code), Code >= 0 ->
|
||||
{_, true} -> error(tag_exists)
|
||||
end.
|
||||
|
||||
set_opts(Opts) ->
|
||||
set_opts(Opts, registered_types()).
|
||||
|
||||
set_opts(Opts, Types) ->
|
||||
Types#{options => Opts}.
|
||||
|
||||
get_opts(#{options := Opts}) ->
|
||||
Opts.
|
||||
|
||||
cache_label(Code, Label) when is_integer(Code), Code >= 0, is_atom(Label) ->
|
||||
#{labels := Lbls, rev_labels := RevLbls} = Types = registered_types(),
|
||||
case {is_map_key(Label, Lbls), is_map_key(Code, RevLbls)} of
|
||||
|
Loading…
x
Reference in New Issue
Block a user