Skip to content

Instantly share code, notes, and snippets.

@potatosalad
Last active October 14, 2022 20:00
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save potatosalad/9066a078aee6bb80895d379c1eda804a to your computer and use it in GitHub Desktop.
Save potatosalad/9066a078aee6bb80895d379c1eda804a to your computer and use it in GitHub Desktop.
rebar3 proper --module=prop_find_broken_maps --numtests 10000 --max_shrinks 250 --constraint_tries 1000 --start_size 33
===> Verifying dependencies...
make: Nothing to be done for `all'.
===> Analyzing applications...
===> Compiling erldist_filter
=ERROR REPORT==== 14-Oct-2022::14:59:33.585605 ===
Module rebar3_proper_prv must be purged before deleting
===> Testing prop_find_broken_maps:prop_find_broken_maps()
..!
Failed: After 3 test(s).
{33,{map_ext,33,[{map_ext_pair,0,12},{map_ext_pair,1,14},{map_ext_pair,2,0.0},{map_ext_pair,3,25},{map_ext_pair,4,26},{map_ext_pair,5,9},{map_ext_pair,6,27},{map_ext_pair,7,9},{map_ext_pair,8,13},{map_ext_pair,9,10},{map_ext_pair,10,13},{map_ext_pair,11,9},{map_ext_pair,12,21},{map_ext_pair,13,19},{map_ext_pair,14,24},{map_ext_pair,15,28},{map_ext_pair,16,4},{map_ext_pair,17,4},{map_ext_pair,18,21},{map_ext_pair,19,31},{map_ext_pair,20,12},{map_ext_pair,21,12},{map_ext_pair,22,19},{map_ext_pair,23,0},{map_ext_pair,24,29},{map_ext_pair,25,23},{map_ext_pair,26,16},{map_ext_pair,29,21},{map_ext_pair,30,28},{map_ext_pair,31,15},{map_ext_pair,32,7},{map_ext_pair,33,27},{map_ext_pair,{map_ext,4,[{map_ext_pair,0.0,17},{map_ext_pair,3,25},{map_ext_pair,21,1},{map_ext_pair,28,32}]},14}]}}
Found encoding of MAP_EXT which decodes into a broken map.
TermExt =
{map_ext,33,
[{map_ext_pair,0,12},
{map_ext_pair,1,14},
{map_ext_pair,2,0.0},
{map_ext_pair,3,25},
{map_ext_pair,4,26},
{map_ext_pair,5,9},
{map_ext_pair,6,27},
{map_ext_pair,7,9},
{map_ext_pair,8,13},
{map_ext_pair,9,10},
{map_ext_pair,10,13},
{map_ext_pair,11,9},
{map_ext_pair,12,21},
{map_ext_pair,13,19},
{map_ext_pair,14,24},
{map_ext_pair,15,28},
{map_ext_pair,16,4},
{map_ext_pair,17,4},
{map_ext_pair,18,21},
{map_ext_pair,19,31},
{map_ext_pair,20,12},
{map_ext_pair,21,12},
{map_ext_pair,22,19},
{map_ext_pair,23,0},
{map_ext_pair,24,29},
{map_ext_pair,25,23},
{map_ext_pair,26,16},
{map_ext_pair,29,21},
{map_ext_pair,30,28},
{map_ext_pair,31,15},
{map_ext_pair,32,7},
{map_ext_pair,33,27},
{map_ext_pair,{map_ext,4,
[{map_ext_pair,0.0,17},
{map_ext_pair,3,25},
{map_ext_pair,21,1},
{map_ext_pair,28,32}]},
14}]}
Term0 =
#{16 => 4,18 => 21,5 => 9,19 => 31,10 => 13,24 => 29,4 => 26,21 => 12,
22 => 19,17 => 4,3 => 25,8 => 13,
#{3 => 25,21 => 1,28 => 32,0.0 => 17} => 14,
1 => 14,7 => 9,2 => 0.0,14 => 24,15 => 28,20 => 12,13 => 19,0 => 12,6 => 27,
25 => 23,32 => 7,9 => 10,11 => 9,31 => 15,26 => 16,30 => 28,29 => 21,
23 => 0,12 => 21,33 => 27}
Term1 =
#{16 => 4,18 => 21,5 => 9,19 => 31,10 => 13,24 => 29,4 => 26,21 => 12,
22 => 19,17 => 4,3 => 25,8 => 13,1 => 14,7 => 9,2 => 0.0,14 => 24,15 => 28,
20 => 12,13 => 19,0 => 12,6 => 27,25 => 23,32 => 7,9 => 10,
#{3 => 25,21 => 1,28 => 32,0.0 => 17} => 14,
11 => 9,31 => 15,26 => 16,30 => 28,29 => 21,23 => 0,12 => 21,33 => 27}
Binary =
<<131,116,0,0,0,33,97,0,97,12,97,1,97,14,97,2,70,0,0,0,0,0,0,0,0,97,3,97,25,97,4,97,26,97,5,97,9,97,6,97,27,97,7,97,9,97,8,97,13,97,9,97,10,97,10,97,13,97,11,97,9,97,12,97,21,97,13,97,19,97,14,97,24,97,15,97,28,97,16,97,4,97,17,97,4,97,18,97,21,97,19,97,31,97,20,97,12,97,21,97,12,97,22,97,19,97,23,97,0,97,24,97,29,97,25,97,23,97,26,97,16,97,29,97,21,97,30,97,28,97,31,97,15,97,32,97,7,97,33,97,27,116,0,0,0,4,70,0,0,0,0,0,0,0,0,97,17,97,3,97,25,97,21,97,1,97,28,97,32,97,14>>
Shrinking ......................................................................................(86 time(s))
{33,{map_ext,33,[{map_ext_pair,0,0},{map_ext_pair,1,0},{map_ext_pair,2,0},{map_ext_pair,3,0},{map_ext_pair,4,0},{map_ext_pair,5,0},{map_ext_pair,6,0},{map_ext_pair,7,0},{map_ext_pair,8,0},{map_ext_pair,9,0},{map_ext_pair,10,0},{map_ext_pair,11,0},{map_ext_pair,12,0},{map_ext_pair,13,0},{map_ext_pair,14,0},{map_ext_pair,15,0},{map_ext_pair,16,0},{map_ext_pair,17,0},{map_ext_pair,18,0},{map_ext_pair,19,0},{map_ext_pair,20,0},{map_ext_pair,21,0},{map_ext_pair,22,0},{map_ext_pair,23,0},{map_ext_pair,24,0},{map_ext_pair,25,0},{map_ext_pair,26,0},{map_ext_pair,27,0},{map_ext_pair,28,0},{map_ext_pair,29,0},{map_ext_pair,30,0},{map_ext_pair,31,0},{map_ext_pair,{map_ext,4,[{map_ext_pair,0.0,0},{map_ext_pair,1,0},{map_ext_pair,2,0},{map_ext_pair,3,0}]},0}]}}
Found encoding of MAP_EXT which decodes into a broken map.
TermExt =
{map_ext,33,
[{map_ext_pair,0,0},
{map_ext_pair,1,0},
{map_ext_pair,2,0},
{map_ext_pair,3,0},
{map_ext_pair,4,0},
{map_ext_pair,5,0},
{map_ext_pair,6,0},
{map_ext_pair,7,0},
{map_ext_pair,8,0},
{map_ext_pair,9,0},
{map_ext_pair,10,0},
{map_ext_pair,11,0},
{map_ext_pair,12,0},
{map_ext_pair,13,0},
{map_ext_pair,14,0},
{map_ext_pair,15,0},
{map_ext_pair,16,0},
{map_ext_pair,17,0},
{map_ext_pair,18,0},
{map_ext_pair,19,0},
{map_ext_pair,20,0},
{map_ext_pair,21,0},
{map_ext_pair,22,0},
{map_ext_pair,23,0},
{map_ext_pair,24,0},
{map_ext_pair,25,0},
{map_ext_pair,26,0},
{map_ext_pair,27,0},
{map_ext_pair,28,0},
{map_ext_pair,29,0},
{map_ext_pair,30,0},
{map_ext_pair,31,0},
{map_ext_pair,{map_ext,4,
[{map_ext_pair,0.0,0},
{map_ext_pair,1,0},
{map_ext_pair,2,0},
{map_ext_pair,3,0}]},
0}]}
Term0 =
#{16 => 0,18 => 0,5 => 0,19 => 0,
#{1 => 0,2 => 0,3 => 0,0.0 => 0} => 0,
27 => 0,10 => 0,24 => 0,4 => 0,21 => 0,22 => 0,17 => 0,3 => 0,8 => 0,1 => 0,
7 => 0,2 => 0,14 => 0,15 => 0,20 => 0,13 => 0,0 => 0,6 => 0,28 => 0,25 => 0,
9 => 0,11 => 0,31 => 0,26 => 0,30 => 0,29 => 0,23 => 0,12 => 0}
Term1 =
#{16 => 0,18 => 0,5 => 0,19 => 0,27 => 0,10 => 0,24 => 0,4 => 0,21 => 0,
22 => 0,17 => 0,3 => 0,8 => 0,1 => 0,7 => 0,2 => 0,14 => 0,15 => 0,20 => 0,
13 => 0,0 => 0,6 => 0,28 => 0,25 => 0,9 => 0,11 => 0,
#{1 => 0,2 => 0,3 => 0,0.0 => 0} => 0,
31 => 0,26 => 0,30 => 0,29 => 0,23 => 0,12 => 0}
Binary =
<<131,116,0,0,0,33,97,0,97,0,97,1,97,0,97,2,97,0,97,3,97,0,97,4,97,0,97,5,97,0,97,6,97,0,97,7,97,0,97,8,97,0,97,9,97,0,97,10,97,0,97,11,97,0,97,12,97,0,97,13,97,0,97,14,97,0,97,15,97,0,97,16,97,0,97,17,97,0,97,18,97,0,97,19,97,0,97,20,97,0,97,21,97,0,97,22,97,0,97,23,97,0,97,24,97,0,97,25,97,0,97,26,97,0,97,27,97,0,97,28,97,0,97,29,97,0,97,30,97,0,97,31,97,0,116,0,0,0,4,70,0,0,0,0,0,0,0,0,97,0,97,1,97,0,97,2,97,0,97,3,97,0,97,0>>
===>
0/1 properties passed, 1 failed
===> Failed test cases:
prop_find_broken_maps:prop_find_broken_maps() -> false
%%% % @format
-module(prop_find_broken_maps).
-include_lib("proper/include/proper.hrl").
%% Properties
-export([
prop_find_broken_maps/0
]).
%% Type Generation API
-export([
mostly/2,
u32/0,
list_ext/0,
list_ext/1,
list_ext/2,
map_ext/0,
map_ext/2,
tuple_ext/0,
tuple_ext/1,
term_ext/0
]).
%% Helper API
-export([
external_binary_to_term/1,
external_term_ext_to_binary/1,
external_term_to_binary/1,
internal_binary_to_term/1,
internal_term_ext_to_binary/1,
internal_term_to_binary/1,
term_ext_to_term/1,
term_to_term_ext/1,
xform/3
]).
%% Records
-record(map_ext, {
arity = 0 :: u32(),
pairs = [] :: list(map_ext_pair())
}).
-record(map_ext_pair, {
key = undefined :: term_ext(),
val = undefined :: term_ext()
}).
-record(term_etf, {
enc = <<>> :: binary()
}).
%% Types
-type u32() :: 0..4294967295.
-type map_ext() :: #map_ext{}.
-type map_ext_pair() :: #map_ext_pair{}.
-type term_etf() :: #term_etf{}.
-type term_ext() :: term() | #map_ext{}.
-export_type([
u32/0,
map_ext/0,
map_ext_pair/0,
term_etf/0,
term_ext/0
]).
%% Macros
-define(DEPTH_KEY, '$term_ext_depth').
-define(DEPTH(), proper_types:parameter(?DEPTH_KEY, 1)).
-define(WITH_DEPTH(Depth, RawType), proper_types:with_parameter(?DEPTH_KEY, Depth, RawType)).
-define(WITH_NEXT_DEPTH(RawType), ?WITH_DEPTH(?DEPTH() + 1, RawType)).
-define(SMALL_TUPLE_EXT, $h).
-define(LARGE_TUPLE_EXT, $i).
-define(NIL_EXT, $j).
-define(LIST_EXT, $l).
-define(MAP_EXT, $t).
-define(VERSION_MAGIC, 131).
%%%=============================================================================
%%% Properties
%%%=============================================================================
prop_find_broken_maps() ->
?FORALL(
{_Arity, TermExt},
?LET(
Arity,
integer(32, 35),
{Arity, map_ext_gen(Arity, ?SHRINK(term_ext(), [integer()]), ?SHRINK(term_ext(), [integer()]))}
),
begin
Binary = external_term_ext_to_binary(TermExt),
Term0 = external_binary_to_term(Binary),
Term1 = term_ext_to_term(TermExt),
?WHENFAIL(whenfail(TermExt, Binary, Term0, Term1), Term0 =:= Term1)
end
).
%% @private
whenfail(TermExt, Binary, Term0, Term1) ->
io:format(
"Found encoding of MAP_EXT which decodes into a broken map.~n"
"TermExt =~n~p~n"
"Term0 =~n~p~n"
"Term1 =~n~p~n"
"Binary =~n~w~n~n",
[
TermExt, Term0, Term1, Binary
]
).
%%%=============================================================================
%%% Type Generation API functions
%%%=============================================================================
mostly(U, T) ->
frequency([
{100, U},
{1, T}
]).
u32() ->
integer(0, 16#FFFFFFFF).
list_ext_length() ->
?SIZED(
Size,
case Size of
_ when Size < 5 ->
integer(0, Size);
_ ->
mostly(integer(0, 4), integer(5, Size))
end
).
list_ext() ->
list_ext(term_ext()).
list_ext(GenElement) ->
% list_ext(GenElement, mostly(exactly([]), ?WITH_NEXT_DEPTH(GenElement))).
list_ext(GenElement, exactly([])).
list_ext(GenElement, GenTail) ->
?LET(
{_Length, ReversedElements, Tail},
?LET(
Length,
list_ext_length(),
{Length, vector(Length, ?WITH_NEXT_DEPTH(GenElement)), ?WITH_NEXT_DEPTH(GenTail)}
),
reconstruct_list(ReversedElements, Tail)
).
map_ext_arity() ->
?SIZED(
Size,
case Size of
_ when Size < 5 ->
integer(0, Size);
_ ->
mostly(integer(0, 4), integer(5, Size))
end
).
map_ext() ->
map_ext(term_ext(), term_ext()).
map_ext(GenKeyExt, GenValExt) ->
?LET(
Arity,
map_ext_arity(),
map_ext_gen(Arity, GenKeyExt, GenValExt)
).
map_ext_gen(Arity, GenKeyExt, GenValExt) ->
?LET(
Pairs,
map_ext_pairs_gen(Arity, GenKeyExt, GenValExt),
begin
Arity = length(Pairs),
return(#map_ext{arity = Arity, pairs = Pairs})
end
).
map_ext_pairs_gen(Arity, GenKeyExt, GenValExt) ->
?LET(
{KeyExts, ValExts},
{map_ext_keys_gen(Arity, GenKeyExt), vector(Arity, ?WITH_NEXT_DEPTH(GenValExt))},
lists:zipwith(
fun(KeyExt, ValExt) ->
#map_ext_pair{key = KeyExt, val = ValExt}
end,
KeyExts,
ValExts
)
).
map_ext_keys_gen(Arity, GenKeyExt) ->
map_ext_keys_gen(Arity, GenKeyExt, orddict:new()).
map_ext_keys_gen(0, _GenKeyExt, Keys) ->
[KeyExt || {_Key, KeyExt} <- Keys];
map_ext_keys_gen(Arity, GenKeyExt, Keys) ->
?LET(
{Key, KeyExt},
?SUCHTHAT(
{Key, _KeyExt},
?LET(
KeyExt,
?WITH_NEXT_DEPTH(GenKeyExt),
{term_ext_to_term(KeyExt), KeyExt}
),
not orddict:is_key(Key, Keys)
),
map_ext_keys_gen(Arity - 1, GenKeyExt, orddict:store(Key, KeyExt, Keys))
).
tuple_ext_arity() ->
?SIZED(
Size,
case Size of
_ when Size < 5 ->
integer(0, Size);
_ ->
mostly(integer(0, 4), integer(5, Size))
end
).
tuple_ext() ->
tuple_ext(term_ext()).
tuple_ext(GenElement) ->
?LET(
{_Arity, Elements},
?LET(
Arity,
tuple_ext_arity(),
{Arity, vector(Arity, ?WITH_NEXT_DEPTH(GenElement))}
),
erlang:list_to_tuple(Elements)
).
term_ext() ->
Depth = ?DEPTH(),
(is_integer(Depth) andalso Depth > 0) orelse error(badarg, [{depth, Depth}]),
% SmallTermExtWeight = 100 * Depth,
LargeTermExtWeight = 1,
frequency([
{100 * Depth, integer()},
{1, float()},
% {SmallTermExtWeight, atom()},
% {SmallTermExtWeight, bitstring()},
% {LargeTermExtWeight, ?LAZY(list_ext())},
% {LargeTermExtWeight, ?LAZY(tuple_ext())},
{LargeTermExtWeight, ?LAZY(map_ext())}
]).
%%%=============================================================================
%%% Helper API functions
%%%=============================================================================
external_binary_to_term(ExternalBinary) when is_binary(ExternalBinary) ->
erlang:binary_to_term(ExternalBinary).
external_term_ext_to_binary(TermExt) ->
InternalBinary = internal_term_ext_to_binary(TermExt),
<<?VERSION_MAGIC:8, InternalBinary/bytes>>.
external_term_to_binary(Term) ->
erlang:term_to_binary(Term, [{minor_version, 2}]).
internal_binary_to_term(InternalBinary) when is_binary(InternalBinary) ->
ExternalBinary = <<?VERSION_MAGIC:8, InternalBinary/bytes>>,
external_binary_to_term(ExternalBinary).
internal_term_ext_to_binary(TermExt) ->
{Pass1, undefined} = xform(TermExt, undefined, fun xform_term_ext_to_binary_pass1/2),
Pass2 = term_ext_to_binary(Pass1),
Pass2.
internal_term_to_binary(Term) ->
<<?VERSION_MAGIC:8, InternalBinary/bytes>> = external_term_to_binary(Term),
InternalBinary.
term_ext_to_term(TermExt) ->
{Term, undefined} = xform(TermExt, undefined, fun xform_term_ext_to_term/2),
Term.
term_to_term_ext(Term) ->
{TermExt, undefined} = xform(Term, undefined, fun xform_term_to_term_ext/2),
TermExt.
xform(T0, Acc0, Fun) when is_function(Fun, 2) ->
case Fun(T0, Acc0) of
{cont, T1, Acc1} ->
case T1 of
#term_etf{enc = _} ->
{T1, Acc1};
#map_ext_pair{key = K0, val = V0} ->
{K1, Acc2} = xform(K0, Acc1, Fun),
{V1, Acc3} = xform(V0, Acc2, Fun),
T2 = T1#map_ext_pair{key = K1, val = V1},
{T2, Acc3};
#map_ext{arity = 0} ->
{T1, Acc1};
#map_ext{arity = Arity, pairs = P0} when Arity > 0 ->
{P1, Acc2} = xform_map_ext_pairs(P0, Acc1, Fun),
T2 = T1#map_ext{pairs = P1},
{T2, Acc2};
[] ->
{T1, Acc1};
_ when is_list(T1) andalso length(T1) > 0 ->
xform_proper_list(T1, Acc1, Fun);
_ when is_list(T1) ->
xform_improper_list(T1, Acc1, Fun);
{} ->
{T1, Acc1};
_ when is_tuple(T1) ->
xform_tuple(T1, Acc1, Fun);
_ when is_map(T1) andalso map_size(T1) =:= 0 ->
{T1, Acc1};
_ when is_map(T1) ->
P0 = [#map_ext_pair{key = K, val = V} || {K, V} <- maps:to_list(T1)],
{P1, Acc2} = xform_map_ext_pairs(P0, Acc1, Fun),
P2 = [{K, V} || #map_ext_pair{key = K, val = V} <- P1],
T2 = maps:from_list(P2),
{T2, Acc2};
_ ->
{T1, Acc1}
end;
{skip, T1, Acc1} ->
{T1, Acc1}
end.
%%%-----------------------------------------------------------------------------
%%% Internal functions
%%%-----------------------------------------------------------------------------
%% @private
list_ext_elements_to_binary([Element | Elements], Acc) ->
list_ext_elements_to_binary(Elements, <<Acc/bytes, (term_ext_to_binary(Element))/bytes>>);
list_ext_elements_to_binary([], Acc) ->
Acc.
%% @private
list_ext_partition([Element | Elements], ReversedElements) ->
list_ext_partition(Elements, [Element | ReversedElements]);
list_ext_partition(Tail, ReversedElements) ->
{lists:reverse(ReversedElements), Tail}.
%% @private
list_ext_to_binary(Elements, Tail) ->
Length = length(Elements),
<<?LIST_EXT:8, Length:32, (list_ext_elements_to_binary(Elements, <<>>))/bytes, (term_ext_to_binary(Tail))/bytes>>.
%% @private
map_ext_pairs_to_binary([#map_ext_pair{key = K, val = V} | Pairs], Acc) ->
map_ext_pairs_to_binary(Pairs, <<Acc/bytes, (term_ext_to_binary(K))/bytes, (term_ext_to_binary(V))/bytes>>);
map_ext_pairs_to_binary([], Acc) ->
Acc.
%% @private
reconstruct_list([Element | Elements], List) ->
reconstruct_list(Elements, [Element | List]);
reconstruct_list([], List) ->
List.
%% @private
term_ext_to_binary(#term_etf{enc = Encoded}) ->
Encoded;
term_ext_to_binary(#map_ext{arity = Arity, pairs = Pairs}) ->
<<?MAP_EXT:8, Arity:32, (map_ext_pairs_to_binary(Pairs, <<>>))/bytes>>;
term_ext_to_binary([]) ->
<<?NIL_EXT:8>>;
term_ext_to_binary(L) when is_list(L) ->
{Elements, Tail} = list_ext_partition(L, []),
list_ext_to_binary(Elements, Tail);
term_ext_to_binary(T) when is_tuple(T) ->
tuple_ext_to_binary(T).
%% @private
tuple_ext_to_binary({}) ->
<<?SMALL_TUPLE_EXT:8, 0:8>>;
tuple_ext_to_binary(T) when is_tuple(T) andalso tuple_size(T) =< 16#FF ->
Arity = tuple_size(T),
Elements = erlang:tuple_to_list(T),
<<?SMALL_TUPLE_EXT:8, Arity:8, (list_ext_elements_to_binary(Elements, <<>>))/bytes>>;
tuple_ext_to_binary(T) when is_tuple(T) ->
Arity = tuple_size(T),
Elements = erlang:tuple_to_list(T),
<<?LARGE_TUPLE_EXT:8, Arity:32, (list_ext_elements_to_binary(Elements, <<>>))/bytes>>.
%% @private
xform_list([Element0 | List], Elements, Acc0, Fun) ->
{Element1, Acc1} = xform(Element0, Acc0, Fun),
xform_list(List, [Element1 | Elements], Acc1, Fun);
xform_list(Tail0, Elements, Acc0, Fun) ->
{Tail1, Acc1} = xform(Tail0, Acc0, Fun),
List = reconstruct_list(Elements, Tail1),
{List, Acc1}.
%% @private
xform_proper_list(ProperList, Acc, Fun) when is_list(ProperList) andalso length(ProperList) > 0 ->
xform_list(ProperList, [], Acc, Fun).
%% @private
xform_improper_list(ImproperList, Acc, Fun) when is_list(ImproperList) ->
xform_list(ImproperList, [], Acc, Fun).
%% @private
xform_tuple(T0, Acc0, Fun) ->
T1 = erlang:tuple_to_list(T0),
{T2, Acc1} = xform_proper_list(T1, Acc0, Fun),
T3 = erlang:list_to_tuple(T2),
{T3, Acc1}.
%% @private
xform_map_ext_pairs(Pairs, Acc, Fun) ->
xform_list(Pairs, [], Acc, Fun).
%% @private
xform_term_ext_to_binary_pass1(T, undefined) when is_list(T) orelse is_tuple(T) ->
{cont, T, undefined};
xform_term_ext_to_binary_pass1(T, undefined) ->
Encoded = #term_etf{enc = internal_term_to_binary(T)},
{cont, Encoded, undefined}.
%% @private
xform_term_ext_to_term(_T0 = #map_ext{pairs = Pairs0}, undefined) ->
Pairs1 = [{K, V} || #map_ext_pair{key = K, val = V} <- Pairs0],
T1 = maps:from_list(Pairs1),
{cont, T1, undefined};
xform_term_ext_to_term(T, undefined) ->
{cont, T, undefined}.
%% @private
xform_term_to_term_ext(T0, undefined) when is_map(T0) ->
Arity = maps:size(T0),
Pairs = [#map_ext_pair{key = K, val = V} || {K, V} <- maps:to_list(T0)],
T1 = #map_ext{arity = Arity, pairs = Pairs},
{cont, T1, undefined};
xform_term_to_term_ext(T, undefined) ->
{cont, T, undefined}.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment