Skip to main content

src/svg_path@serialize.erl

-module(svg_path@serialize).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/svg_path/serialize.gleam").
-export([default_options/0, decimal_options/1, fixed_decimal_options/1, relative_options/0, relative_decimal_options/1, relative_fixed_decimal_options/1, minimize_whitespace/1, with_commas/2, repeat_commands/2, with_newlines/2, with_left_decimals/2, with_right_decimals/2, with_left_padding/2, path_with_options/2, path/1, subpath_with_options/2, subpath/1, segment_with_options/2, segment/1]).
-export_type([options/0, newlines/0, left_padding_style/0, left_decimal_options/0, right_decimal_options/0, format/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(
    " SVG path data serializer.\n"
    "\n"
    " This module turns paths, subpaths, and segments into SVG `d` attribute\n"
    " strings. The default output favors readable canonical forms; options can be\n"
    " used for relative commands, smaller whitespace, and omitted repeated command\n"
    " letters.\n"
).

-type options() :: {options,
        left_decimal_options(),
        right_decimal_options(),
        boolean(),
        boolean(),
        boolean(),
        boolean(),
        newlines()}.

-type newlines() :: one_line | at_subpaths | at_segments.

-type left_padding_style() :: zero | space.

-type left_decimal_options() :: succinct |
    {auto_left_padding, left_padding_style()} |
    {left_padding, integer(), left_padding_style()}.

-type right_decimal_options() :: system |
    {at_most, integer()} |
    {fixed, integer()}.

-type format() :: {format, options(), svg_path@number_format:number_format()}.

-file("src/svg_path/serialize.gleam", 86).
?DOC(
    " Default serialization options.\n"
    "\n"
    " Defaults to readable absolute commands, up to 5 decimal places, repeated\n"
    " command letters, and normal whitespace.\n"
).
-spec default_options() -> options().
default_options() ->
    {options, succinct, {at_most, 5}, false, false, false, true, one_line}.

-file("src/svg_path/serialize.gleam", 101).
?DOC(
    " Create options that round numbers to the given number of decimal places.\n"
    "\n"
    " Trailing zeroes are stripped. Negative decimal places are clamped to zero.\n"
).
-spec decimal_options(integer()) -> options().
decimal_options(Decimal_places) ->
    {options,
        succinct,
        {at_most, Decimal_places},
        false,
        false,
        false,
        true,
        one_line}.

-file("src/svg_path/serialize.gleam", 117).
?DOC(
    " Create options that round numbers and keep exactly the given number of\n"
    " decimal places.\n"
    "\n"
    " Negative decimal places are clamped to zero.\n"
).
-spec fixed_decimal_options(integer()) -> options().
fixed_decimal_options(Decimal_places) ->
    {options,
        succinct,
        {fixed, Decimal_places},
        false,
        false,
        false,
        true,
        one_line}.

-file("src/svg_path/serialize.gleam", 130).
?DOC(" Create options that serialize with relative commands.\n").
-spec relative_options() -> options().
relative_options() ->
    {options, succinct, {at_most, 5}, true, false, false, true, one_line}.

-file("src/svg_path/serialize.gleam", 143).
?DOC(" Create relative serialization options with decimal rounding.\n").
-spec relative_decimal_options(integer()) -> options().
relative_decimal_options(Decimal_places) ->
    {options,
        succinct,
        {at_most, Decimal_places},
        true,
        false,
        false,
        true,
        one_line}.

-file("src/svg_path/serialize.gleam", 156).
?DOC(" Create relative serialization options with fixed decimal formatting.\n").
-spec relative_fixed_decimal_options(integer()) -> options().
relative_fixed_decimal_options(Decimal_places) ->
    {options,
        succinct,
        {fixed, Decimal_places},
        true,
        false,
        false,
        true,
        one_line}.

-file("src/svg_path/serialize.gleam", 169).
?DOC(" Remove optional spaces between command letters and their arguments.\n").
-spec minimize_whitespace(options()) -> options().
minimize_whitespace(Options) ->
    {options,
        erlang:element(2, Options),
        erlang:element(3, Options),
        erlang:element(4, Options),
        true,
        erlang:element(6, Options),
        erlang:element(7, Options),
        erlang:element(8, Options)}.

-file("src/svg_path/serialize.gleam", 174).
?DOC(" Configure whether coordinate pairs should use a comma between `x` and `y`.\n").
-spec with_commas(options(), boolean()) -> options().
with_commas(Options, Commas) ->
    {options,
        erlang:element(2, Options),
        erlang:element(3, Options),
        erlang:element(4, Options),
        erlang:element(5, Options),
        Commas,
        erlang:element(7, Options),
        erlang:element(8, Options)}.

-file("src/svg_path/serialize.gleam", 182).
?DOC(
    " Configure whether repeated command letters should be emitted.\n"
    "\n"
    " SVG allows some commands to omit the command letter when the same command\n"
    " repeats. Pass `False` for smaller, less verbose output.\n"
).
-spec repeat_commands(options(), boolean()) -> options().
repeat_commands(Options, Repeat_commands) ->
    {options,
        erlang:element(2, Options),
        erlang:element(3, Options),
        erlang:element(4, Options),
        erlang:element(5, Options),
        erlang:element(6, Options),
        Repeat_commands,
        erlang:element(8, Options)}.

-file("src/svg_path/serialize.gleam", 187).
?DOC(" Configure where newlines should be inserted in serialized path data.\n").
-spec with_newlines(options(), newlines()) -> options().
with_newlines(Options, Newlines) ->
    {options,
        erlang:element(2, Options),
        erlang:element(3, Options),
        erlang:element(4, Options),
        erlang:element(5, Options),
        erlang:element(6, Options),
        erlang:element(7, Options),
        Newlines}.

-file("src/svg_path/serialize.gleam", 195).
?DOC(" Set left-side decimal formatting for serialization options.\n").
-spec with_left_decimals(options(), left_decimal_options()) -> options().
with_left_decimals(Options, Left_decimals) ->
    {options,
        Left_decimals,
        erlang:element(3, Options),
        erlang:element(4, Options),
        erlang:element(5, Options),
        erlang:element(6, Options),
        erlang:element(7, Options),
        erlang:element(8, Options)}.

-file("src/svg_path/serialize.gleam", 203).
?DOC(" Set right-side decimal formatting for serialization options.\n").
-spec with_right_decimals(options(), right_decimal_options()) -> options().
with_right_decimals(Options, Right_decimals) ->
    {options,
        erlang:element(2, Options),
        Right_decimals,
        erlang:element(4, Options),
        erlang:element(5, Options),
        erlang:element(6, Options),
        erlang:element(7, Options),
        erlang:element(8, Options)}.

-file("src/svg_path/serialize.gleam", 211).
?DOC(" Set left-side number padding for serialization options.\n").
-spec with_left_padding(options(), left_decimal_options()) -> options().
with_left_padding(Options, Left_padding) ->
    with_left_decimals(Options, Left_padding).

-file("src/svg_path/serialize.gleam", 745).
-spec append_to_current_line(list(binary()), binary()) -> list(binary()).
append_to_current_line(Lines, Suffix) ->
    case Lines of
        [] ->
            [Suffix];

        [Line | Rest] ->
            [<<<<Line/binary, " "/utf8>>/binary, Suffix/binary>> | Rest]
    end.

-file("src/svg_path/serialize.gleam", 752).
-spec is_move_command(binary()) -> boolean().
is_move_command(Command) ->
    (Command =:= <<"M"/utf8>>) orelse (Command =:= <<"m"/utf8>>).

-file("src/svg_path/serialize.gleam", 792).
-spec command_arguments(binary(), options()) -> binary().
command_arguments(Command, Options) ->
    Arguments = gleam@string:drop_start(Command, 1),
    case erlang:element(5, Options) of
        true ->
            Arguments;

        false ->
            gleam@string:drop_start(Arguments, 1)
    end.

-file("src/svg_path/serialize.gleam", 756).
-spec is_command_name(binary()) -> boolean().
is_command_name(Command) ->
    gleam@list:contains(
        [<<"M"/utf8>>,
            <<"m"/utf8>>,
            <<"L"/utf8>>,
            <<"l"/utf8>>,
            <<"H"/utf8>>,
            <<"h"/utf8>>,
            <<"V"/utf8>>,
            <<"v"/utf8>>,
            <<"Q"/utf8>>,
            <<"q"/utf8>>,
            <<"C"/utf8>>,
            <<"c"/utf8>>,
            <<"A"/utf8>>,
            <<"a"/utf8>>,
            <<"Z"/utf8>>,
            <<"z"/utf8>>],
        Command
    ).

-file("src/svg_path/serialize.gleam", 785).
-spec command_name(binary()) -> binary().
command_name(Command) ->
    case gleam@string:to_graphemes(Command) of
        [Name | _] ->
            Name;

        [] ->
            <<""/utf8>>
    end.

-file("src/svg_path/serialize.gleam", 697).
-spec join_segment_lines_with_command_newlines(
    list(binary()),
    list(binary()),
    boolean(),
    options()
) -> binary().
join_segment_lines_with_command_newlines(
    Commands,
    Lines,
    After_command,
    Options
) ->
    case Commands of
        [] ->
            _pipe = Lines,
            _pipe@1 = lists:reverse(_pipe),
            gleam@string:join(_pipe@1, <<"\n"/utf8>>);

        [Command | Rest] ->
            Name = command_name(Command),
            case is_command_name(Name) of
                false ->
                    join_segment_lines_with_command_newlines(
                        Rest,
                        [Command | Lines],
                        false,
                        Options
                    );

                true ->
                    Arguments = command_arguments(Command, Options),
                    Lines@1 = case (Lines =:= []) orelse After_command of
                        true ->
                            [Name | Lines];

                        false ->
                            case is_move_command(Name) of
                                true ->
                                    [Name | Lines];

                                false ->
                                    append_to_current_line(Lines, Name)
                            end
                    end,
                    Lines@2 = case Arguments =:= <<""/utf8>> of
                        true ->
                            Lines@1;

                        false ->
                            [Arguments | Lines@1]
                    end,
                    join_segment_lines_with_command_newlines(
                        Rest,
                        Lines@2,
                        Arguments =:= <<""/utf8>>,
                        Options
                    )
            end
    end.

-file("src/svg_path/serialize.gleam", 801).
-spec compacted_command_arguments(binary(), options()) -> binary().
compacted_command_arguments(Command, Options) ->
    Arguments = command_arguments(Command, Options),
    case erlang:element(5, Options) of
        true ->
            <<" "/utf8, Arguments/binary>>;

        false ->
            Arguments
    end.

-file("src/svg_path/serialize.gleam", 810).
-spec can_repeat_command(binary()) -> boolean().
can_repeat_command(Command) ->
    gleam@list:contains(
        [<<"L"/utf8>>,
            <<"l"/utf8>>,
            <<"H"/utf8>>,
            <<"h"/utf8>>,
            <<"V"/utf8>>,
            <<"v"/utf8>>,
            <<"Q"/utf8>>,
            <<"q"/utf8>>,
            <<"C"/utf8>>,
            <<"c"/utf8>>,
            <<"A"/utf8>>,
            <<"a"/utf8>>],
        Command
    ).

-file("src/svg_path/serialize.gleam", 766).
-spec compact_repeated_commands(list(binary()), binary(), format()) -> list(binary()).
compact_repeated_commands(Commands, Previous, Format) ->
    case Commands of
        [] ->
            [];

        [Command | Rest] ->
            Current = command_name(Command),
            Compacted = case (Current =:= Previous) andalso can_repeat_command(
                Current
            ) of
                true ->
                    compacted_command_arguments(
                        Command,
                        erlang:element(2, Format)
                    );

                false ->
                    Command
            end,
            [Compacted | compact_repeated_commands(Rest, Current, Format)]
    end.

-file("src/svg_path/serialize.gleam", 683).
-spec join_segment_lines(list(binary()), format()) -> binary().
join_segment_lines(Commands, Format) ->
    case erlang:element(7, erlang:element(2, Format)) of
        true ->
            gleam@string:join(Commands, <<"\n"/utf8>>);

        false ->
            _pipe = Commands,
            _pipe@1 = compact_repeated_commands(_pipe, <<""/utf8>>, Format),
            join_segment_lines_with_command_newlines(
                _pipe@1,
                [],
                false,
                erlang:element(2, Format)
            )
    end.

-file("src/svg_path/serialize.gleam", 817).
-spec command_separator(options()) -> binary().
command_separator(Options) ->
    case erlang:element(5, Options) of
        true ->
            <<""/utf8>>;

        false ->
            <<" "/utf8>>
    end.

-file("src/svg_path/serialize.gleam", 660).
-spec join_with_subpath_separators(list(binary()), binary(), format()) -> binary().
join_with_subpath_separators(Commands, Previous, Format) ->
    case Commands of
        [] ->
            <<""/utf8>>;

        [Command] ->
            <<Previous/binary, Command/binary>>;

        [Command@1, Next | Rest] ->
            Separator = case is_move_command(command_name(Next)) of
                true ->
                    <<"\n"/utf8>>;

                false ->
                    command_separator(erlang:element(2, Format))
            end,
            join_with_subpath_separators(
                [Next | Rest],
                <<<<Previous/binary, Command@1/binary>>/binary,
                    Separator/binary>>,
                Format
            )
    end.

-file("src/svg_path/serialize.gleam", 651).
-spec join_subpath_lines(list(binary()), format()) -> binary().
join_subpath_lines(Commands, Format) ->
    Commands@1 = case erlang:element(7, erlang:element(2, Format)) of
        true ->
            Commands;

        false ->
            compact_repeated_commands(Commands, <<""/utf8>>, Format)
    end,
    join_with_subpath_separators(Commands@1, <<""/utf8>>, Format).

-file("src/svg_path/serialize.gleam", 641).
-spec join_one_line(list(binary()), format()) -> binary().
join_one_line(Commands, Format) ->
    case erlang:element(7, erlang:element(2, Format)) of
        true ->
            gleam@string:join(
                Commands,
                command_separator(erlang:element(2, Format))
            );

        false ->
            _pipe = Commands,
            _pipe@1 = compact_repeated_commands(_pipe, <<""/utf8>>, Format),
            gleam@string:join(
                _pipe@1,
                command_separator(erlang:element(2, Format))
            )
    end.

-file("src/svg_path/serialize.gleam", 633).
-spec join_commands(list(binary()), format()) -> binary().
join_commands(Commands, Format) ->
    case erlang:element(8, erlang:element(2, Format)) of
        one_line ->
            join_one_line(Commands, Format);

        at_subpaths ->
            join_subpath_lines(Commands, Format);

        at_segments ->
            join_segment_lines(Commands, Format)
    end.

-file("src/svg_path/serialize.gleam", 1023).
-spec number(float(), format()) -> binary().
number(Number, Format) ->
    svg_path@number_format:number(Number, erlang:element(3, Format)).

-file("src/svg_path/serialize.gleam", 619).
-spec coordinate_separator(options()) -> binary().
coordinate_separator(Options) ->
    case erlang:element(6, Options) of
        true ->
            <<","/utf8>>;

        false ->
            <<" "/utf8>>
    end.

-file("src/svg_path/serialize.gleam", 609).
-spec point(vec@vec2:vec2(float()), format()) -> binary().
point(Point, Format) ->
    <<<<(number(erlang:element(2, Point), Format))/binary,
            (coordinate_separator(erlang:element(2, Format)))/binary>>/binary,
        (number(erlang:element(3, Point), Format))/binary>>.

-file("src/svg_path/serialize.gleam", 1070).
-spec flag(boolean()) -> binary().
flag(Flag) ->
    case Flag of
        true ->
            <<"1"/utf8>>;

        false ->
            <<"0"/utf8>>
    end.

-file("src/svg_path/serialize.gleam", 626).
-spec command_argument_separator(options()) -> binary().
command_argument_separator(Options) ->
    case erlang:element(5, Options) of
        true ->
            <<""/utf8>>;

        false ->
            <<" "/utf8>>
    end.

-file("src/svg_path/serialize.gleam", 615).
-spec command(binary(), binary(), format()) -> binary().
command(Command, Arguments, Format) ->
    <<<<Command/binary,
            (command_argument_separator(erlang:element(2, Format)))/binary>>/binary,
        Arguments/binary>>.

-file("src/svg_path/serialize.gleam", 530).
-spec absolute_line(vec@vec2:vec2(float()), vec@vec2:vec2(float()), format()) -> binary().
absolute_line(Start, End, Format) ->
    Start_x = number(erlang:element(2, Start), Format),
    Start_y = number(erlang:element(3, Start), Format),
    End_x = number(erlang:element(2, End), Format),
    End_y = number(erlang:element(3, End), Format),
    case Start_y =:= End_y of
        true ->
            command(<<"H"/utf8>>, End_x, Format);

        false ->
            case Start_x =:= End_x of
                true ->
                    command(<<"V"/utf8>>, End_y, Format);

                false ->
                    command(
                        <<"L"/utf8>>,
                        <<<<End_x/binary,
                                (coordinate_separator(erlang:element(2, Format)))/binary>>/binary,
                            End_y/binary>>,
                        Format
                    )
            end
    end.

-file("src/svg_path/serialize.gleam", 444).
-spec absolute_segment_without_move(svg_path:segment(), format()) -> binary().
absolute_segment_without_move(Segment, Format) ->
    case Segment of
        {line, Start, End} ->
            absolute_line(Start, End, Format);

        {quadratic_bezier, _, Control, End@1} ->
            command(
                <<"Q"/utf8>>,
                <<<<(point(Control, Format))/binary, " "/utf8>>/binary,
                    (point(End@1, Format))/binary>>,
                Format
            );

        {cubic_bezier, _, Control1, Control2, End@2} ->
            command(
                <<"C"/utf8>>,
                <<<<<<<<(point(Control1, Format))/binary, " "/utf8>>/binary,
                            (point(Control2, Format))/binary>>/binary,
                        " "/utf8>>/binary,
                    (point(End@2, Format))/binary>>,
                Format
            );

        {arc, _, Radius, X_axis_rotation, Large_arc, Sweep, End@3} ->
            command(
                <<"A"/utf8>>,
                <<<<<<<<<<<<<<<<(point(Radius, Format))/binary, " "/utf8>>/binary,
                                            (number(X_axis_rotation, Format))/binary>>/binary,
                                        " "/utf8>>/binary,
                                    (flag(Large_arc))/binary>>/binary,
                                " "/utf8>>/binary,
                            (flag(Sweep))/binary>>/binary,
                        " "/utf8>>/binary,
                    (point(End@3, Format))/binary>>,
                Format
            )
    end.

-file("src/svg_path/serialize.gleam", 432).
-spec drop_last_if_closing_line(
    list(svg_path:segment()),
    vec@vec2:vec2(float())
) -> list(svg_path:segment()).
drop_last_if_closing_line(Reversed_segments, Start) ->
    case Reversed_segments of
        [{line, Line_start, Line_end} | Rest] when (Line_end =:= Start) andalso (Line_start =/= Line_end) ->
            Rest;

        _ ->
            Reversed_segments
    end.

-file("src/svg_path/serialize.gleam", 416).
-spec drop_closing_line(list(svg_path:segment())) -> list(svg_path:segment()).
drop_closing_line(Segments) ->
    case Segments of
        [] ->
            [];

        [First | _] ->
            Start = svg_path:segment_start(First),
            _pipe = Segments,
            _pipe@1 = lists:reverse(_pipe),
            _pipe@2 = drop_last_if_closing_line(_pipe@1, Start),
            lists:reverse(_pipe@2)
    end.

-file("src/svg_path/serialize.gleam", 407).
-spec serializable_segments(svg_path:subpath()) -> list(svg_path:segment()).
serializable_segments(Subpath) ->
    Segments = svg_path:segments(Subpath),
    case svg_path:is_closed(Subpath) of
        false ->
            Segments;

        true ->
            drop_closing_line(Segments)
    end.

-file("src/svg_path/serialize.gleam", 304).
-spec serialize_absolute_subpath(svg_path:subpath(), format()) -> binary().
serialize_absolute_subpath(Subpath, Format) ->
    Start@1 = case svg_path:start(Subpath) of
        {ok, Start} -> Start;
        _assert_fail ->
            erlang:error(#{gleam_error => let_assert,
                        message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
                        file => <<?FILEPATH/utf8>>,
                        module => <<"svg_path/serialize"/utf8>>,
                        function => <<"serialize_absolute_subpath"/utf8>>,
                        line => 308,
                        value => _assert_fail,
                        start => 8604,
                        'end' => 8650,
                        pattern_start => 8615,
                        pattern_end => 8624})
    end,
    case svg_path:segments(Subpath) of
        [] ->
            Commands = [command(<<"M"/utf8>>, point(Start@1, Format), Format)],
            Commands@1 = case svg_path:is_closed(Subpath) of
                true ->
                    lists:append(Commands, [<<"Z"/utf8>>]);

                false ->
                    Commands
            end,
            join_commands(Commands@1, Format);

        [_ | _] ->
            Segments = serializable_segments(Subpath),
            Commands@2 = [command(<<"M"/utf8>>, point(Start@1, Format), Format)],
            Commands@3 = lists:append(
                Commands@2,
                gleam@list:map(
                    Segments,
                    fun(_capture) ->
                        absolute_segment_without_move(_capture, Format)
                    end
                )
            ),
            Commands@4 = case svg_path:is_closed(Subpath) of
                true ->
                    lists:append(Commands@3, [<<"Z"/utf8>>]);

                false ->
                    Commands@3
            end,
            join_commands(Commands@4, Format)
    end.

-file("src/svg_path/serialize.gleam", 601).
-spec origin() -> vec@vec2:vec2(float()).
origin() ->
    svg_path:point(+0.0, +0.0).

-file("src/svg_path/serialize.gleam", 605).
-spec delta(vec@vec2:vec2(float()), vec@vec2:vec2(float())) -> vec@vec2:vec2(float()).
delta(Point, Origin) ->
    svg_path:point(
        erlang:element(2, Point) - erlang:element(2, Origin),
        erlang:element(3, Point) - erlang:element(3, Origin)
    ).

-file("src/svg_path/serialize.gleam", 556).
-spec relative_line(vec@vec2:vec2(float()), vec@vec2:vec2(float()), format()) -> binary().
relative_line(Start, End, Format) ->
    Difference = delta(End, Start),
    Dx = number(erlang:element(2, Difference), Format),
    Dy = number(erlang:element(3, Difference), Format),
    Zero = number(+0.0, Format),
    case Dy =:= Zero of
        true ->
            command(<<"h"/utf8>>, Dx, Format);

        false ->
            case Dx =:= Zero of
                true ->
                    command(<<"v"/utf8>>, Dy, Format);

                false ->
                    command(
                        <<"l"/utf8>>,
                        <<<<Dx/binary,
                                (coordinate_separator(erlang:element(2, Format)))/binary>>/binary,
                            Dy/binary>>,
                        Format
                    )
            end
    end.

-file("src/svg_path/serialize.gleam", 482).
-spec relative_segment_without_move(svg_path:segment(), format()) -> binary().
relative_segment_without_move(Segment, Format) ->
    Start = svg_path:segment_start(Segment),
    case Segment of
        {line, _, End} ->
            relative_line(Start, End, Format);

        {quadratic_bezier, _, Control, End@1} ->
            command(
                <<"q"/utf8>>,
                <<<<(point(delta(Control, Start), Format))/binary, " "/utf8>>/binary,
                    (point(delta(End@1, Start), Format))/binary>>,
                Format
            );

        {cubic_bezier, _, Control1, Control2, End@2} ->
            command(
                <<"c"/utf8>>,
                <<<<<<<<(point(delta(Control1, Start), Format))/binary,
                                " "/utf8>>/binary,
                            (point(delta(Control2, Start), Format))/binary>>/binary,
                        " "/utf8>>/binary,
                    (point(delta(End@2, Start), Format))/binary>>,
                Format
            );

        {arc, _, Radius, X_axis_rotation, Large_arc, Sweep, End@3} ->
            command(
                <<"a"/utf8>>,
                <<<<<<<<<<<<<<<<(point(Radius, Format))/binary, " "/utf8>>/binary,
                                            (number(X_axis_rotation, Format))/binary>>/binary,
                                        " "/utf8>>/binary,
                                    (flag(Large_arc))/binary>>/binary,
                                " "/utf8>>/binary,
                            (flag(Sweep))/binary>>/binary,
                        " "/utf8>>/binary,
                    (point(delta(End@3, Start), Format))/binary>>,
                Format
            )
    end.

-file("src/svg_path/serialize.gleam", 368).
-spec subpath_from_current(svg_path:subpath(), vec@vec2:vec2(float()), format()) -> binary().
subpath_from_current(Subpath, Current, Format) ->
    Start@1 = case svg_path:start(Subpath) of
        {ok, Start} -> Start;
        _assert_fail ->
            erlang:error(#{gleam_error => let_assert,
                        message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
                        file => <<?FILEPATH/utf8>>,
                        module => <<"svg_path/serialize"/utf8>>,
                        function => <<"subpath_from_current"/utf8>>,
                        line => 373,
                        value => _assert_fail,
                        start => 10217,
                        'end' => 10263,
                        pattern_start => 10228,
                        pattern_end => 10237})
    end,
    case svg_path:segments(Subpath) of
        [] ->
            Commands = [command(
                    <<"m"/utf8>>,
                    point(delta(Start@1, Current), Format),
                    Format
                )],
            Commands@1 = case svg_path:is_closed(Subpath) of
                true ->
                    lists:append(Commands, [<<"z"/utf8>>]);

                false ->
                    Commands
            end,
            join_commands(Commands@1, Format);

        [_ | _] ->
            Segments = serializable_segments(Subpath),
            Commands@2 = [command(
                    <<"m"/utf8>>,
                    point(delta(Start@1, Current), Format),
                    Format
                )],
            Commands@3 = lists:append(
                Commands@2,
                gleam@list:map(
                    Segments,
                    fun(_capture) ->
                        relative_segment_without_move(_capture, Format)
                    end
                )
            ),
            Commands@4 = case svg_path:is_closed(Subpath) of
                true ->
                    lists:append(Commands@3, [<<"z"/utf8>>]);

                false ->
                    Commands@3
            end,
            join_commands(Commands@4, Format)
    end.

