diff --git a/src/aeb_fate_data.erl b/src/aeb_fate_data.erl index 4adfb71..d6792aa 100644 --- a/src/aeb_fate_data.erl +++ b/src/aeb_fate_data.erl @@ -96,7 +96,10 @@ , make_bits/1 , make_unit/0 ]). --export([format/1]). +-export([ + elt/2 + , lt/2 + , format/1]). make_boolean(true) -> ?FATE_TRUE; @@ -193,3 +196,54 @@ format_list(List) -> format_kvs(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. + diff --git a/src/aeb_fate_encoding.erl b/src/aeb_fate_encoding.erl index 3bc3529..1127a27 100644 --- a/src/aeb_fate_encoding.erl +++ b/src/aeb_fate_encoding.erl @@ -1,21 +1,29 @@ %% Fate data (and instruction) serialization. %% -%% The FATE serialization has to fullfill the following properties: -%% * There has to be 1 and only 1 byte sequence -%% representing each unique value in FATE. -%% * A valid byte sequence has to be deserializable to a FATE value. -%% * A valid byte sequence must not contain any trailing bytes. -%% * A serialization is a sequence of 8-bit bytes. -%% -%% The serialization function should fullfill the following: -%% * A valid FATE value should be serialized to a byte sequence. -%% * Any other argument, not representing a valid FATE value should +%% 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: +%% * For each value (V) in FATE there has to be a bytecode sequence (B) +%% representing that value. +%% * A valid byte sequence has to be deserializable to a FATE value. +%% * A valid byte sequence must not contain any trailing bytes. +%% * A serialization is a sequence of 8-bit bytes. +%% The serialization function (S) should fullfill the following: +%% * A valid FATE value should be serialized to a byte sequence. +%% * Any other argument, not representing a valid FATE value should %% throw an exception -%% -%% The deserialization function should fullfill the following: -%% * A valid byte sequence should be deserialized to a valid FATE value. -%% * Any other argument, not representing a valid byte sequence should +%% The deserialization function (D) should fullfill the following: +%% * A valid byte sequence should be deserialized to a valid FATE value. +%% * Any other argument, not representing a valid byte sequence should %% throw an exception +%% The following equalities should hold: +%% * D(S(V)) == V +%% * if V1 == V2 then S(V1) == S(V2) +%% %% %% History %% * First draft of FATE serialization encoding/decoding. @@ -421,7 +429,7 @@ deserialize_elements(N, Es) -> {[E|Tail], Rest2}. -%% It is important to rem ove duplicated keys. +%% It is important to remove duplicated keys. %% For deserialize this check is needed to observe illegal duplicates. sort_and_check(List) -> UniqKeyList = @@ -439,7 +447,7 @@ sort_and_check(List) -> sort(KVList) -> SortFun = fun({K1, _}, {K2, _}) -> - K1 =< K2 + aeb_fate_data:elt(K1, K2) end, lists:sort(SortFun, KVList).