Last active
October 14, 2022 20:00
-
-
Save potatosalad/9066a078aee6bb80895d379c1eda804a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
%%% % @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