-file("src/svg_path/serialize.gleam", 578).
-spec current_after_subpath(svg_path:subpath(), vec@vec2:vec2(float())) -> vec@vec2:vec2(float()).
current_after_subpath(Subpath, Current) ->
    case svg_path:segments(Subpath) of
        [] ->
            Start@1 = case svg_path:start(Subpath) of
                {ok, Start} -> Start;
                _assert_fail ->
                    erlang:error(#{gleam_error => let_assert,
                                message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
                                file => <<?FILEPATH/utf8>>,
                                module => <<"svg_path/serialize"/utf8>>,
                                function => <<"current_after_subpath"/utf8>>,
                                line => 584,
                                value => _assert_fail,
                                start => 15282,
                                'end' => 15328,
                                pattern_start => 15293,
                                pattern_end => 15302})
            end,
            Start@1;

        [First | _] ->
            case svg_path:is_closed(Subpath) of
                true ->
                    svg_path:segment_start(First);

                false ->
                    case svg_path:'end'(Subpath) of
                        {ok, End} ->
                            End;

                        {error, _} ->
                            Current
                    end
            end
    end.

-file("src/svg_path/serialize.gleam", 344).
-spec relative_path_loop(
    list(svg_path:subpath()),
    vec@vec2:vec2(float()),
    list(binary()),
    format()
) -> binary().
relative_path_loop(Subpaths, Current, Serialized, Format) ->
    case Subpaths of
        [] ->
            _pipe = Serialized,
            _pipe@1 = lists:reverse(_pipe),
            _pipe@2 = gleam@list:filter(
                _pipe@1,
                fun(Subpath) -> Subpath /= <<""/utf8>> end
            ),
            join_commands(_pipe@2, Format);

        [Subpath@1 | Rest] ->
            relative_path_loop(
                Rest,
                current_after_subpath(Subpath@1, Current),
                [subpath_from_current(Subpath@1, Current, Format) | Serialized],
                Format
            )
    end.

