Packages

Type-safe finite state machine library for Gleam

Current section

Files

Jump to
scamper src scamper@visualization.erl
Raw

src/scamper@visualization.erl

-module(scamper@visualization).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/scamper/visualization.gleam").
-export([to_mermaid/4, to_dot/4, machine_to_string/2]).
-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(
" Visualization utilities for scamper FSMs.\n"
"\n"
" Generate Mermaid diagrams, DOT graphs, and string representations.\n"
).
-file("src/scamper/visualization.gleam", 13).
?DOC(" Generate a Mermaid stateDiagram-v2 string from the config.\n").
-spec to_mermaid(
scamper@config:config(JAO, any(), JAQ),
JAO,
fun((JAO) -> binary()),
fun((JAQ) -> binary())
) -> binary().
to_mermaid(Config, Initial_state, State_to_string, Event_to_string) ->
Transitions = scamper@config:get_transitions(Config),
Final_states = scamper@config:get_final_states(Config),
Header = <<"stateDiagram-v2"/utf8>>,
Initial_arrow = <<" [*] --> "/utf8,
(State_to_string(Initial_state))/binary>>,
Transition_lines = begin
_pipe = Transitions,
gleam@list:map(
_pipe,
fun(Rule) ->
Label = Event_to_string(erlang:element(3, Rule)),
Guard_suffix = case gleam@option:is_some(
erlang:element(5, Rule)
) of
true ->
<<" [guarded]"/utf8>>;
false ->
<<""/utf8>>
end,
<<<<<<<<<<<<" "/utf8,
(State_to_string(
erlang:element(2, Rule)
))/binary>>/binary,
" --> "/utf8>>/binary,
(State_to_string(erlang:element(4, Rule)))/binary>>/binary,
" : "/utf8>>/binary,
Label/binary>>/binary,
Guard_suffix/binary>>
end
)
end,
Final_lines = begin
_pipe@1 = Final_states,
gleam@list:map(
_pipe@1,
fun(S) ->
<<<<" "/utf8, (State_to_string(S))/binary>>/binary,
" --> [*]"/utf8>>
end
)
end,
_pipe@2 = [Header, Initial_arrow],
_pipe@3 = lists:append(_pipe@2, Transition_lines),
_pipe@4 = lists:append(_pipe@3, Final_lines),
gleam@string:join(_pipe@4, <<"\n"/utf8>>).
-file("src/scamper/visualization.gleam", 57).
?DOC(" Generate a DOT (Graphviz) graph string from the config.\n").
-spec to_dot(
scamper@config:config(JAU, any(), JAW),
JAU,
fun((JAU) -> binary()),
fun((JAW) -> binary())
) -> binary().
to_dot(Config, Initial_state, State_to_string, Event_to_string) ->
Transitions = scamper@config:get_transitions(Config),
Final_states = scamper@config:get_final_states(Config),
Header_lines = [<<"digraph FSM {"/utf8>>,
<<" rankdir=LR;"/utf8>>,
<<" node [shape=circle];"/utf8>>,
<<" __start__ [shape=point];"/utf8>>],
Final_node_lines = begin
_pipe = Final_states,
gleam@list:map(
_pipe,
fun(S) ->
<<<<" "/utf8, (State_to_string(S))/binary>>/binary,
" [shape=doublecircle];"/utf8>>
end
)
end,
Initial_edge = <<<<" __start__ -> "/utf8,
(State_to_string(Initial_state))/binary>>/binary,
";"/utf8>>,
Transition_lines = begin
_pipe@1 = Transitions,
gleam@list:map(
_pipe@1,
fun(Rule) ->
Label = Event_to_string(erlang:element(3, Rule)),
Guard_suffix = case gleam@option:is_some(
erlang:element(5, Rule)
) of
true ->
<<" [guarded]"/utf8>>;
false ->
<<""/utf8>>
end,
<<<<<<<<<<<<<<" "/utf8,
(State_to_string(
erlang:element(2, Rule)
))/binary>>/binary,
" -> "/utf8>>/binary,
(State_to_string(erlang:element(4, Rule)))/binary>>/binary,
" [label=\""/utf8>>/binary,
Label/binary>>/binary,
Guard_suffix/binary>>/binary,
"\"];"/utf8>>
end
)
end,
Footer = <<"}"/utf8>>,
_pipe@2 = Header_lines,
_pipe@3 = lists:append(_pipe@2, Final_node_lines),
_pipe@4 = lists:append(_pipe@3, [Initial_edge]),
_pipe@5 = lists:append(_pipe@4, Transition_lines),
_pipe@6 = lists:append(_pipe@5, [Footer]),
gleam@string:join(_pipe@6, <<"\n"/utf8>>).
-file("src/scamper/visualization.gleam", 114).
?DOC(" Generate a one-line summary of a machine's current state.\n").
-spec machine_to_string(
scamper:machine(JBA, any(), any()),
fun((JBA) -> binary())
) -> binary().
machine_to_string(Machine, State_to_string) ->
State_str = State_to_string(scamper:current_state(Machine)),
History_count = erlang:length(scamper:history(Machine)),
<<<<<<<<"Machine(state: "/utf8, State_str/binary>>/binary,
", history: "/utf8>>/binary,
(erlang:integer_to_binary(History_count))/binary>>/binary,
")"/utf8>>.