Add first draft of total order for FATE terms.

This commit is contained in:
Erik Stenman 2019-05-30 12:31:40 +02:00
parent 53130fc638
commit 942c7fb069
2 changed files with 79 additions and 17 deletions

View File

@ -96,7 +96,10 @@
, make_bits/1 , make_bits/1
, make_unit/0 , make_unit/0
]). ]).
-export([format/1]). -export([
elt/2
, lt/2
, format/1]).
make_boolean(true) -> ?FATE_TRUE; make_boolean(true) -> ?FATE_TRUE;
@ -193,3 +196,54 @@ format_list(List) ->
format_kvs(List) -> format_kvs(List) ->
lists:join(", ", [ [format(K), " => ", format(V)] || {K, V} <- List]). lists:join(", ", [ [format(K), " => ", format(V)] || {K, V} <- List]).
%% Total order of FATE terms.
%% Integers < Booleans < Address < Channel < Contract < Name < Oracle
%% < Hash < Signature < Bits < Tuple < Map < List
ordinal(T) when ?IS_FATE_INTEGER(T) -> 0;
ordinal(T) when ?IS_FATE_BOOLEAN(T) -> 1;
ordinal(T) when ?IS_FATE_ADDRESS(T) -> 2;
ordinal(T) when ?IS_FATE_CHANNEL(T) -> 3;
ordinal(T) when ?IS_FATE_CONTRACT(T) -> 4;
ordinal(T) when ?IS_FATE_NAME(T) -> 5;
ordinal(T) when ?IS_FATE_ORACLE(T) -> 6;
ordinal(T) when ?IS_FATE_HASH(T) -> 7;
ordinal(T) when ?IS_FATE_SIGNATURE(T) -> 8;
ordinal(T) when ?IS_FATE_BITS(T) -> 9;
ordinal(T) when ?IS_FATE_TUPLE(T) -> 10;
ordinal(T) when ?IS_FATE_MAP(T) -> 11;
ordinal(T) when ?IS_FATE_LIST(T) -> 12.
-spec lt(fate_type(), fate_type()) -> boolean.
%% This function assumes that all lists and maps are monomorphic,
%% and only tests one element of a list or a map.
%% If there is a risc that the term is not monomorphic,
%% use safe_lt.
lt(A, B) ->
O1 = ordinal(A),
O2 = ordinal(B),
if O1 == O2 -> lt(O1, A, B);
true -> O1 < O2
end.
%% Integer is the smallest FATE type.
%% Integers themselves are ordered as usual.
lt(0, A, B) when ?IS_FATE_INTEGER(A), ?IS_FATE_INTEGER(B) ->
?FATE_INTEGER_VALUE(A) < ?FATE_INTEGER_VALUE(B);
%% Boolean is the second smallest FATE type.
%% false is smaller than true (true also for erlang booleans).
lt(1, A, B) when ?IS_FATE_BOOLEAN(A), ?IS_FATE_INTEGER(B) -> false;
lt(1, A, B) when ?IS_FATE_BOOLEAN(A), ?IS_FATE_BOOLEAN(B) ->
?FATE_BOOLEAN_VALUE(A) < ?FATE_BOOLEAN_VALUE(B);
lt(_, A, B) -> A < B.
-spec elt(fate_type(), fate_type()) -> boolean.
elt(A, A) -> true;
elt(A, B) ->
R = lt(A, B),
io:format("~w < ~w : ~w~n", [A, B, R]),
R.

View File

@ -1,21 +1,29 @@
%% Fate data (and instruction) serialization. %% Fate data (and instruction) serialization.
%% %%
%% Assuming
%% S is seralize/1 (fate_type() -> binary())
%% D is deserialize/1 (binary) -> fate_type())
%% V, V1, V2 are of the type fate_type()
%% B is of the type binary()
%% Then
%% The FATE serialization has to fullfill the following properties: %% The FATE serialization has to fullfill the following properties:
%% * There has to be 1 and only 1 byte sequence %% * For each value (V) in FATE there has to be a bytecode sequence (B)
%% representing each unique value in FATE. %% representing that value.
%% * A valid byte sequence has to be deserializable to a FATE value. %% * A valid byte sequence has to be deserializable to a FATE value.
%% * A valid byte sequence must not contain any trailing bytes. %% * A valid byte sequence must not contain any trailing bytes.
%% * A serialization is a sequence of 8-bit bytes. %% * A serialization is a sequence of 8-bit bytes.
%% %% The serialization function (S) should fullfill the following:
%% The serialization function should fullfill the following:
%% * A valid FATE value should be serialized to a byte sequence. %% * A valid FATE value should be serialized to a byte sequence.
%% * Any other argument, not representing a valid FATE value should %% * Any other argument, not representing a valid FATE value should
%% throw an exception %% throw an exception
%% %% The deserialization function (D) should fullfill the following:
%% The deserialization function should fullfill the following:
%% * A valid byte sequence should be deserialized to a valid FATE value. %% * A valid byte sequence should be deserialized to a valid FATE value.
%% * Any other argument, not representing a valid byte sequence should %% * Any other argument, not representing a valid byte sequence should
%% throw an exception %% throw an exception
%% The following equalities should hold:
%% * D(S(V)) == V
%% * if V1 == V2 then S(V1) == S(V2)
%%
%% %%
%% History %% History
%% * First draft of FATE serialization encoding/decoding. %% * First draft of FATE serialization encoding/decoding.
@ -439,7 +447,7 @@ sort_and_check(List) ->
sort(KVList) -> sort(KVList) ->
SortFun = fun({K1, _}, {K2, _}) -> SortFun = fun({K1, _}, {K2, _}) ->
K1 =< K2 aeb_fate_data:elt(K1, K2)
end, end,
lists:sort(SortFun, KVList). lists:sort(SortFun, KVList).