-file("src/svg_path/serialize.gleam", 340).
-spec relative_path(list(svg_path:subpath()), format()) -> binary().
relative_path(Subpaths, Format) ->
    relative_path_loop(Subpaths, origin(), [], Format).

-file("src/svg_path/serialize.gleam", 1008).
-spec point_numbers(vec@vec2:vec2(float())) -> list(float()).
point_numbers(Point) ->
    [erlang:element(2, Point), erlang:element(3, Point)].

-file("src/svg_path/serialize.gleam", 1060).
-spec right_decimals(right_decimal_options()) -> svg_path@number_format:right_decimal_options().
right_decimals(Right_decimals) ->
    case Right_decimals of
        system ->
            system;

        {at_most, Decimal_places} ->
            {at_most, Decimal_places};

        {fixed, Decimal_places@1} ->
            {fixed, Decimal_places@1}
    end.

-file("src/svg_path/serialize.gleam", 1051).
-spec left_padding_style(left_padding_style()) -> svg_path@number_format:left_padding_style().
left_padding_style(Style) ->
    case Style of
        zero ->
            zero;

        space ->
            space
    end.

-file("src/svg_path/serialize.gleam", 1038).
-spec left_decimals(left_decimal_options()) -> svg_path@number_format:left_decimal_options().
left_decimals(Left_decimals) ->
    case Left_decimals of
        succinct ->
            succinct;

        {auto_left_padding, Style} ->
            {auto_left_padding, left_padding_style(Style)};

        {left_padding, Width, Style@1} ->
            {left_padding, Width, left_padding_style(Style@1)}
    end.

