1%% 2%% %CopyrightBegin% 3%% 4%% Copyright Ericsson AB 2000-2016. All Rights Reserved. 5%% 6%% Licensed under the Apache License, Version 2.0 (the "License"); 7%% you may not use this file except in compliance with the License. 8%% You may obtain a copy of the License at 9%% 10%% http://www.apache.org/licenses/LICENSE-2.0 11%% 12%% Unless required by applicable law or agreed to in writing, software 13%% distributed under the License is distributed on an "AS IS" BASIS, 14%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15%% See the License for the specific language governing permissions and 16%% limitations under the License. 17%% 18%% %CopyrightEnd% 19%% 20-module(bs_match_misc_SUITE). 21 22-export([all/0, suite/0, 23 bound_var/1,bound_tail/1,t_float/1,little_float/1,sean/1, 24 kenneth/1,encode_binary/1,native/1,happi/1, 25 size_var/1,wiger/1,x0_context/1,huge_float_field/1, 26 writable_binary_matched/1,otp_7198/1,unordered_bindings/1, 27 float_middle_endian/1]). 28 29-include_lib("common_test/include/ct.hrl"). 30 31suite() -> 32 [{ct_hooks,[ts_install_cth]}, 33 {timetrap, {seconds, 10}}]. 34 35all() -> 36 [bound_var, bound_tail, t_float, little_float, sean, 37 kenneth, encode_binary, native, happi, size_var, wiger, 38 x0_context, huge_float_field, writable_binary_matched, 39 otp_7198, unordered_bindings, float_middle_endian]. 40 41 42%% Test matching of bound variables. 43bound_var(Config) when is_list(Config) -> 44 ok = bound_var(42, 13, <<42,13>>), 45 nope = bound_var(42, 13, <<42,255>>), 46 nope = bound_var(42, 13, <<154,255>>), 47 ok. 48 49bound_var(A, B, <<A:8,B:8>>) -> ok; 50bound_var(_, _, _) -> nope. 51 52%% Test matching of a bound tail. 53bound_tail(Config) when is_list(Config) -> 54 ok = bound_tail(<<>>, <<13,14>>), 55 ok = bound_tail(<<2,3>>, <<1,1,2,3>>), 56 nope = bound_tail(<<2,3>>, <<1,1,2,7>>), 57 nope = bound_tail(<<2,3>>, <<1,1,2,3,4>>), 58 nope = bound_tail(<<2,3>>, <<>>), 59 ok. 60 61bound_tail(T, <<_:16,T/binary>>) -> ok; 62bound_tail(_, _) -> nope. 63 64t_float(Config) when is_list(Config) -> 65 F = f1(), 66 G = f_one(), 67 68 G = match_float(<<63,128,0,0>>, 32, 0), 69 G = match_float(<<63,240,0,0,0,0,0,0>>, 64, 0), 70 71 fcmp(F, match_float(<<F:32/float>>, 32, 0)), 72 fcmp(F, match_float(<<F:64/float>>, 64, 0)), 73 fcmp(F, match_float(<<1:1,F:32/float,127:7>>, 32, 1)), 74 fcmp(F, match_float(<<1:1,F:64/float,127:7>>, 64, 1)), 75 fcmp(F, match_float(<<1:13,F:32/float,127:3>>, 32, 13)), 76 fcmp(F, match_float(<<1:13,F:64/float,127:3>>, 64, 13)), 77 78 {'EXIT',{{badmatch,_},_}} = (catch match_float(<<0,0>>, 16, 0)), 79 {'EXIT',{{badmatch,_},_}} = (catch match_float(<<0,0>>, 16#7fffffff, 0)), 80 81 ok. 82 83float_middle_endian(Config) when is_list(Config) -> 84 F = 9007199254740990.0, % turns to -NaN when word-swapped 85 fcmp(F, match_float(<<F:64/float>>, 64, 0)), 86 fcmp(F, match_float(<<1:1,F:64/float,127:7>>, 64, 1)), 87 fcmp(F, match_float(<<1:13,F:64/float,127:3>>, 64, 13)), 88 ok. 89 90 91fcmp(F1, F2) when (F1 - F2) / F2 < 0.0000001 -> ok. 92 93match_float(Bin0, Fsz, I) -> 94 Bin = make_sub_bin(Bin0), 95 Bsz = size(Bin) * 8, 96 Tsz = Bsz - Fsz - I, 97 <<_:I,F:Fsz/float,_:Tsz>> = Bin, 98 F. 99 100little_float(Config) when is_list(Config) -> 101 F = f2(), 102 G = f_one(), 103 104 G = match_float_little(<<0,0,0,0,0,0,240,63>>, 64, 0), 105 G = match_float_little(<<0,0,128,63>>, 32, 0), 106 107 fcmp(F, match_float_little(<<F:32/float-little>>, 32, 0)), 108 fcmp(F, match_float_little(<<F:64/float-little>>, 64, 0)), 109 fcmp(F, match_float_little(<<1:1,F:32/float-little,127:7>>, 32, 1)), 110 fcmp(F, match_float_little(<<1:1,F:64/float-little,127:7>>, 64, 1)), 111 fcmp(F, match_float_little(<<1:13,F:32/float-little,127:3>>, 32, 13)), 112 fcmp(F, match_float_little(<<1:13,F:64/float-little,127:3>>, 64, 13)), 113 114 ok. 115 116match_float_little(Bin0, Fsz, I) -> 117 Bin = make_sub_bin(Bin0), 118 Bsz = size(Bin) * 8, 119 Tsz = Bsz - Fsz - I, 120 <<_:I,F:Fsz/float-little,_:Tsz>> = Bin, 121 F. 122 123 124make_sub_bin(Bin0) -> 125 Sz = size(Bin0), 126 Bin1 = <<37,Bin0/binary,38,39>>, 127 <<_:8,Bin:Sz/binary,_:8,_:8>> = Bin1, 128 Bin. 129 130f1() -> 131 3.1415. 132 133f2() -> 134 2.7133. 135 136f_one() -> 137 1.0. 138 139sean(Config) when is_list(Config) -> 140 small = sean1(<<>>), 141 small = sean1(<<1>>), 142 small = sean1(<<1,2>>), 143 small = sean1(<<1,2,3>>), 144 large = sean1(<<1,2,3,4>>), 145 146 small = sean1(<<4>>), 147 small = sean1(<<4,5>>), 148 small = sean1(<<4,5,6>>), 149 {'EXIT',{function_clause,_}} = (catch sean1(<<4,5,6,7>>)), 150 ok. 151 152sean1(<<B/binary>>) when byte_size(B) < 4 -> small; 153sean1(<<1, _B/binary>>) -> large. 154 155kenneth(Config) when is_list(Config) -> 156 {ok,[145,148,113,129,0,0,0,0]} = 157 msisdn_internal_storage(<<145,148,113,129,0,0,0,0>>, []). 158 159msisdn_internal_storage(<<>>,MSISDN) -> 160 {ok,lists:reverse(MSISDN)}; 161msisdn_internal_storage(<<2#11111111:8,_Rest/binary>>,MSISDN) -> 162 {ok,lists:reverse(MSISDN)}; 163msisdn_internal_storage(<<2#1111:4,DigitN:4,_Rest/binary>>,MSISDN) when 164 DigitN < 10 -> 165 {ok,lists:reverse([(DigitN bor 2#11110000)|MSISDN])}; 166msisdn_internal_storage(<<DigitNplus1:4,DigitN:4,Rest/binary>>,MSISDN) when 167 DigitNplus1 < 10, 168 DigitN < 10 -> 169 NewMSISDN=[((DigitNplus1 bsl 4) bor DigitN)|MSISDN], 170 msisdn_internal_storage(Rest,NewMSISDN); 171msisdn_internal_storage(_Rest,_MSISDN) -> 172 {fault}. %% Mandatory IE incorrect 173 174encode_binary(Config) when is_list(Config) -> 175 "C2J2QiSc" = encodeBinary(<<11,98,118,66,36,156>>, []), 176 ok. 177 178encodeBinary(<<>>, Output) -> 179 lists:reverse(Output); 180encodeBinary(<<Data:1/binary>>, Output) -> 181 <<DChar1:6, DChar2:2>> = Data, 182 Char1 = getBase64Char(DChar1), 183 Char2 = getBase64Char(DChar2), 184 Char3 = "=", 185 Char4 = "=", 186 NewOutput = Char4 ++ Char3 ++ Char2 ++ Char1 ++ Output, 187 encodeBinary(<<>>, NewOutput); 188encodeBinary(<<Data:2/binary>>, Output) -> 189 <<DChar1:6, DChar2:6, DChar3:4>> = Data, 190 Char1 = getBase64Char(DChar1), 191 Char2 = getBase64Char(DChar2), 192 Char3 = getBase64Char(DChar3), 193 Char4 = "=", 194 NewOutput = Char4 ++ Char3 ++ Char2 ++ Char1 ++ Output, 195 encodeBinary(<<>>, NewOutput); 196encodeBinary(<<Data:3/binary, Rest/binary>>, Output) -> 197 <<DChar1:6, DChar2:6, DChar3:6, DChar4:6>> = Data, 198 Char1 = getBase64Char(DChar1), 199 Char2 = getBase64Char(DChar2), 200 Char3 = getBase64Char(DChar3), 201 Char4 = getBase64Char(DChar4), 202 NewOutput = Char4 ++ Char3 ++ Char2 ++ Char1 ++ Output, 203 encodeBinary(Rest, NewOutput); 204encodeBinary(_Data, _) -> 205 error. 206 207getBase64Char(0) -> "A"; 208getBase64Char(1) -> "B"; 209getBase64Char(2) -> "C"; 210getBase64Char(3) -> "D"; 211getBase64Char(4) -> "E"; 212getBase64Char(5) -> "F"; 213getBase64Char(6) -> "G"; 214getBase64Char(7) -> "H"; 215getBase64Char(8) -> "I"; 216getBase64Char(9) -> "J"; 217getBase64Char(10) -> "K"; 218getBase64Char(11) -> "L"; 219getBase64Char(12) -> "M"; 220getBase64Char(13) -> "N"; 221getBase64Char(14) -> "O"; 222getBase64Char(15) -> "P"; 223getBase64Char(16) -> "Q"; 224getBase64Char(17) -> "R"; 225getBase64Char(18) -> "S"; 226getBase64Char(19) -> "T"; 227getBase64Char(20) -> "U"; 228getBase64Char(21) -> "V"; 229getBase64Char(22) -> "W"; 230getBase64Char(23) -> "X"; 231getBase64Char(24) -> "Y"; 232getBase64Char(25) -> "Z"; 233getBase64Char(26) -> "a"; 234getBase64Char(27) -> "b"; 235getBase64Char(28) -> "c"; 236getBase64Char(29) -> "d"; 237getBase64Char(30) -> "e"; 238getBase64Char(31) -> "f"; 239getBase64Char(32) -> "g"; 240getBase64Char(33) -> "h"; 241getBase64Char(34) -> "i"; 242getBase64Char(35) -> "j"; 243getBase64Char(36) -> "k"; 244getBase64Char(37) -> "l"; 245getBase64Char(38) -> "m"; 246getBase64Char(39) -> "n"; 247getBase64Char(40) -> "o"; 248getBase64Char(41) -> "p"; 249getBase64Char(42) -> "q"; 250getBase64Char(43) -> "r"; 251getBase64Char(44) -> "s"; 252getBase64Char(45) -> "t"; 253getBase64Char(46) -> "u"; 254getBase64Char(47) -> "v"; 255getBase64Char(48) -> "w"; 256getBase64Char(49) -> "x"; 257getBase64Char(50) -> "y"; 258getBase64Char(51) -> "z"; 259getBase64Char(52) -> "0"; 260getBase64Char(53) -> "1"; 261getBase64Char(54) -> "2"; 262getBase64Char(55) -> "3"; 263getBase64Char(56) -> "4"; 264getBase64Char(57) -> "5"; 265getBase64Char(58) -> "6"; 266getBase64Char(59) -> "7"; 267getBase64Char(60) -> "8"; 268getBase64Char(61) -> "9"; 269getBase64Char(62) -> "+"; 270getBase64Char(63) -> "/"; 271getBase64Char(_Else) -> 272 %% This is an illegal input. 273% cgLogEM:log(error, ?MODULE, getBase64Char, [Else], 274% "illegal input", 275% ?LINE, version()), 276 "**". 277 278-define(M(F), <<F>> = <<F>>). 279 280native(Config) when is_list(Config) -> 281 ?M(3.14:64/native-float), 282 ?M(333:16/native), 283 ?M(38658345:32/native), 284 case <<1:16/native>> of 285 <<0,1>> -> native_big(); 286 <<1,0>> -> native_little() 287 end. 288 289native_big() -> 290 <<37.33:64/native-float>> = <<37.33:64/big-float>>, 291 <<3974:16/native-integer>> = <<3974:16/big-integer>>, 292 {comment,"Big endian"}. 293 294native_little() -> 295 <<37869.32343:64/native-float>> = <<37869.32343:64/little-float>>, 296 <<7974:16/native-integer>> = <<7974:16/little-integer>>, 297 {comment,"Little endian"}. 298 299happi(Config) when is_list(Config) -> 300 Bin = <<".123">>, 301 <<"123">> = lex_digits1(Bin, 1, []), 302 <<"123">> = lex_digits2(Bin, 1, []), 303 ok. 304 305lex_digits1(<<$., Rest/binary>>,_Val,_Acc) -> 306 Rest; 307lex_digits1(<<N, Rest/binary>>,Val, Acc) when N >= $0 , N =< $9 -> 308 lex_digits1(Rest,Val*10+dec(N),Acc); 309lex_digits1(_Other,_Val,_Acc) -> 310 not_ok. 311 312lex_digits2(<<N, Rest/binary>>,Val, Acc) when N >= $0 , N =< $9 -> 313 lex_digits2(Rest,Val*10+dec(N),Acc); 314lex_digits2(<<$., Rest/binary>>,_Val,_Acc) -> 315 Rest; 316lex_digits2(_Other,_Val,_Acc) -> 317 not_ok. 318 319dec(A) -> 320 A-$0. 321 322size_var(Config) when is_list(Config) -> 323 {<<45>>,<<>>} = split(<<1:16,45>>), 324 {<<45>>,<<46,47>>} = split(<<1:16,45,46,47>>), 325 {<<45,46>>,<<47>>} = split(<<2:16,45,46,47>>), 326 327 {<<45,46,47>>,<<48>>} = split_2(<<16:8,3:16,45,46,47,48>>), 328 329 {<<45,46>>,<<47>>} = split(2, <<2:16,45,46,47>>), 330 {'EXIT',{function_clause,_}} = (catch split(42, <<2:16,45,46,47>>)), 331 332 <<"cdef">> = skip(<<2:8,"abcdef">>), 333 334 ok. 335 336split(<<N:16,B:N/binary,T/binary>>) -> 337 {B,T}. 338 339split(N, <<N:16,B:N/binary,T/binary>>) -> 340 {B,T}. 341 342split_2(<<N0:8,N:N0,B:N/binary,T/binary>>) -> 343 {B,T}. 344 345skip(<<N:8,_:N/binary,T/binary>>) -> T. 346 347wiger(Config) when is_list(Config) -> 348 ok1 = wcheck(<<3>>), 349 ok2 = wcheck(<<1,2,3>>), 350 ok3 = wcheck(<<4>>), 351 {error,<<1,2,3,4>>} = wcheck(<<1,2,3,4>>), 352 {error,<<>>} = wcheck(<<>>), 353 ok. 354 355wcheck(<<A>>) when A==3-> 356 ok1; 357wcheck(<<_,_:2/binary>>) -> 358 ok2; 359wcheck(<<_>>) -> 360 ok3; 361wcheck(Other) -> 362 {error,Other}. 363 364%% Test that having the match context in x(0) works. 365 366x0_context(Config) when is_list(Config) -> 367 x0_0([], <<3.0:64/float,42:16,123456:32>>). 368 369x0_0(_, Bin) -> 370 <<3.0:64/float,42:16,_/binary>> = Bin, 371 x0_1([], Bin, 64, 16, 2). 372 373x0_1(_, Bin, FloatSz, IntSz, BinSz) -> 374 <<_:FloatSz/float,42:IntSz,B:BinSz/binary,C:1/binary,D/binary>> = Bin, 375 id({B,C,D}), 376 <<_:FloatSz/float,42:IntSz,B:BinSz/binary,_/binary>> = Bin, 377 x0_2([], Bin). 378 379x0_2(_, Bin) -> 380 <<_:64,0:7,42:9,_/binary>> = Bin, 381 x0_3([], Bin). 382 383x0_3(_, Bin) -> 384 case Bin of 385 <<_:72,7:8,_/binary>> -> 386 ct:fail(bs_matched_1); 387 <<_:64,0:16,_/binary>> -> 388 ct:fail(bs_matched_2); 389 <<_:64,42:16,123456:32,_/binary>> -> 390 ok 391 end. 392 393 394huge_float_field(Config) when is_list(Config) -> 395 Sz = 1 bsl 27, 396 Bin = <<0:Sz>>, 397 398 nomatch = overflow_huge_float_skip_32(Bin), 399 nomatch = overflow_huge_float_32(Bin), 400 401 ok = overflow_huge_float(Bin, lists:seq(25, 32)++lists:seq(50, 64)), 402 ok = overflow_huge_float_unit128(Bin, lists:seq(25, 32)++lists:seq(50, 64)), 403 ok. 404 405overflow_huge_float_skip_32(<<_:4294967296/float,0,_/binary>>) -> 1; % 1 bsl 32 406overflow_huge_float_skip_32(<<_:33554432/float-unit:128,0,_/binary>>) -> 2; % 1 bsl 25 407overflow_huge_float_skip_32(<<_:67108864/float-unit:64,0,_/binary>>) -> 3; % 1 bsl 26 408overflow_huge_float_skip_32(<<_:134217728/float-unit:32,0,_/binary>>) -> 4; % 1 bsl 27 409overflow_huge_float_skip_32(<<_:268435456/float-unit:16,0,_/binary>>) -> 5; % 1 bsl 28 410overflow_huge_float_skip_32(<<_:536870912/float-unit:8,0,_/binary>>) -> 6; % 1 bsl 29 411overflow_huge_float_skip_32(<<_:1073741824/float-unit:8,0,_/binary>>) -> 7; % 1 bsl 30 412overflow_huge_float_skip_32(<<_:2147483648/float-unit:8,0,_/binary>>) -> 8; % 1 bsl 31 413overflow_huge_float_skip_32(_) -> nomatch. 414 415overflow_huge_float_32(<<F:4294967296/float,_/binary>>) -> {1,F}; % 1 bsl 32 416overflow_huge_float_32(<<F:33554432/float-unit:128,0,_/binary>>) -> {2,F}; % 1 bsl 25 417overflow_huge_float_32(<<F:67108864/float-unit:128,0,_/binary>>) -> {3,F}; % 1 bsl 26 418overflow_huge_float_32(<<F:134217728/float-unit:128,0,_/binary>>) -> {4,F}; % 1 bsl 27 419overflow_huge_float_32(<<F:268435456/float-unit:128,0,_/binary>>) -> {5,F}; % 1 bsl 28 420overflow_huge_float_32(<<F:536870912/float-unit:128,0,_/binary>>) -> {6,F}; % 1 bsl 29 421overflow_huge_float_32(<<F:1073741824/float-unit:128,0,_/binary>>) -> {7,F}; % 1 bsl 30 422overflow_huge_float_32(<<F:2147483648/float-unit:128,0,_/binary>>) -> {8,F}; % 1 bsl 31 423overflow_huge_float_32(_) -> nomatch. 424 425 426overflow_huge_float(Bin, [Sz0|Sizes]) -> 427 Sz = id(1 bsl Sz0), 428 case Bin of 429 <<_:Sz/float-unit:8,0,_/binary>> -> 430 {error,Sz}; 431 _ -> 432 case Bin of 433 <<Var:Sz/float-unit:8,0,_/binary>> -> 434 {error,Sz,Var}; 435 _ -> 436 overflow_huge_float(Bin, Sizes) 437 end 438 end; 439overflow_huge_float(_, []) -> ok. 440 441overflow_huge_float_unit128(Bin, [Sz0|Sizes]) -> 442 Sz = id(1 bsl Sz0), 443 case Bin of 444 <<_:Sz/float-unit:128,0,_/binary>> -> 445 {error,Sz}; 446 _ -> 447 case Bin of 448 <<Var:Sz/float-unit:128,0,_/binary>> -> 449 {error,Sz,Var}; 450 _ -> 451 overflow_huge_float_unit128(Bin, Sizes) 452 end 453 end; 454overflow_huge_float_unit128(_, []) -> ok. 455 456 457%% 458%% Test that a writable binary can be safely matched. 459%% 460 461writable_binary_matched(Config) when is_list(Config) -> 462 WritableBin = create_writeable_binary(), 463 writable_binary_matched(WritableBin, WritableBin, 500). 464 465writable_binary_matched(<<0>>, _, N) -> 466 if N =:= 0 -> ok; 467 true -> 468 put(grow_heap, [N|get(grow_heap)]), 469 WritableBin = create_writeable_binary(), 470 writable_binary_matched(WritableBin, WritableBin, N-1) 471 end; 472writable_binary_matched(<<B:8,T/binary>>, WritableBin0, N) -> 473 WritableBin = writable_binary(WritableBin0, B), 474 writable_binary_matched(T, WritableBin, N). 475 476writable_binary(WritableBin0, B) when is_binary(WritableBin0) -> 477 %% Heavy append to force the binary to move. 478 WritableBin = <<WritableBin0/binary,0:(size(WritableBin0))/unit:8,B>>, 479 id(<<(id(0)):128/unit:8>>), 480 WritableBin. 481 482create_writeable_binary() -> 483 <<(id(<<>>))/binary,1,2,3,4,5,6,0>>. 484 485otp_7198(Config) when is_list(Config) -> 486 %% When a match context was reused, and grown at the same time to 487 %% increase the number of saved positions, the thing word was not updated 488 %% to account for the new size. Therefore, if there was a garbage collection, 489 %% the new slots would be included in the garbage collection. 490 [do_otp_7198(FillerSize) || FillerSize <- lists:seq(0, 256)], 491 ok. 492 493do_otp_7198(FillerSize) -> 494 Filler = erlang:make_tuple(FillerSize, 42), 495 {Pid,Ref} = spawn_monitor(fun() -> do_otp_7198_test(Filler) end), 496 receive 497 {'DOWN',Ref,process,Pid,normal} -> 498 ok; 499 {'DOWN',Ref,process,Pid,Reason} -> 500 ct:fail("unexpected: ~p", [Reason]) 501 end. 502 503do_otp_7198_test(_) -> 504 [{'KEYWORD',114}, 505 {'KEYWORD',101}, 506 {'KEYWORD',103}, 507 {'KEYWORD',105}, 508 {'KEYWORD',111}, 509 {'FIELD',110}, 510 {'KEYWORD',119}, 511 {'KEYWORD',104}, 512 {'KEYWORD',97}, 513 {'KEYWORD',116}, 514 {'KEYWORD',101}, 515 {'KEYWORD',118}, 516 {'KEYWORD',101}, 517 {'KEYWORD',114}, 518 '$thats_all_folks$'] = otp_7198_scan(<<"region:whatever">>, []). 519 520 521otp_7198_scan(<<>>, TokAcc) -> 522 lists:reverse(['$thats_all_folks$' | TokAcc]); 523 524otp_7198_scan(<<D, Z, Rest/binary>>, TokAcc) when 525 (D =:= $D orelse D =:= $d) and 526 ((Z =:= $\s) or (Z =:= $() or (Z =:= $))) -> 527 otp_7198_scan(<<Z, Rest/binary>>, ['AND' | TokAcc]); 528 529otp_7198_scan(<<D>>, TokAcc) when 530 (D =:= $D) or (D =:= $d) -> 531 otp_7198_scan(<<>>, ['AND' | TokAcc]); 532 533otp_7198_scan(<<N, Z, Rest/binary>>, TokAcc) when 534 (N =:= $N orelse N =:= $n) and 535 ((Z =:= $\s) or (Z =:= $() or (Z =:= $))) -> 536 otp_7198_scan(<<Z, Rest/binary>>, ['NOT' | TokAcc]); 537 538otp_7198_scan(<<C, Rest/binary>>, TokAcc) when 539 (C >= $A) and (C =< $Z); 540 (C >= $a) and (C =< $z); 541 (C >= $0) and (C =< $9) -> 542 case Rest of 543 <<$:, R/binary>> -> 544 otp_7198_scan(R, [{'FIELD', C} | TokAcc]); 545 _ -> 546 otp_7198_scan(Rest, [{'KEYWORD', C} | TokAcc]) 547 end. 548 549unordered_bindings(Config) when is_list(Config) -> 550 {<<1,2,3,4>>,<<42,42>>,<<3,3,3>>} = 551 unordered_bindings(4, 2, 3, <<1,2,3,4, 42,42, 3,3,3, 3>>), 552 ok. 553 554unordered_bindings(CompressedLength, HashSize, PadLength, T) -> 555 <<Content:CompressedLength/binary,Mac:HashSize/binary, 556 Padding:PadLength/binary,PadLength>> = T, 557 {Content,Mac,Padding}. 558 559 560id(I) -> I. 561