diff --git a/include/aeb_fate_data.hrl b/include/aeb_fate_data.hrl index 3160b4d..8c07896 100644 --- a/include/aeb_fate_data.hrl +++ b/include/aeb_fate_data.hrl @@ -5,6 +5,7 @@ -define(FATE_LIST_T, list()). -define(FATE_UNIT_T, {tuple, {}}). -define(FATE_MAP_T, #{ fate_type() => fate_type() }). +-define(FATE_STORE_MAP_T, {store_map, #{ fate_type() => fate_type() | ?FATE_MAP_TOMBSTONE }, integer()}). -define(FATE_STRING_T, binary()). -define(FATE_ADDRESS_T, {address, <<_:256>>}). -define(FATE_BYTES_T(N), {bytes, binary()}). @@ -20,6 +21,10 @@ -define(IS_FATE_INTEGER(X), (is_integer(X))). -define(IS_FATE_LIST(X), (is_list(X))). -define(IS_FATE_STRING(X), (is_binary(X))). +-define(IS_FATE_STORE_MAP(X), (is_tuple(X) andalso tuple_size(X) == 3 + andalso store_map == element(1, X) + andalso is_map(element(2, X)) + andalso is_integer(element(3, X)))). -define(IS_FATE_MAP(X), (is_map(X))). -define(IS_FATE_TUPLE(X), (is_tuple(X) andalso (tuple == element(1, X) andalso is_tuple(element(2, X))))). -define(IS_FATE_ADDRESS(X), (is_tuple(X) andalso (address == element(1, X) andalso is_binary(element(2, X))))). @@ -50,6 +55,8 @@ -define(FATE_CHANNEL(X), {channel, X}). -define(FATE_BITS(B), {bits, B}). -define(FATE_TYPEREP(T), {typerep, T}). +-define(FATE_STORE_MAP(Cache, Id), {store_map, Cache, Id}). +-define(FATE_MAP_TOMBSTONE, '__DELETED__'). -define(FATE_INTEGER_VALUE(X), (X)). -define(FATE_BOOLEAN_VALUE(X), (X)). @@ -63,6 +70,8 @@ -define(FATE_CHANNEL_VALUE(X), (element(2, X))). -define(FATE_BITS_VALUE(X), (element(2, X))). -define(FATE_MAP_VALUE(X), (X)). +-define(FATE_STORE_MAP_CACHE(X), (element(2, X))). +-define(FATE_STORE_MAP_ID(X), (element(3, X))). -define(FATE_MAP_SIZE(X), (map_size(X))). -define(FATE_STRING_SIZE(X), (byte_size(X))). -define(FATE_TRUE, true). diff --git a/src/aeb_fate_data.erl b/src/aeb_fate_data.erl index 2660386..eb7b54b 100644 --- a/src/aeb_fate_data.erl +++ b/src/aeb_fate_data.erl @@ -10,6 +10,7 @@ -type fate_list() :: ?FATE_LIST_T. -type fate_unit() :: ?FATE_UNIT_T. -type fate_map() :: ?FATE_MAP_T. +-type fate_store_map() :: ?FATE_STORE_MAP_T. -type fate_string() :: ?FATE_STRING_T. -type fate_address() :: ?FATE_ADDRESS_T. -type fate_hash() :: ?FATE_BYTES_T(32). @@ -71,6 +72,7 @@ , fate_channel/0 , fate_variant/0 , fate_map/0 + , fate_store_map/0 , fate_bits/0 , fate_type_type/0 ]). @@ -82,6 +84,8 @@ , make_tuple/1 , make_string/1 , make_map/1 + , make_store_map/1 + , make_store_map/2 , make_address/1 , make_bytes/1 , make_hash/1 @@ -108,6 +112,8 @@ make_list(L) -> ?MAKE_FATE_LIST(L). make_unit() -> ?FATE_UNIT. make_tuple(T) -> ?FATE_TUPLE(T). make_map(M) -> ?MAKE_FATE_MAP(M). +make_store_map(Id) -> make_store_map(#{}, Id). +make_store_map(Cache, Id) -> ?FATE_STORE_MAP(Cache, Id). make_address(X) -> ?FATE_ADDRESS(X). make_bytes(X) -> ?FATE_BYTES(X). make_hash(X) -> make_bytes(X). diff --git a/src/aeb_fate_encoding.erl b/src/aeb_fate_encoding.erl index 2475c1d..3706322 100644 --- a/src/aeb_fate_encoding.erl +++ b/src/aeb_fate_encoding.erl @@ -93,6 +93,7 @@ %% %% 1000 1111 - FREE (Possibly for bytecode in the future.) -define(OBJECT , 2#10011111). %% 1001 1111 | ObjectType | RLP encoded Array -define(VARIANT , 2#10101111). %% 1010 1111 | [encoded arities] | encoded tag | [encoded values] +-define(MAP_ID , 2#10111111). %% 1011 1111 | RLP encoded integer (store map id) -define(NEG_BITS , 2#11001111). %% 1100 1111 | RLP encoded integer (infinite 1:s bitfield) -define(EMPTY_MAP , 2#11011111). %% 1101 1111 -define(NEG_BIG_INT , 2#11101111). %% 1110 1111 | RLP encoded (integer - 64) @@ -193,6 +194,9 @@ serialize(Map) when ?IS_FATE_MAP(Map) -> <>; +serialize(?FATE_STORE_MAP(Cache, Id)) when Cache =:= #{} -> + %% We should never get to serialization without having flushed the caches. + <>; serialize(?FATE_VARIANT(Arities, Tag, Values)) -> Arities = [A || A <- Arities, is_integer(A), A < 256], Size = length(Arities), @@ -426,6 +430,9 @@ deserialize2(<>) -> false -> error({unknown_map_serialization_format, KVList}) end; +deserialize2(<>) -> + {Id, Rest1} = rlp_decode_int(Rest), + {?FATE_STORE_MAP(#{}, Id), Rest1}; deserialize2(<>) -> {AritiesBin, <>} = aeser_rlp:decode_one(Rest), Arities = binary_to_list(AritiesBin),