Current section
Files
Jump to
Current section
Files
src/ssevents@encoder.erl
-module(ssevents@encoder).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/ssevents/encoder.gleam").
-export([default_line_ending/0, encode_with_line_ending/2, encode/1, encode_bytes/1, encode_item_with_line_ending/2, encode_item/1, encode_item_bytes/1, encode_items_with_line_ending/2, encode_items/1, encode_items_bytes/1]).
-export_type([line_ending/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(
" Deterministic Server-Sent Events encoding.\n"
"\n"
" The default line ending is LF. Call the `*_with_line_ending`\n"
" variants to emit CRLF instead.\n"
).
-type line_ending() :: lf | crlf.
-file("src/ssevents/encoder.gleam", 18).
-spec default_line_ending() -> line_ending().
default_line_ending() ->
lf.
-file("src/ssevents/encoder.gleam", 179).
-spec comment_line(binary()) -> binary().
comment_line(Text) ->
case Text of
<<""/utf8>> ->
<<":"/utf8>>;
_ ->
<<": "/utf8, Text/binary>>
end.
-file("src/ssevents/encoder.gleam", 186).
-spec prefixed_line(binary(), binary()) -> binary().
prefixed_line(Field, Value) ->
case Value of
<<""/utf8>> ->
<<Field/binary, ":"/utf8>>;
_ ->
<<<<Field/binary, ": "/utf8>>/binary, Value/binary>>
end.
-file("src/ssevents/encoder.gleam", 146).
-spec prepend_optional(list(binary()), binary(), gleam@option:option(binary())) -> list(binary()).
prepend_optional(Lines, Field, Maybe_value) ->
case Maybe_value of
{some, Value} ->
[prefixed_line(Field, Value) | Lines];
none ->
Lines
end.
-file("src/ssevents/encoder.gleam", 157).
-spec prepend_optional_int(
list(binary()),
binary(),
gleam@option:option(integer())
) -> list(binary()).
prepend_optional_int(Lines, Field, Maybe_value) ->
case Maybe_value of
{some, Value} ->
[prefixed_line(Field, erlang:integer_to_binary(Value)) | Lines];
none ->
Lines
end.
-file("src/ssevents/encoder.gleam", 193).
-spec line_ending_to_string(line_ending()) -> binary().
line_ending_to_string(Line_ending) ->
case Line_ending of
lf ->
<<"\n"/utf8>>;
crlf ->
<<"\r\n"/utf8>>
end.
-file("src/ssevents/encoder.gleam", 168).
-spec encode_comment_with_line_ending(binary(), line_ending()) -> binary().
encode_comment_with_line_ending(Text, Line_ending) ->
Newline = line_ending_to_string(Line_ending),
<<(comment_line(Text))/binary, Newline/binary>>.
-file("src/ssevents/encoder.gleam", 220).
-spec walk_normalise_newlines(bitstring(), bitstring()) -> bitstring().
walk_normalise_newlines(Input, Acc) ->
case Input of
<<>> ->
Acc;
<<13, 10, Rest/binary>> ->
walk_normalise_newlines(Rest, <<Acc/bitstring, 10>>);
<<13, Rest@1/binary>> ->
walk_normalise_newlines(Rest@1, <<Acc/bitstring, 10>>);
<<Byte, Rest@2/binary>> ->
walk_normalise_newlines(Rest@2, <<Acc/bitstring, Byte>>);
_ ->
Acc
end.
-file("src/ssevents/encoder.gleam", 200).
-spec normalise_newlines(binary()) -> binary().
normalise_newlines(Text) ->
S@1 = case begin
_pipe = Text,
_pipe@1 = gleam_stdlib:identity(_pipe),
_pipe@2 = walk_normalise_newlines(_pipe@1, <<>>),
gleam@bit_array:to_string(_pipe@2)
end of
{ok, S} -> S;
_assert_fail ->
erlang:error(#{gleam_error => let_assert,
message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
file => <<?FILEPATH/utf8>>,
module => <<"ssevents/encoder"/utf8>>,
function => <<"normalise_newlines"/utf8>>,
line => 212,
value => _assert_fail,
start => 6610,
'end' => 6730,
pattern_start => 6621,
pattern_end => 6626})
end,
S@1.
-file("src/ssevents/encoder.gleam", 129).
-spec chunk_data_line_loop(binary(), list(binary())) -> list(binary()).
chunk_data_line_loop(Remaining, Acc) ->
case string:length(Remaining) =< 2000 of
true ->
lists:reverse([Remaining | Acc]);
false ->
Head = gleam@string:slice(Remaining, 0, 2000),
Rest = gleam@string:slice(
Remaining,
2000,
string:length(Remaining) - 2000
),
chunk_data_line_loop(Rest, [Head | Acc])
end.
-file("src/ssevents/encoder.gleam", 122).
-spec chunk_data_line(binary()) -> list(binary()).
chunk_data_line(Line) ->
case erlang:byte_size(Line) =< (2000 * 4) of
true ->
[Line];
false ->
chunk_data_line_loop(Line, [])
end.
-file("src/ssevents/encoder.gleam", 86).
-spec event_lines(ssevents@event:event()) -> list(binary()).
event_lines(Ev) ->
Prefix_lines = begin
_pipe = [],
_pipe@1 = prepend_optional(
_pipe,
<<"event"/utf8>>,
ssevents@event:name_of(Ev)
),
_pipe@2 = prepend_optional(
_pipe@1,
<<"id"/utf8>>,
ssevents@event:id_of(Ev)
),
_pipe@3 = prepend_optional_int(
_pipe@2,
<<"retry"/utf8>>,
ssevents@event:retry_of(Ev)
),
lists:reverse(_pipe@3)
end,
Data_lines = begin
_pipe@4 = ssevents@event:data_of(Ev),
_pipe@5 = normalise_newlines(_pipe@4),
_pipe@6 = gleam@string:split(_pipe@5, <<"\n"/utf8>>),
_pipe@7 = gleam@list:flat_map(_pipe@6, fun chunk_data_line/1),
gleam@list:map(
_pipe@7,
fun(Line) -> prefixed_line(<<"data"/utf8>>, Line) end
)
end,
lists:append(Prefix_lines, Data_lines).
-file("src/ssevents/encoder.gleam", 57).
-spec encode_with_line_ending(ssevents@event:event(), line_ending()) -> binary().
encode_with_line_ending(Event, Line_ending) ->
Newline = line_ending_to_string(Line_ending),
Lines = event_lines(Event),
<<(erlang:list_to_binary(
gleam@list:map(
Lines,
fun(Line) -> <<Line/binary, Newline/binary>> end
)
))/binary,
Newline/binary>>.
-file("src/ssevents/encoder.gleam", 33).
?DOC(
" Encode one semantic SSE `Event` to its wire-format `String` (LF\n"
" line ending).\n"
"\n"
" **Determinism invariant** (#72): the encoded bytes depend only on\n"
" the *value* of the `Event`, not on the builder call sequence used to\n"
" construct it. For any two structurally equal `Event` values\n"
" (`Event.from_parts(...)` with the same fields, or any sequence of\n"
" builder calls that ends in the same field assignment),\n"
" `encode(a) == encode(b)` byte-for-byte. The same invariant holds\n"
" across the BEAM and JavaScript targets, so caches, signatures, and\n"
" content-addressable storage on the wire are stable across runtimes.\n"
).
-spec encode(ssevents@event:event()) -> binary().
encode(Event) ->
encode_with_line_ending(Event, lf).
-file("src/ssevents/encoder.gleam", 37).
-spec encode_bytes(ssevents@event:event()) -> bitstring().
encode_bytes(Event) ->
_pipe = encode(Event),
gleam_stdlib:identity(_pipe).
-file("src/ssevents/encoder.gleam", 66).
-spec encode_item_with_line_ending(ssevents@event:item(), line_ending()) -> binary().
encode_item_with_line_ending(Item, Line_ending) ->
case Item of
{event_item, Ev} ->
encode_with_line_ending(Ev, Line_ending);
{comment_item, C} ->
encode_comment_with_line_ending(
ssevents@event:comment_text_of(C),
Line_ending
)
end.
-file("src/ssevents/encoder.gleam", 41).
-spec encode_item(ssevents@event:item()) -> binary().
encode_item(Item) ->
encode_item_with_line_ending(Item, lf).
-file("src/ssevents/encoder.gleam", 45).
-spec encode_item_bytes(ssevents@event:item()) -> bitstring().
encode_item_bytes(Item) ->
_pipe = encode_item(Item),
gleam_stdlib:identity(_pipe).
-file("src/ssevents/encoder.gleam", 77).
-spec encode_items_with_line_ending(list(ssevents@event:item()), line_ending()) -> binary().
encode_items_with_line_ending(Items, Line_ending) ->
_pipe = Items,
_pipe@1 = gleam@list:map(
_pipe,
fun(Item) -> encode_item_with_line_ending(Item, Line_ending) end
),
erlang:list_to_binary(_pipe@1).
-file("src/ssevents/encoder.gleam", 49).
-spec encode_items(list(ssevents@event:item())) -> binary().
encode_items(Items) ->
encode_items_with_line_ending(Items, lf).
-file("src/ssevents/encoder.gleam", 53).
-spec encode_items_bytes(list(ssevents@event:item())) -> bitstring().
encode_items_bytes(Items) ->
_pipe = encode_items(Items),
gleam_stdlib:identity(_pipe).