-module(lightspeed@diff). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/lightspeed/diff.gleam"). -export([target/1, operation/1, carries_html/1, slot/2, keyed_node/2, keyed_patch_plan/3, encode_stream/1, encode/1, decode_stream/1, decode/1, decode_error_to_string/1]). -export_type([dynamic_slot/0, keyed_node/0, patch/0, decode_error/0]). -if(?OTP_RELEASE >= 27). -define(MODULEDOC(Str), -moduledoc(Str)). -define(DOC(Str), -doc(Str)). -else. -define(MODULEDOC(Str), -compile([])). -define(DOC(Str), -compile([])). -endif. ?MODULEDOC(" Patch model and codec for rendered updates.\n"). -type dynamic_slot() :: {dynamic_slot, binary(), binary()}. -type keyed_node() :: {keyed_node, binary(), binary()}. -type patch() :: {replace, binary(), binary()} | {append, binary(), binary()} | {prepend, binary(), binary()} | {remove, binary()} | {replace_segments, binary(), binary(), binary(), list(dynamic_slot())} | {update_segments, binary(), binary(), list(dynamic_slot())} | {upsert_keyed, binary(), binary(), binary()} | {remove_keyed, binary(), binary()} | {reorder_keyed, binary(), list(binary())}. -type decode_error() :: empty_payload | {unknown_payload_tag, binary()} | {bad_field_count, binary(), integer(), integer()} | {invalid_integer, binary()} | {unsupported_version, integer()} | {missing_dictionary_entry, integer()} | {malformed_operation, binary()} | invalid_escape_sequence. -file("src/lightspeed/diff.gleam", 54). ?DOC(" Return the target selector or id for a patch.\n"). -spec target(patch()) -> binary(). target(Patch) -> case Patch of {replace, Target, _} -> Target; {append, Target@1, _} -> Target@1; {prepend, Target@2, _} -> Target@2; {remove, Target@3} -> Target@3; {replace_segments, Target@4, _, _, _} -> Target@4; {update_segments, Target@5, _, _} -> Target@5; {upsert_keyed, Target@6, _, _} -> Target@6; {remove_keyed, Target@7, _} -> Target@7; {reorder_keyed, Target@8, _} -> Target@8 end. -file("src/lightspeed/diff.gleam", 69). ?DOC(" Return the patch operation name.\n"). -spec operation(patch()) -> binary(). operation(Patch) -> case Patch of {replace, _, _} -> <<"replace"/utf8>>; {append, _, _} -> <<"append"/utf8>>; {prepend, _, _} -> <<"prepend"/utf8>>; {remove, _} -> <<"remove"/utf8>>; {replace_segments, _, _, _, _} -> <<"replace_segments"/utf8>>; {update_segments, _, _, _} -> <<"update_segments"/utf8>>; {upsert_keyed, _, _, _} -> <<"upsert_keyed"/utf8>>; {remove_keyed, _, _} -> <<"remove_keyed"/utf8>>; {reorder_keyed, _, _} -> <<"reorder_keyed"/utf8>> end. -file("src/lightspeed/diff.gleam", 84). ?DOC(" True when a patch carries HTML content.\n"). -spec carries_html(patch()) -> boolean(). carries_html(Patch) -> case Patch of {remove, _} -> false; {update_segments, _, _, _} -> false; {remove_keyed, _, _} -> false; {reorder_keyed, _, _} -> false; _ -> true end. -file("src/lightspeed/diff.gleam", 95). ?DOC(" Build one dynamic slot value.\n"). -spec slot(binary(), binary()) -> dynamic_slot(). slot(Name, Value) -> {dynamic_slot, Name, Value}. -file("src/lightspeed/diff.gleam", 100). ?DOC(" Build one keyed node.\n"). -spec keyed_node(binary(), binary()) -> keyed_node(). keyed_node(Key, Html) -> {keyed_node, Key, Html}. -file("src/lightspeed/diff.gleam", 238). -spec keyed_lookup(list(keyed_node()), binary()) -> {ok, binary()} | {error, nil}. keyed_lookup(Nodes, Key) -> case Nodes of [] -> {error, nil}; [{keyed_node, Node_key, Html} | Rest] -> case Node_key =:= Key of true -> {ok, Html}; false -> keyed_lookup(Rest, Key) end end. -file("src/lightspeed/diff.gleam", 220). -spec keyed_removals(binary(), list(keyed_node()), list(keyed_node())) -> list(patch()). keyed_removals(Target, Previous, Current) -> case Previous of [] -> []; [{keyed_node, Key, _} | Rest] -> case keyed_lookup(Current, Key) of {ok, _} -> keyed_removals(Target, Rest, Current); {error, nil} -> [{remove_keyed, Target, Key} | keyed_removals(Target, Rest, Current)] end end. -file("src/lightspeed/diff.gleam", 194). -spec keyed_upserts(binary(), list(keyed_node()), list(keyed_node())) -> list(patch()). keyed_upserts(Target, Previous, Current) -> case Current of [] -> []; [{keyed_node, Key, Html} | Rest] -> case keyed_lookup(Previous, Key) of {ok, Previous_html} -> case Previous_html =:= Html of true -> keyed_upserts(Target, Previous, Rest); false -> [{upsert_keyed, Target, Key, Html} | keyed_upserts(Target, Previous, Rest)] end; {error, nil} -> [{upsert_keyed, Target, Key, Html} | keyed_upserts(Target, Previous, Rest)] end end. -file("src/lightspeed/diff.gleam", 864). -spec concat(list(FLQ), list(FLQ)) -> list(FLQ). concat(Left, Right) -> case Left of [] -> Right; [Entry | Rest] -> [Entry | concat(Rest, Right)] end. -file("src/lightspeed/diff.gleam", 105). ?DOC(" Build a keyed update plan from previous and current collections.\n"). -spec keyed_patch_plan(binary(), list(keyed_node()), list(keyed_node())) -> list(patch()). keyed_patch_plan(Target, Previous, Current) -> concat( keyed_upserts(Target, Previous, Current), keyed_removals(Target, Previous, Current) ). -file("src/lightspeed/diff.gleam", 903). -spec escape_chars(list(binary()), binary()) -> binary(). escape_chars(Chars, Acc) -> case Chars of [] -> Acc; [Char | Rest] -> case Char of <<"\\"/utf8>> -> escape_chars(Rest, <>); <<"|"/utf8>> -> escape_chars(Rest, <>); _ -> escape_chars(Rest, <>) end end. -file("src/lightspeed/diff.gleam", 899). -spec escape_field(binary()) -> binary(). escape_field(Value) -> escape_chars(gleam@string:to_graphemes(Value), <<""/utf8>>). -file("src/lightspeed/diff.gleam", 892). -spec join_fields_loop(list(binary()), binary()) -> binary(). join_fields_loop(Fields, Acc) -> case Fields of [] -> Acc; [Field | Rest] -> join_fields_loop( Rest, <<<>/binary, (escape_field(Field))/binary>> ) end. -file("src/lightspeed/diff.gleam", 885). -spec join_fields(list(binary())) -> binary(). join_fields(Fields) -> case Fields of [] -> <<""/utf8>>; [Field | Rest] -> join_fields_loop(Rest, escape_field(Field)) end. -file("src/lightspeed/diff.gleam", 443). -spec index_of(list(binary()), binary(), integer()) -> integer(). index_of(Values, Target, Index) -> case Values of [] -> 0; [Value | Rest] -> case Value =:= Target of true -> Index; false -> index_of(Rest, Target, Index + 1) end end. -file("src/lightspeed/diff.gleam", 439). -spec encode_index(list(binary()), binary()) -> binary(). encode_index(Dictionary, Value) -> erlang:integer_to_binary(index_of(Dictionary, Value, 0)). -file("src/lightspeed/diff.gleam", 408). -spec encode_key_tokens(list(binary()), list(binary()), list(binary())) -> list(binary()). encode_key_tokens(Keys, Dictionary, Tokens_rev) -> case Keys of [] -> lists:reverse(Tokens_rev); [Key | Rest] -> encode_key_tokens( Rest, Dictionary, [encode_index(Dictionary, Key) | Tokens_rev] ) end. -file("src/lightspeed/diff.gleam", 878). -spec join_tokens_loop(list(binary()), binary()) -> binary(). join_tokens_loop(Tokens, Acc) -> case Tokens of [] -> Acc; [Token | Rest] -> join_tokens_loop( Rest, <<<>/binary, Token/binary>> ) end. -file("src/lightspeed/diff.gleam", 871). -spec join_tokens(list(binary())) -> binary(). join_tokens(Tokens) -> case Tokens of [] -> <<""/utf8>>; [Token | Rest] -> join_tokens_loop(Rest, Token) end. -file("src/lightspeed/diff.gleam", 423). -spec encode_dynamic_slot_tokens( list(dynamic_slot()), list(binary()), list(binary()) ) -> list(binary()). encode_dynamic_slot_tokens(Dynamic_slots, Dictionary, Tokens_rev) -> case Dynamic_slots of [] -> lists:reverse(Tokens_rev); [{dynamic_slot, Name, Value} | Rest] -> encode_dynamic_slot_tokens( Rest, Dictionary, [encode_index(Dictionary, Value), encode_index(Dictionary, Name) | Tokens_rev] ) end. -file("src/lightspeed/diff.gleam", 333). -spec encode_operation(patch(), list(binary())) -> binary(). encode_operation(Patch, Dictionary) -> case Patch of {replace, Target, Html} -> join_tokens( [<<"r"/utf8>>, encode_index(Dictionary, Target), encode_index(Dictionary, Html)] ); {append, Target@1, Html@1} -> join_tokens( [<<"a"/utf8>>, encode_index(Dictionary, Target@1), encode_index(Dictionary, Html@1)] ); {prepend, Target@2, Html@2} -> join_tokens( [<<"p"/utf8>>, encode_index(Dictionary, Target@2), encode_index(Dictionary, Html@2)] ); {remove, Target@3} -> join_tokens([<<"x"/utf8>>, encode_index(Dictionary, Target@3)]); {replace_segments, Target@4, Fingerprint, Static_html, Dynamic_slots} -> join_tokens( concat( [<<"s"/utf8>>, encode_index(Dictionary, Target@4), encode_index(Dictionary, Fingerprint), encode_index(Dictionary, Static_html), erlang:integer_to_binary(erlang:length(Dynamic_slots))], encode_dynamic_slot_tokens(Dynamic_slots, Dictionary, []) ) ); {update_segments, Target@5, Fingerprint@1, Dynamic_slots@1} -> join_tokens( concat( [<<"u"/utf8>>, encode_index(Dictionary, Target@5), encode_index(Dictionary, Fingerprint@1), erlang:integer_to_binary(erlang:length(Dynamic_slots@1))], encode_dynamic_slot_tokens(Dynamic_slots@1, Dictionary, []) ) ); {upsert_keyed, Target@6, Key, Html@3} -> join_tokens( [<<"k"/utf8>>, encode_index(Dictionary, Target@6), encode_index(Dictionary, Key), encode_index(Dictionary, Html@3)] ); {remove_keyed, Target@7, Key@1} -> join_tokens( [<<"q"/utf8>>, encode_index(Dictionary, Target@7), encode_index(Dictionary, Key@1)] ); {reorder_keyed, Target@8, Keys} -> join_tokens( concat( [<<"o"/utf8>>, encode_index(Dictionary, Target@8), erlang:integer_to_binary(erlang:length(Keys))], encode_key_tokens(Keys, Dictionary, []) ) ) end. -file("src/lightspeed/diff.gleam", 318). -spec encode_operations(list(patch()), list(binary()), list(binary())) -> list(binary()). encode_operations(Patches, Dictionary, Operation_fields_rev) -> case Patches of [] -> lists:reverse(Operation_fields_rev); [Patch | Rest] -> encode_operations( Rest, Dictionary, [encode_operation(Patch, Dictionary) | Operation_fields_rev] ) end. -file("src/lightspeed/diff.gleam", 279). -spec dynamic_slot_strings(list(dynamic_slot())) -> list(binary()). dynamic_slot_strings(Dynamic_slots) -> case Dynamic_slots of [] -> []; [{dynamic_slot, Name, Value} | Rest] -> [Name, Value | dynamic_slot_strings(Rest)] end. -file("src/lightspeed/diff.gleam", 260). -spec patch_strings(patch()) -> list(binary()). patch_strings(Patch) -> case Patch of {replace, Target, Html} -> [Target, Html]; {append, Target@1, Html@1} -> [Target@1, Html@1]; {prepend, Target@2, Html@2} -> [Target@2, Html@2]; {remove, Target@3} -> [Target@3]; {replace_segments, Target@4, Fingerprint, Static_html, Dynamic_slots} -> concat( [Target@4, Fingerprint, Static_html], dynamic_slot_strings(Dynamic_slots) ); {update_segments, Target@5, Fingerprint@1, Dynamic_slots@1} -> concat( [Target@5, Fingerprint@1], dynamic_slot_strings(Dynamic_slots@1) ); {upsert_keyed, Target@6, Key, Html@3} -> [Target@6, Key, Html@3]; {remove_keyed, Target@7, Key@1} -> [Target@7, Key@1]; {reorder_keyed, Target@8, Keys} -> concat([Target@8], Keys) end. -file("src/lightspeed/diff.gleam", 307). -spec contains_string(list(binary()), binary()) -> boolean(). contains_string(Values, Target) -> case Values of [] -> false; [Value | Rest] -> case Value =:= Target of true -> true; false -> contains_string(Rest, Target) end end. -file("src/lightspeed/diff.gleam", 300). -spec add_unique(list(binary()), binary()) -> list(binary()). add_unique(Dictionary, Value) -> case contains_string(Dictionary, Value) of true -> Dictionary; false -> concat(Dictionary, [Value]) end. -file("src/lightspeed/diff.gleam", 290). -spec add_all_unique(list(binary()), list(binary())) -> list(binary()). add_all_unique(Dictionary, Values) -> case Values of [] -> Dictionary; [Value | Rest] -> add_all_unique(add_unique(Dictionary, Value), Rest) end. -file("src/lightspeed/diff.gleam", 249). -spec build_dictionary(list(patch()), list(binary())) -> list(binary()). build_dictionary(Patches, Dictionary) -> case Patches of [] -> Dictionary; [Patch | Rest] -> build_dictionary( Rest, add_all_unique(Dictionary, patch_strings(Patch)) ) end. -file("src/lightspeed/diff.gleam", 122). ?DOC(" Encode a patch stream with dictionary compression.\n"). -spec encode_stream(list(patch())) -> binary(). encode_stream(Patches) -> Dictionary = build_dictionary(Patches, []), Operation_fields = encode_operations(Patches, Dictionary, []), Fields = concat( concat( concat( [<<"ps"/utf8>>, erlang:integer_to_binary(1), erlang:integer_to_binary(erlang:length(Dictionary))], Dictionary ), [erlang:integer_to_binary(erlang:length(Operation_fields))] ), Operation_fields ), join_fields(Fields). -file("src/lightspeed/diff.gleam", 117). ?DOC(" Encode one patch into a versioned compressed stream.\n"). -spec encode(patch()) -> binary(). encode(Patch) -> encode_stream([Patch]). -file("src/lightspeed/diff.gleam", 839). -spec dictionary_value(list(binary()), integer()) -> {ok, binary()} | {error, decode_error()}. dictionary_value(Dictionary, Index) -> case Index < 0 of true -> {error, {missing_dictionary_entry, Index}}; false -> case Dictionary of [] -> {error, {missing_dictionary_entry, Index}}; [Entry | Rest] -> case Index =:= 0 of true -> {ok, Entry}; false -> dictionary_value(Rest, Index - 1) end end end. -file("src/lightspeed/diff.gleam", 857). -spec parse_int(binary()) -> {ok, integer()} | {error, decode_error()}. parse_int(Value) -> case gleam_stdlib:parse_int(Value) of {ok, Parsed} -> {ok, Parsed}; {error, _} -> {error, {invalid_integer, Value}} end. -file("src/lightspeed/diff.gleam", 829). -spec decode_dictionary_value(binary(), list(binary())) -> {ok, binary()} | {error, decode_error()}. decode_dictionary_value(Index_text, Dictionary) -> case parse_int(Index_text) of {error, Error} -> {error, Error}; {ok, Index} -> dictionary_value(Dictionary, Index) end. -file("src/lightspeed/diff.gleam", 803). -spec decode_dynamic_slot_pairs( list(binary()), list(binary()), list(dynamic_slot()) ) -> {ok, list(dynamic_slot())} | {error, decode_error()}. decode_dynamic_slot_pairs(Slot_tokens, Dictionary, Dynamic_slots_rev) -> case Slot_tokens of [] -> {ok, lists:reverse(Dynamic_slots_rev)}; [Name_index, Value_index | Rest] -> case decode_dictionary_value(Name_index, Dictionary) of {error, Error} -> {error, Error}; {ok, Name} -> case decode_dictionary_value(Value_index, Dictionary) of {error, Error@1} -> {error, Error@1}; {ok, Value} -> decode_dynamic_slot_pairs( Rest, Dictionary, [{dynamic_slot, Name, Value} | Dynamic_slots_rev] ) end end; _ -> {error, {malformed_operation, <<"dynamic_slot_pair"/utf8>>}} end. -file("src/lightspeed/diff.gleam", 783). -spec decode_dynamic_slots(binary(), list(binary()), list(binary())) -> {ok, list(dynamic_slot())} | {error, decode_error()}. decode_dynamic_slots(Slot_count_text, Slot_tokens, Dictionary) -> case parse_int(Slot_count_text) of {error, Error} -> {error, Error}; {ok, Slot_count} -> case erlang:length(Slot_tokens) =:= (Slot_count * 2) of false -> {error, {bad_field_count, <<"dynamic_slots"/utf8>>, Slot_count * 2, erlang:length(Slot_tokens)}}; true -> decode_dynamic_slot_pairs(Slot_tokens, Dictionary, []) end end. -file("src/lightspeed/diff.gleam", 757). -spec decode_update_segment_patch( binary(), binary(), binary(), list(binary()), list(binary()) ) -> {ok, patch()} | {error, decode_error()}. decode_update_segment_patch( Target_index, Fingerprint_index, Slot_count_text, Slot_tokens, Dictionary ) -> case decode_dictionary_value(Target_index, Dictionary) of {error, Error} -> {error, Error}; {ok, Target} -> case decode_dictionary_value(Fingerprint_index, Dictionary) of {error, Error@1} -> {error, Error@1}; {ok, Fingerprint} -> case decode_dynamic_slots( Slot_count_text, Slot_tokens, Dictionary ) of {error, Error@2} -> {error, Error@2}; {ok, Dynamic_slots} -> {ok, {update_segments, Target, Fingerprint, Dynamic_slots}} end end end. -file("src/lightspeed/diff.gleam", 723). -spec decode_segment_patch( binary(), binary(), binary(), binary(), list(binary()), list(binary()) ) -> {ok, patch()} | {error, decode_error()}. decode_segment_patch( Target_index, Fingerprint_index, Static_index, Slot_count_text, Slot_tokens, Dictionary ) -> case decode_dictionary_value(Target_index, Dictionary) of {error, Error} -> {error, Error}; {ok, Target} -> case decode_dictionary_value(Fingerprint_index, Dictionary) of {error, Error@1} -> {error, Error@1}; {ok, Fingerprint} -> case decode_dictionary_value(Static_index, Dictionary) of {error, Error@2} -> {error, Error@2}; {ok, Static_html} -> case decode_dynamic_slots( Slot_count_text, Slot_tokens, Dictionary ) of {error, Error@3} -> {error, Error@3}; {ok, Dynamic_slots} -> {ok, {replace_segments, Target, Fingerprint, Static_html, Dynamic_slots}} end end end end. -file("src/lightspeed/diff.gleam", 679). -spec decode_key_indexes(list(binary()), list(binary()), list(binary())) -> {ok, list(binary())} | {error, decode_error()}. decode_key_indexes(Key_indexes, Dictionary, Keys_rev) -> case Key_indexes of [] -> {ok, lists:reverse(Keys_rev)}; [Key_index | Rest] -> case decode_dictionary_value(Key_index, Dictionary) of {error, Error} -> {error, Error}; {ok, Key} -> decode_key_indexes(Rest, Dictionary, [Key | Keys_rev]) end end. -file("src/lightspeed/diff.gleam", 650). -spec decode_reorder_patch(binary(), binary(), list(binary()), list(binary())) -> {ok, patch()} | {error, decode_error()}. decode_reorder_patch(Target_index, Key_count_text, Key_indexes, Dictionary) -> case decode_dictionary_value(Target_index, Dictionary) of {error, Error} -> {error, Error}; {ok, Target} -> case parse_int(Key_count_text) of {error, Error@1} -> {error, Error@1}; {ok, Key_count} -> case erlang:length(Key_indexes) =:= Key_count of false -> {error, {bad_field_count, <<"reorder_keyed_keys"/utf8>>, Key_count, erlang:length(Key_indexes)}}; true -> case decode_key_indexes(Key_indexes, Dictionary, []) of {error, Error@2} -> {error, Error@2}; {ok, Keys} -> {ok, {reorder_keyed, Target, Keys}} end end end end. -file("src/lightspeed/diff.gleam", 712). -spec map_patch_name_error({ok, patch()} | {error, decode_error()}, binary()) -> {ok, patch()} | {error, decode_error()}. map_patch_name_error(Result, Patch_name) -> case Result of {ok, Patch} -> {ok, Patch}; {error, {malformed_operation, _}} -> {error, {malformed_operation, Patch_name}}; {error, Error} -> {error, Error} end. -file("src/lightspeed/diff.gleam", 694). -spec decode_binary_patch( binary(), binary(), binary(), list(binary()), fun((binary(), binary()) -> patch()) ) -> {ok, patch()} | {error, decode_error()}. decode_binary_patch( Patch_name, Target_index, Html_index, Dictionary, Constructor ) -> _pipe = case decode_dictionary_value(Target_index, Dictionary) of {error, Error} -> {error, Error}; {ok, Target} -> case decode_dictionary_value(Html_index, Dictionary) of {error, Error@1} -> {error, Error@1}; {ok, Html} -> {ok, Constructor(Target, Html)} end end, map_patch_name_error(_pipe, Patch_name). -file("src/lightspeed/diff.gleam", 552). -spec decode_operation(binary(), list(binary())) -> {ok, patch()} | {error, decode_error()}. decode_operation(Operation_field, Dictionary) -> Tokens = gleam@string:split(Operation_field, <<","/utf8>>), case Tokens of [<<"r"/utf8>>, Target_index, Html_index] -> decode_binary_patch( <<"replace"/utf8>>, Target_index, Html_index, Dictionary, fun(Field@0, Field@1) -> {replace, Field@0, Field@1} end ); [<<"a"/utf8>>, Target_index@1, Html_index@1] -> decode_binary_patch( <<"append"/utf8>>, Target_index@1, Html_index@1, Dictionary, fun(Field@0, Field@1) -> {append, Field@0, Field@1} end ); [<<"p"/utf8>>, Target_index@2, Html_index@2] -> decode_binary_patch( <<"prepend"/utf8>>, Target_index@2, Html_index@2, Dictionary, fun(Field@0, Field@1) -> {prepend, Field@0, Field@1} end ); [<<"x"/utf8>>, Target_index@3] -> case decode_dictionary_value(Target_index@3, Dictionary) of {error, Error} -> {error, Error}; {ok, Target} -> {ok, {remove, Target}} end; [<<"k"/utf8>>, Target_index@4, Key_index, Html_index@3] -> case decode_dictionary_value(Target_index@4, Dictionary) of {error, Error@1} -> {error, Error@1}; {ok, Target@1} -> case decode_dictionary_value(Key_index, Dictionary) of {error, Error@2} -> {error, Error@2}; {ok, Key} -> case decode_dictionary_value( Html_index@3, Dictionary ) of {error, Error@3} -> {error, Error@3}; {ok, Html} -> {ok, {upsert_keyed, Target@1, Key, Html}} end end end; [<<"q"/utf8>>, Target_index@5, Key_index@1] -> case decode_dictionary_value(Target_index@5, Dictionary) of {error, Error@4} -> {error, Error@4}; {ok, Target@2} -> case decode_dictionary_value(Key_index@1, Dictionary) of {error, Error@5} -> {error, Error@5}; {ok, Key@1} -> {ok, {remove_keyed, Target@2, Key@1}} end end; [<<"o"/utf8>>, Target_index@6, Key_count | Key_indexes] -> decode_reorder_patch( Target_index@6, Key_count, Key_indexes, Dictionary ); [<<"s"/utf8>>, Target_index@7, Fingerprint_index, Static_index, Slot_count | Slot_tokens] -> decode_segment_patch( Target_index@7, Fingerprint_index, Static_index, Slot_count, Slot_tokens, Dictionary ); [<<"u"/utf8>>, Target_index@8, Fingerprint_index@1, Slot_count@1 | Slot_tokens@1] -> decode_update_segment_patch( Target_index@8, Fingerprint_index@1, Slot_count@1, Slot_tokens@1, Dictionary ); _ -> {error, {malformed_operation, Operation_field}} end. -file("src/lightspeed/diff.gleam", 537). -spec decode_operations(list(binary()), list(binary()), list(patch())) -> {ok, list(patch())} | {error, decode_error()}. decode_operations(Operation_fields, Dictionary, Patches_rev) -> case Operation_fields of [] -> {ok, lists:reverse(Patches_rev)}; [Operation_field | Rest] -> case decode_operation(Operation_field, Dictionary) of {error, Error} -> {error, Error}; {ok, Patch} -> decode_operations(Rest, Dictionary, [Patch | Patches_rev]) end end. -file("src/lightspeed/diff.gleam", 518). -spec split_n(list(binary()), integer(), list(binary())) -> {ok, {list(binary()), list(binary())}} | {error, decode_error()}. split_n(Values, Count, Acc_rev) -> case Count < 0 of true -> {error, {malformed_operation, <<"negative_count"/utf8>>}}; false -> case Count of 0 -> {ok, {lists:reverse(Acc_rev), Values}}; _ -> case Values of [] -> {error, {malformed_operation, <<"insufficient_fields"/utf8>>}}; [Value | Rest] -> split_n(Rest, Count - 1, [Value | Acc_rev]) end end end. -file("src/lightspeed/diff.gleam", 481). -spec decode_dictionary_and_operations(binary(), list(binary())) -> {ok, list(patch())} | {error, decode_error()}. decode_dictionary_and_operations(Dictionary_count_text, Rest_fields) -> case parse_int(Dictionary_count_text) of {error, Error} -> {error, Error}; {ok, Dictionary_count} -> case split_n(Rest_fields, Dictionary_count, []) of {error, Error@1} -> {error, Error@1}; {ok, {Dictionary, Operation_count_and_fields}} -> case Operation_count_and_fields of [Operation_count_text | Operation_fields] -> case parse_int(Operation_count_text) of {error, Error@2} -> {error, Error@2}; {ok, Operation_count} -> case erlang:length(Operation_fields) =:= Operation_count of false -> {error, {bad_field_count, <<"operation_fields"/utf8>>, Operation_count, erlang:length( Operation_fields )}}; true -> decode_operations( Operation_fields, Dictionary, [] ) end end; _ -> {error, {bad_field_count, <<"operation_count"/utf8>>, 1, 0}} end end end. -file("src/lightspeed/diff.gleam", 454). -spec decode_fields(list(binary())) -> {ok, list(patch())} | {error, decode_error()}. decode_fields(Fields) -> case Fields of [Tag, Version_text, Dictionary_count_text | Rest] -> case Tag of <<"ps"/utf8>> -> case parse_int(Version_text) of {error, Error} -> {error, Error}; {ok, Version} -> case Version =:= 1 of false -> {error, {unsupported_version, Version}}; true -> decode_dictionary_and_operations( Dictionary_count_text, Rest ) end end; _ -> {error, {unknown_payload_tag, Tag}} end; _ -> {error, {bad_field_count, <<"stream_header"/utf8>>, 3, erlang:length(Fields)}} end. -file("src/lightspeed/diff.gleam", 919). -spec split_chars(list(binary()), binary(), list(binary()), boolean()) -> {ok, list(binary())} | {error, decode_error()}. split_chars(Chars, Current, Fields_rev, Escaped) -> case Chars of [] -> case Escaped of true -> {error, invalid_escape_sequence}; false -> {ok, lists:reverse([Current | Fields_rev])} end; [Char | Rest] -> case Escaped of true -> split_chars( Rest, <>, Fields_rev, false ); false -> case Char of <<"\\"/utf8>> -> split_chars(Rest, Current, Fields_rev, true); <<"|"/utf8>> -> split_chars( Rest, <<""/utf8>>, [Current | Fields_rev], false ); _ -> split_chars( Rest, <>, Fields_rev, false ) end end end. -file("src/lightspeed/diff.gleam", 915). -spec split_fields(binary()) -> {ok, list(binary())} | {error, decode_error()}. split_fields(Payload) -> split_chars(gleam@string:to_graphemes(Payload), <<""/utf8>>, [], false). -file("src/lightspeed/diff.gleam", 161). ?DOC(" Decode a patch stream.\n"). -spec decode_stream(binary()) -> {ok, list(patch())} | {error, decode_error()}. decode_stream(Payload) -> case Payload of <<""/utf8>> -> {error, empty_payload}; _ -> case split_fields(Payload) of {error, Error} -> {error, Error}; {ok, Fields} -> decode_fields(Fields) end end. -file("src/lightspeed/diff.gleam", 146). ?DOC(" Decode one patch from a versioned compressed stream.\n"). -spec decode(binary()) -> {ok, patch()} | {error, decode_error()}. decode(Payload) -> case decode_stream(Payload) of {error, Error} -> {error, Error}; {ok, Patches} -> case Patches of [Patch] -> {ok, Patch}; _ -> {error, {malformed_operation, <<"expected_single_patch:"/utf8, (erlang:integer_to_binary( erlang:length(Patches) ))/binary>>}} end end. -file("src/lightspeed/diff.gleam", 173). ?DOC(" Stable error labels for logs and adapter failures.\n"). -spec decode_error_to_string(decode_error()) -> binary(). decode_error_to_string(Error) -> case Error of empty_payload -> <<"empty_payload"/utf8>>; {unknown_payload_tag, Tag} -> <<"unknown_payload_tag:"/utf8, Tag/binary>>; {bad_field_count, Stage, Expected, Actual} -> <<<<<<<<<<"bad_field_count:"/utf8, Stage/binary>>/binary, ":"/utf8>>/binary, (erlang:integer_to_binary(Expected))/binary>>/binary, ":"/utf8>>/binary, (erlang:integer_to_binary(Actual))/binary>>; {invalid_integer, Value} -> <<"invalid_integer:"/utf8, Value/binary>>; {unsupported_version, Version} -> <<"unsupported_version:"/utf8, (erlang:integer_to_binary(Version))/binary>>; {missing_dictionary_entry, Index} -> <<"missing_dictionary_entry:"/utf8, (erlang:integer_to_binary(Index))/binary>>; {malformed_operation, Reason} -> <<"malformed_operation:"/utf8, Reason/binary>>; invalid_escape_sequence -> <<"invalid_escape_sequence"/utf8>> end.