-file("src/svg_path/serialize.gleam", 1031).
-spec number_options(options()) -> svg_path@number_format:options().
number_options(Options) ->
    {options,
        left_decimals(erlang:element(2, Options)),
        right_decimals(erlang:element(3, Options))}.

-file("src/svg_path/serialize.gleam", 1027).
-spec raw_number(float(), options()) -> binary().
raw_number(Number, Options) ->
    svg_path@number_format:raw_number(Number, number_options(Options)).

-file("src/svg_path/serialize.gleam", 966).
-spec absolute_line_numbers(
    vec@vec2:vec2(float()),
    vec@vec2:vec2(float()),
    options()
) -> list(float()).
absolute_line_numbers(Start, End, Options) ->
    Start_x = raw_number(erlang:element(2, Start), Options),
    Start_y = raw_number(erlang:element(3, Start), Options),
    End_x = raw_number(erlang:element(2, End), Options),
    End_y = raw_number(erlang:element(3, End), Options),
    case Start_y =:= End_y of
        true ->
            [erlang:element(2, End)];

        false ->
            case Start_x =:= End_x of
                true ->
                    [erlang:element(3, End)];

                false ->
                    point_numbers(End)
            end
    end.

-file("src/svg_path/serialize.gleam", 925).
-spec absolute_segment_numbers(svg_path:segment(), options()) -> list(float()).
absolute_segment_numbers(Segment, Options) ->
    case Segment of
        {line, Start, End} ->
            absolute_line_numbers(Start, End, Options);

        {quadratic_bezier, _, Control, End@1} ->
            _pipe = point_numbers(Control),
            lists:append(_pipe, point_numbers(End@1));

        {cubic_bezier, _, Control1, Control2, End@2} ->
            _pipe@1 = point_numbers(Control1),
            _pipe@2 = lists:append(_pipe@1, point_numbers(Control2)),
            lists:append(_pipe@2, point_numbers(End@2));

        {arc, _, Radius, X_axis_rotation, _, _, End@3} ->
            _pipe@3 = point_numbers(Radius),
            _pipe@4 = lists:append(_pipe@3, [X_axis_rotation]),
            lists:append(_pipe@4, point_numbers(End@3))
    end.

