coerce bits

The thing to remember about bits is that they are actually integers...
It is tempting to present bits as binaries, but that hides the nuance of
the infinite leading zeroes, the potential for infinite leading ones,
etc.
This commit is contained in:
Jarvis Carroll 2025-09-23 15:42:53 +10:00
parent 4ed2bd0cd1
commit d3fb598506

View File

@ -1848,8 +1848,16 @@ coerce({O, N, string}, Str, Direction) ->
StrBin ->
{ok, StrBin}
end;
coerce({O, N, {bytes, [Count]}}, Bytes, _Direction) when is_binary(Bytes) ->
coerce({O, N, {bytes, [Count]}}, Bytes, _Direction) when is_bitstring(Bytes) ->
coerce_bytes(O, N, Count, Bytes);
coerce({_, _, bits}, {bits, Num}, from_fate) ->
{ok, Num};
coerce({_, _, bits}, Num, to_fate) when is_integer(Num) ->
{ok, {bits, Num}};
coerce({_, _, bits}, Bits, to_fate) when is_bitstring(Bits) ->
Size = bit_size(Bits),
<<IntValue:Size>> = Bits,
{ok, {bits, IntValue}};
coerce({_, _, {list, [Type]}}, Data, Direction) when is_list(Data) ->
coerce_list(Type, Data, Direction);
coerce({_, _, {map, [KeyType, ValType]}}, Data, Direction) when is_map(Data) ->
@ -2524,6 +2532,14 @@ coerce_record_test() ->
{ok, Type} = annotate_type({record, [{"a", integer}, {"b", integer}]}, #{}),
try_coerce(Type, #{"a" => 123, "b" => 456}, {tuple, {123, 456}}).
coerce_bytes_test() ->
{ok, Type} = annotate_type({tuple, [{bytes, [4]}, {bytes, [any]}]}, #{}),
try_coerce(Type, {<<"abcd">>, <<"efghi">>}, {tuple, {<<"abcd">>, <<"efghi">>}}).
bits_test() ->
{ok, Type} = annotate_type(bits, #{}),
try_coerce(Type, 5, {bits, 5}).
%%% Complex AACI paramter and namespace tests
@ -2610,12 +2626,27 @@ param_test() ->
try_coerce(Input, 0, 0),
try_coerce(Output, 0, 0).
bytes_test() ->
%%% Obscure Sophia types where we should check the AACI as well
obscure_aaci_test() ->
Contract = "
contract C =
entrypoint f(): bytes(4) * bytes() = (#DEADBEEF, Bytes.to_any_size(#112233))
entrypoint options(): option(int) = None
entrypoint fixed_bytes(): bytes(4) = #DEADBEEF
entrypoint any_bytes(): bytes() = Bytes.to_any_size(#112233)
entrypoint bits(): bits = Bits.all
",
{ok, AACI} = aaci_from_string(Contract),
{ok, {[], Output}} = aaci_lookup_spec(AACI, "f"),
try_coerce(Output, {<<"abcd">>, <<"efghi">>}, {tuple, {<<"abcd">>, <<"efghi">>}}).
IntAnnotated = {integer, already_normalized, integer},
OptionFlat = {variant, [{"None", []}, {"Some", [IntAnnotated]}]},
OptionAnnotated = {{option, [integer]}, already_normalized, OptionFlat},
{ok, {[], OptionAnnotated}} = aaci_lookup_spec(AACI, "options"),
{ok, {[], {_, _, {bytes, [4]}}}} = aaci_lookup_spec(AACI, "fixed_bytes"),
{ok, {[], {_, _, {bytes, [any]}}}} = aaci_lookup_spec(AACI, "any_bytes"),
{ok, {[], {_, _, bits}}} = aaci_lookup_spec(AACI, "bits"),
ok.