-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, <<Acc/binary, "\\\\"/utf8>>);
<<"|"/utf8>> ->
escape_chars(Rest, <<Acc/binary, "\\|"/utf8>>);
_ ->
escape_chars(Rest, <<Acc/binary, Char/binary>>)
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,
<<<<Acc/binary, "|"/utf8>>/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,
<<<<Acc/binary, ","/utf8>>/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,
<<Current/binary, Char/binary>>,
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,
<<Current/binary, Char/binary>>,
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.