-file("src/svg_path/serialize.gleam", 867).
-spec absolute_subpath_numbers(svg_path:subpath(), options()) -> list(float()).
absolute_subpath_numbers(Subpath, Options) ->
    Start@1 = case svg_path:start(Subpath) of
        {ok, Start} -> Start;
        _assert_fail ->
            erlang:error(#{gleam_error => let_assert,
                        message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
                        file => <<?FILEPATH/utf8>>,
                        module => <<"svg_path/serialize"/utf8>>,
                        function => <<"absolute_subpath_numbers"/utf8>>,
                        line => 871,
                        value => _assert_fail,
                        start => 22470,
                        'end' => 22516,
                        pattern_start => 22481,
                        pattern_end => 22490})
    end,
    case svg_path:segments(Subpath) of
        [] ->
            point_numbers(Start@1);

        [_ | _] ->
            _pipe = serializable_segments(Subpath),
            gleam@list:fold(
                _pipe,
                point_numbers(Start@1),
                fun(Accumulated, Segment) ->
                    lists:append(
                        Accumulated,
                        absolute_segment_numbers(Segment, Options)
                    )
                end
            )
    end.

-file("src/svg_path/serialize.gleam", 987).
-spec relative_line_numbers(
    vec@vec2:vec2(float()),
    vec@vec2:vec2(float()),
    options()
) -> list(float()).
relative_line_numbers(Start, End, Options) ->
    Difference = delta(End, Start),
    Dx = raw_number(erlang:element(2, Difference), Options),
    Dy = raw_number(erlang:element(3, Difference), Options),
    Zero = raw_number(+0.0, Options),
    case Dy =:= Zero of
        true ->
            [erlang:element(2, Difference)];

        false ->
            case Dx =:= Zero of
                true ->
                    [erlang:element(3, Difference)];

                false ->
                    point_numbers(Difference)
            end
    end.

