coerce bytes

This commit is contained in:
Jarvis Carroll 2025-09-23 14:35:42 +10:00
parent 0caf5a61c7
commit 4ed2bd0cd1

View File

@ -1520,6 +1520,8 @@ opaque_type(Params, #{variant := VariantDefs}) ->
{variant, Variants};
opaque_type(Params, #{tuple := TypeDefs}) ->
{tuple, [opaque_type(Params, Type) || Type <- TypeDefs]};
opaque_type(_, #{bytes := Count}) ->
{bytes, [Count]};
opaque_type(Params, Pair) when is_map(Pair) ->
[{Name, TypeArgs}] = maps:to_list(Pair),
{opaque_type_name(Name), [opaque_type(Params, Arg) || Arg <- TypeArgs]}.
@ -1544,7 +1546,6 @@ opaque_type_name(<<"string">>) -> string;
opaque_type_name(<<"address">>) -> address;
opaque_type_name(<<"hash">>) -> hash;
opaque_type_name(<<"signature">>) -> signature;
opaque_type_name(<<"bytes">>) -> bytes;
opaque_type_name(<<"contract">>) -> contract;
opaque_type_name(<<"list">>) -> list;
opaque_type_name(<<"map">>) -> map;
@ -1615,6 +1616,10 @@ annotate_types([], _Types, Acc) ->
annotate_type_subexpressions(PrimitiveType, _Types) when is_atom(PrimitiveType) ->
{ok, PrimitiveType};
annotate_type_subexpressions({bytes, [Count]}, _Types) ->
% bytes is weird, because it has an argument, but that argument isn't an
% opaque type.
{ok, {bytes, [Count]}};
annotate_type_subexpressions({variant, VariantsOpaque}, Types) ->
case annotate_variants(VariantsOpaque, Types, []) of
{ok, Variants} -> {ok, {variant, Variants}};
@ -1843,6 +1848,8 @@ coerce({O, N, string}, Str, Direction) ->
StrBin ->
{ok, StrBin}
end;
coerce({O, N, {bytes, [Count]}}, Bytes, _Direction) when is_binary(Bytes) ->
coerce_bytes(O, N, Count, Bytes);
coerce({_, _, {list, [Type]}}, Data, Direction) when is_list(Data) ->
coerce_list(Type, Data, Direction);
coerce({_, _, {map, [KeyType, ValType]}}, Data, Direction) when is_map(Data) ->
@ -1892,6 +1899,15 @@ coerce({O, N, _}, Data, from_fate) ->
{ok, Data};
coerce({O, N, _}, Data, _) -> single_error({invalid, O, N, Data}).
coerce_bytes(O, N, _, Bytes) when bit_size(Bytes) rem 8 /= 0 ->
single_error({partial_bytes, O, N, bit_size(Bytes)});
coerce_bytes(_, _, any, Bytes) ->
{ok, Bytes};
coerce_bytes(O, N, Count, Bytes) when byte_size(Bytes) /= Count ->
single_error({incorrect_size, O, N, Bytes});
coerce_bytes(_, _, _, Bytes) ->
{ok, Bytes}.
coerce_chain_object(O, N, T, Tag, S) ->
case decode_chain_object(Tag, S) of
{ok, Data} -> {ok, coerce_chain_object2(T, Data)};
@ -2594,3 +2610,12 @@ param_test() ->
try_coerce(Input, 0, 0),
try_coerce(Output, 0, 0).
bytes_test() ->
Contract = "
contract C =
entrypoint f(): bytes(4) * bytes() = (#DEADBEEF, Bytes.to_any_size(#112233))
",
{ok, AACI} = aaci_from_string(Contract),
{ok, {[], Output}} = aaci_lookup_spec(AACI, "f"),
try_coerce(Output, {<<"abcd">>, <<"efghi">>}, {tuple, {<<"abcd">>, <<"efghi">>}}).