-module(bson@decoder). -compile(no_auto_import). -export([decode/1]). -spec decode(bitstring()) -> {ok, list({binary(), bson@types:value()})} | {error, nil}. decode(Data) -> case decode_document(Data) of {ok, {document, Doc}} -> {ok, Doc}; {error, nil} -> {error, nil} end. -spec decode_document(bitstring()) -> {ok, bson@types:value()} | {error, nil}. decode_document(Data) -> Total_size = gleam@bit_string:byte_size(Data), Last_byte = gleam@bit_string:slice(Data, Total_size, -1), case Last_byte =:= {ok, <<0>>} of true -> <> = Data, case Total_size =:= Given_size of true -> case gleam@bit_string:slice(Rest, 0, (Total_size - 4) - 1) of {ok, Body} -> case decode_body(Body, []) of {ok, Body@1} -> {ok, {document, Body@1}}; {error, nil} -> {error, nil} end; {error, nil} -> {error, nil} end; false -> {error, nil} end; false -> {error, nil} end. -spec decode_body(bitstring(), list({binary(), bson@types:value()})) -> {ok, list({binary(), bson@types:value()})} | {error, nil}. decode_body(Data, Storage) -> case gleam@bit_string:byte_size(Data) =:= 0 of true -> {ok, Storage}; false -> <> = Data, Total_size = gleam@bit_string:byte_size(Data@1), case consume_till_zero(Data@1, <<>>) of {ok, Key} -> Key_size = gleam@bit_string:byte_size(Key), case gleam@bit_string:to_string(Key) of {ok, Key@1} -> case gleam@bit_string:slice( Data@1, Key_size + 1, (Total_size - Key_size) - 1 ) of {ok, Rest} -> Kind = {kind, <>}, case Kind of Kind@1 when Kind@1 =:= {kind, <<16#01>>} -> <> = Rest, decode_body( Rest@1, [{Key@1, {double, Value}} | Storage] ); Kind@2 when Kind@2 =:= {kind, <<16#07>>} -> <> = Rest, case bson@object_id:from_bit_string( Value@1 ) of {ok, Oid} -> decode_body( Rest@2, [{Key@1, {object_id, Oid}} | Storage] ); {error, nil} -> {error, nil} end; Kind@3 when Kind@3 =:= {kind, <<16#08>>} -> <> = Rest, case Value@2 of 1 -> decode_body( Rest@3, [{Key@1, {boolean, true}} | Storage] ); 0 -> decode_body( Rest@3, [{Key@1, {boolean, false}} | Storage] ); _@1 -> {error, nil} end; Kind@4 when Kind@4 =:= {kind, <<16#0A>>} -> decode_body( Rest, [{Key@1, null} | Storage] ); Kind@5 when Kind@5 =:= {kind, <<16#10>>} -> <> = Rest, decode_body( Rest@4, [{Key@1, {integer, Value@3}} | Storage] ); Kind@6 when Kind@6 =:= {kind, <<16#12>>} -> <> = Rest, decode_body( Rest@5, [{Key@1, {integer, Value@4}} | Storage] ); Kind@7 when Kind@7 =:= {kind, <<16#02>>} -> <> = Rest, case consume_till_zero(Rest@6, <<>>) of {ok, Str} -> Str_size = gleam@bit_string:byte_size( Str ), case Given_size =:= (Str_size + 1) of true -> case gleam@bit_string:to_string( Str ) of {ok, Str@1} -> case gleam@bit_string:slice( Rest@6, Str_size + 1, (gleam@bit_string:byte_size( Rest@6 ) - Str_size) - 1 ) of {ok, Rest@7} -> decode_body( Rest@7, [{Key@1, {str, Str@1}} | Storage] ); {error, nil} -> {error, nil} end; {error, nil} -> {error, nil} end; false -> {error, nil} end; {error, nil} -> {error, nil} end; Kind@8 when (Kind@8 =:= {kind, <<16#03>>}) orelse (Kind@8 =:= {kind, <<16#04>>}) -> <> = Rest, case gleam@bit_string:slice( Rest, 0, Doc_size ) of {ok, Doc} -> case decode_document(Doc) of {ok, Doc@1} -> Doc@3 = case Kind@8 of Kind@9 when Kind@9 =:= {kind, <<16#03>>} -> {ok, Doc@1}; Kind@10 when Kind@10 =:= {kind, <<16#04>>} -> case Doc@1 of {document, Doc@2} -> List = begin _pipe = Doc@2, gleam@list:map( _pipe, fun( Item ) -> {begin _pipe@1 = Item, _pipe@2 = gleam@pair:first( _pipe@1 ), gleam@int:parse( _pipe@2 ) end, begin _pipe@3 = Item, gleam@pair:second( _pipe@3 ) end} end ) end, case gleam@list:any( List, fun( Item@1 ) -> gleam@result:is_error( begin _pipe@4 = Item@1, gleam@pair:first( _pipe@4 ) end ) end ) of true -> {error, nil}; false -> {ok, {array, begin _pipe@5 = List, _pipe@8 = gleam@list:map( _pipe@5, fun( Item@2 ) -> {ok, First@1} = case begin _pipe@6 = Item@2, gleam@pair:first( _pipe@6 ) end of {ok, First} -> {ok, First}; _try -> erlang:error( #{gleam_error => assert, message => <<"Assertion pattern match failed"/utf8>>, value => _try, module => <<"bson/decoder"/utf8>>, function => <<"decode_body"/utf8>>, line => 179} ) end, {First@1, begin _pipe@7 = Item@2, gleam@pair:second( _pipe@7 ) end} end ), _pipe@11 = gleam@list:sort( _pipe@8, fun( A, B ) -> A_index = begin _pipe@9 = A, gleam@pair:first( _pipe@9 ) end, B_index = begin _pipe@10 = B, gleam@pair:first( _pipe@10 ) end, gleam@int:compare( A_index, B_index ) end ), gleam@list:map( _pipe@11, fun( Item@3 ) -> _pipe@12 = Item@3, gleam@pair:second( _pipe@12 ) end ) end}} end; _@3 -> {error, nil} end; _@4 -> {error, nil} end, case Doc@3 of {ok, Doc@4} -> case Doc_size =:= gleam@bit_string:byte_size( Rest ) of true -> {ok, [{Key@1, Doc@4} | Storage]}; false -> case gleam@bit_string:slice( Rest, Doc_size, gleam@bit_string:byte_size( Rest ) - Doc_size ) of {ok, Rest@8} -> decode_body( Rest@8, [{Key@1, Doc@4} | Storage] ); {error, nil} -> {error, nil} end end; {error, nil} -> {error, nil} end; {error, nil} -> {error, nil} end; {error, nil} -> {error, nil} end; _@5 -> {error, nil} end; {error, nil} -> {error, nil} end; {error, nil} -> {error, nil} end; {error, nil} -> {error, nil} end end. -spec consume_till_zero(bitstring(), bitstring()) -> {ok, bitstring()} | {error, nil}. consume_till_zero(Data, Storage) -> case gleam@bit_string:byte_size(Data) =:= 0 of false -> <> = Data, case Ch =:= 0 of true -> {ok, Storage}; false -> consume_till_zero( Rest, gleam@bit_string:append(Storage, <>) ) end; true -> {error, nil} end.