-file("src/svg_path/serialize.gleam", 944).
-spec relative_segment_numbers(svg_path:segment(), options()) -> list(float()).
relative_segment_numbers(Segment, Options) ->
    Start = svg_path:segment_start(Segment),
    case Segment of
        {line, _, End} ->
            relative_line_numbers(Start, End, Options);

        {quadratic_bezier, _, Control, End@1} ->
            _pipe = point_numbers(delta(Control, Start)),
            lists:append(_pipe, point_numbers(delta(End@1, Start)));

        {cubic_bezier, _, Control1, Control2, End@2} ->
            _pipe@1 = point_numbers(delta(Control1, Start)),
            _pipe@2 = lists:append(
                _pipe@1,
                point_numbers(delta(Control2, Start))
            ),
            lists:append(_pipe@2, point_numbers(delta(End@2, Start)));

        {arc, _, Radius, X_axis_rotation, _, _, End@3} ->
            _pipe@3 = point_numbers(Radius),
            _pipe@4 = lists:append(_pipe@3, [X_axis_rotation]),
            lists:append(_pipe@4, point_numbers(delta(End@3, Start)))
    end.

-file("src/svg_path/serialize.gleam", 884).
-spec relative_subpath_numbers(
    svg_path:subpath(),
    vec@vec2:vec2(float()),
    options()
) -> list(float()).
relative_subpath_numbers(Subpath, Current, Options) ->
    Start@1 = case svg_path:start(Subpath) of
        {ok, Start} -> Start;
        _assert_fail ->
            erlang:error(#{gleam_error => let_assert,
                        message => <<"Pattern match failed, no pattern matched the value."/utf8>>,
                        file => <<?FILEPATH/utf8>>,
                        module => <<"svg_path/serialize"/utf8>>,
                        function => <<"relative_subpath_numbers"/utf8>>,
                        line => 889,
                        value => _assert_fail,
                        start => 22932,
                        'end' => 22978,
                        pattern_start => 22943,
                        pattern_end => 22952})
    end,
    case svg_path:segments(Subpath) of
        [] ->
            point_numbers(delta(Start@1, Current));

        [_ | _] ->
            _pipe = serializable_segments(Subpath),
            gleam@list:fold(
                _pipe,
                point_numbers(delta(Start@1, Current)),
                fun(Accumulated, Segment) ->
                    lists:append(
                        Accumulated,
                        relative_segment_numbers(Segment, Options)
                    )
                end
            )
    end.

