Current section
Files
Jump to
Current section
Files
src/plushie@testing@command_processor.erl
-module(plushie@testing@command_processor).
-compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]).
-define(FILEPATH, "src/plushie/testing/command_processor.gleam").
-export([process_commands/4]).
-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(
" Synchronous command processor for test backends.\n"
"\n"
" Executes async, stream, done, and batch commands synchronously so that\n"
" update side effects resolve immediately in tests. Widget ops, window\n"
" ops, timers, and cancel are silently skipped (they need a renderer).\n"
"\n"
" Since execution is synchronous, await_async returns immediately --\n"
" commands have already completed by the time it is called.\n"
).
-file("src/plushie/testing/command_processor.gleam", 100).
-spec batch_process(
plushie@app:app(SPJ, SPK),
SPJ,
list(plushie@command:command(SPK)),
integer(),
integer(),
list(plushie@event:event())
) -> {SPJ, list(plushie@event:event())}.
batch_process(App, Model, Commands, Depth, Max_depth, Events) ->
case Commands of
[] ->
{Model, Events};
[Cmd | Rest] ->
{Model@1, Events@1} = do_process(
App,
Model,
Cmd,
Depth,
Max_depth,
Events
),
batch_process(App, Model@1, Rest, Depth, Max_depth, Events@1)
end.
-file("src/plushie/testing/command_processor.gleam", 38).
-spec do_process(
plushie@app:app(SPC, SPD),
SPC,
plushie@command:command(SPD),
integer(),
integer(),
list(plushie@event:event())
) -> {SPC, list(plushie@event:event())}.
do_process(App, Model, Cmd, Depth, Max_depth, Events) ->
case Depth > Max_depth of
true ->
{Model, Events};
false ->
case Cmd of
none ->
{Model, Events};
{batch, Commands} ->
batch_process(
App,
Model,
Commands,
Depth,
Max_depth,
Events
);
{done, Value, Mapper} ->
Msg = Mapper(Value),
Update_fn = plushie@app:get_update(App),
{New_model, New_commands} = Update_fn(Model, Msg),
do_process(
App,
New_model,
New_commands,
Depth + 1,
Max_depth,
Events
);
{async, Work, Tag} ->
Result = Work(),
dispatch_async_result(
App,
Model,
Tag,
{ok, Result},
Depth,
Max_depth,
Events
);
{stream, Work@1, Tag@1} ->
Values = plushie_test_ffi:collect_stream_values(Work@1),
{Model@1, Events@1} = drain_stream_values(
App,
Model,
Tag@1,
erlang:element(1, Values),
Depth,
Max_depth,
Events
),
dispatch_async_result(
App,
Model@1,
Tag@1,
{ok, erlang:element(2, Values)},
Depth,
Max_depth,
Events@1
);
_ ->
{Model, Events}
end
end.
-file("src/plushie/testing/command_processor.gleam", 25).
?DOC(
" Process commands synchronously, threading model state through each\n"
" update dispatch. Returns the final model and list of events processed.\n"
"\n"
" `max_depth` controls recursion depth: `None` uses the default limit,\n"
" `Some(n)` uses n.\n"
).
-spec process_commands(
plushie@app:app(SOV, SOW),
SOV,
plushie@command:command(SOW),
gleam@option:option(integer())
) -> {SOV, list(plushie@event:event())}.
process_commands(App, Model, Commands, Max_depth) ->
Effective_max = case Max_depth of
{some, N} ->
N;
none ->
100
end,
do_process(App, Model, Commands, 0, Effective_max, []).
-file("src/plushie/testing/command_processor.gleam", 118).
-spec dispatch_async_result(
plushie@app:app(SPR, any()),
SPR,
binary(),
{ok, gleam@dynamic:dynamic_()} | {error, gleam@dynamic:dynamic_()},
integer(),
integer(),
list(plushie@event:event())
) -> {SPR, list(plushie@event:event())}.
dispatch_async_result(App, Model, Tag, Result, Depth, Max_depth, Events) ->
Raw_event = {async_result, Tag, Result},
Events@1 = [Raw_event | Events],
case plushie@app:get_on_event(App) of
{some, On_event} ->
Msg = On_event(Raw_event),
Update_fn = plushie@app:get_update(App),
{New_model, New_commands} = Update_fn(Model, Msg),
do_process(
App,
New_model,
New_commands,
Depth + 1,
Max_depth,
Events@1
);
none ->
Msg@1 = plushie_test_ffi:identity(Raw_event),
Update_fn@1 = plushie@app:get_update(App),
{New_model@1, New_commands@1} = Update_fn@1(Model, Msg@1),
do_process(
App,
New_model@1,
New_commands@1,
Depth + 1,
Max_depth,
Events@1
)
end.
-file("src/plushie/testing/command_processor.gleam", 145).
-spec dispatch_stream_value(
plushie@app:app(SPZ, any()),
SPZ,
binary(),
gleam@dynamic:dynamic_(),
integer(),
integer(),
list(plushie@event:event())
) -> {SPZ, list(plushie@event:event())}.
dispatch_stream_value(App, Model, Tag, Value, Depth, Max_depth, Events) ->
Raw_event = {stream_value, Tag, Value},
Events@1 = [Raw_event | Events],
case plushie@app:get_on_event(App) of
{some, On_event} ->
Msg = On_event(Raw_event),
Update_fn = plushie@app:get_update(App),
{New_model, New_commands} = Update_fn(Model, Msg),
do_process(
App,
New_model,
New_commands,
Depth + 1,
Max_depth,
Events@1
);
none ->
Msg@1 = plushie_test_ffi:identity(Raw_event),
Update_fn@1 = plushie@app:get_update(App),
{New_model@1, New_commands@1} = Update_fn@1(Model, Msg@1),
do_process(
App,
New_model@1,
New_commands@1,
Depth + 1,
Max_depth,
Events@1
)
end.
-file("src/plushie/testing/command_processor.gleam", 172).
-spec drain_stream_values(
plushie@app:app(SQF, any()),
SQF,
binary(),
list(gleam@dynamic:dynamic_()),
integer(),
integer(),
list(plushie@event:event())
) -> {SQF, list(plushie@event:event())}.
drain_stream_values(App, Model, Tag, Values, Depth, Max_depth, Events) ->
case Values of
[] ->
{Model, Events};
[Value | Rest] ->
{Model@1, Events@1} = dispatch_stream_value(
App,
Model,
Tag,
Value,
Depth,
Max_depth,
Events
),
drain_stream_values(
App,
Model@1,
Tag,
Rest,
Depth,
Max_depth,
Events@1
)
end.