-file("src/svg_path/serialize.gleam", 838).
-spec relative_path_numbers(
    list(svg_path:subpath()),
    vec@vec2:vec2(float()),
    list(float()),
    options()
) -> list(float()).
relative_path_numbers(Subpaths, Current, Accumulated, Options) ->
    case Subpaths of
        [] ->
            Accumulated;

        [Subpath | Rest] ->
            relative_path_numbers(
                Rest,
                current_after_subpath(Subpath, Current),
                lists:append(
                    Accumulated,
                    relative_subpath_numbers(Subpath, Current, Options)
                ),
                Options
            )
    end.

-file("src/svg_path/serialize.gleam", 824).
-spec path_numbers(svg_path:path(), options()) -> list(float()).
path_numbers(Path, Options) ->
    case erlang:element(4, Options) of
        true ->
            relative_path_numbers(
                svg_path:subpaths(Path),
                origin(),
                [],
                Options
            );

        false ->
            _pipe = Path,
            _pipe@1 = svg_path:subpaths(_pipe),
            gleam@list:fold(
                _pipe@1,
                [],
                fun(Accumulated, Subpath) ->
                    lists:append(
                        Accumulated,
                        absolute_subpath_numbers(Subpath, Options)
                    )
                end
            )
    end.

-file("src/svg_path/serialize.gleam", 1016).
-spec serialization_format(options(), list(float())) -> format().
serialization_format(Options, Numbers) ->
    {format,
        Options,
        svg_path@number_format:prepare(number_options(Options), Numbers)}.

-file("src/svg_path/serialize.gleam", 229).
?DOC(
    " Serialize a path with custom options.\n"
    "\n"
    " With relative options, closed subpaths end in `z`.\n"
).
-spec path_with_options(svg_path:path(), options()) -> binary().
path_with_options(Path, Options) ->
    Format = serialization_format(Options, path_numbers(Path, Options)),
    case erlang:element(4, Options) of
        true ->
            relative_path(svg_path:subpaths(Path), Format);

        false ->
            _pipe = Path,
            _pipe@1 = svg_path:subpaths(_pipe),
            _pipe@2 = gleam@list:map(
                _pipe@1,
                fun(_capture) ->
                    serialize_absolute_subpath(_capture, Format)
                end
            ),
            _pipe@3 = gleam@list:filter(
                _pipe@2,
                fun(Serialized) -> Serialized /= <<""/utf8>> end
            ),
            join_commands(_pipe@3, Format)
    end.

-file("src/svg_path/serialize.gleam", 222).
?DOC(
    " Serialize a path with default options.\n"
    "\n"
    " Empty paths serialize to the empty string. Empty subpaths serialize as\n"
    " move-only subpaths. Closed subpaths end in `Z`.\n"
).
-spec path(svg_path:path()) -> binary().
path(Path) ->
    path_with_options(Path, default_options()).

-file("src/svg_path/serialize.gleam", 860).
-spec subpath_numbers(svg_path:subpath(), options()) -> list(float()).
subpath_numbers(Subpath, Options) ->
    case erlang:element(4, Options) of
        true ->
            relative_subpath_numbers(Subpath, origin(), Options);

        false ->
            absolute_subpath_numbers(Subpath, Options)
    end.

-file("src/svg_path/serialize.gleam", 257).
?DOC(
    " Serialize a subpath with custom options.\n"
    "\n"
    " With relative options, closed subpaths end in `z`.\n"
).
-spec subpath_with_options(svg_path:subpath(), options()) -> binary().
subpath_with_options(Subpath, Options) ->
    Format = serialization_format(Options, subpath_numbers(Subpath, Options)),
    case erlang:element(4, Options) of
        true ->
            subpath_from_current(Subpath, origin(), Format);

        false ->
            serialize_absolute_subpath(Subpath, Format)
    end.

-file("src/svg_path/serialize.gleam", 250).
?DOC(
    " Serialize a subpath with default options.\n"
    "\n"
    " Empty subpaths serialize as move-only subpaths. Closed subpaths end in `Z`.\n"
).
-spec subpath(svg_path:subpath()) -> binary().
subpath(Subpath) ->
    subpath_with_options(Subpath, default_options()).

-file("src/svg_path/serialize.gleam", 905).
-spec segment_with_move_numbers(svg_path:segment(), options()) -> list(float()).
segment_with_move_numbers(Segment, Options) ->
    Start = svg_path:segment_start(Segment),
    case erlang:element(4, Options) of
        true ->
            lists:append(
                point_numbers(Start),
                relative_segment_numbers(Segment, Options)
            );

        false ->
            lists:append(
                point_numbers(Start),
                absolute_segment_numbers(Segment, Options)
            )
    end.

-file("src/svg_path/serialize.gleam", 275).
?DOC(" Serialize a segment with custom options.\n").
-spec segment_with_options(svg_path:segment(), options()) -> binary().
segment_with_options(Segment, Options) ->
    Format = serialization_format(
        Options,
        segment_with_move_numbers(Segment, Options)
    ),
    Start = svg_path:segment_start(Segment),
    case erlang:element(4, Options) of
        true ->
            join_commands(
                [command(<<"m"/utf8>>, point(Start, Format), Format),
                    relative_segment_without_move(Segment, Format)],
                Format
            );

        false ->
            join_commands(
                [command(<<"M"/utf8>>, point(Start, Format), Format),
                    absolute_segment_without_move(Segment, Format)],
                Format
            )
    end.

-file("src/svg_path/serialize.gleam", 270).
?DOC(" Serialize a segment with default options.\n").
-spec segment(svg_path:segment()) -> binary().
segment(Segment) ->
    segment_with_options(Segment, default_options()).