-module(lightspeed@async). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/lightspeed/async.gleam"). -export([new/1, connected/1, assign_async/2, connect/1, disconnect/1, state_label/1, succeed/3, fail/3, cancel/3, state/2, error_to_string/1]). -export_type([async_state/1, async_error/0, async_entry/1, runtime/1]). -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(" LiveView-style async assign/task compatibility model.\n"). -type async_state(GFS) :: idle | pending_disconnected | {loading, integer()} | {succeeded, GFS} | {failed, binary()} | {cancelled, binary()}. -type async_error() :: {unknown_task, binary()} | {invalid_transition, binary(), binary(), binary()}. -type async_entry(GFT) :: {async_entry, binary(), async_state(GFT)}. -opaque runtime(GFU) :: {runtime, boolean(), integer(), list(async_entry(GFU))}. -file("src/lightspeed/async.gleam", 32). ?DOC(" Build a runtime.\n"). -spec new(boolean()) -> runtime(any()). new(Connected) -> {runtime, Connected, 1, []}. -file("src/lightspeed/async.gleam", 37). ?DOC(" Connection status.\n"). -spec connected(runtime(any())) -> boolean(). connected(Runtime) -> erlang:element(2, Runtime). -file("src/lightspeed/async.gleam", 203). -spec put_entry(list(async_entry(GIA)), binary(), async_state(GIA)) -> list(async_entry(GIA)). put_entry(Entries_rev, Key, State) -> case Entries_rev of [] -> [{async_entry, Key, State}]; [Entry | Rest] -> case erlang:element(2, Entry) =:= Key of true -> [{async_entry, erlang:element(2, Entry), State} | Rest]; false -> [Entry | put_entry(Rest, Key, State)] end end. -file("src/lightspeed/async.gleam", 45). ?DOC( " Start one async assignment.\n" "\n" " - when connected: enters `Loading(ref)`\n" " - when disconnected: enters `PendingDisconnected`\n" ). -spec assign_async(runtime(GFZ), binary()) -> {runtime(GFZ), async_state(GFZ)}. assign_async(Runtime, Key) -> case erlang:element(2, Runtime) of true -> Ref = erlang:element(3, Runtime), State = {loading, Ref}, Entries_rev = put_entry(erlang:element(4, Runtime), Key, State), {{runtime, erlang:element(2, Runtime), Ref + 1, Entries_rev}, State}; false -> State@1 = pending_disconnected, Entries_rev@1 = put_entry(erlang:element(4, Runtime), Key, State@1), {{runtime, erlang:element(2, Runtime), erlang:element(3, Runtime), Entries_rev@1}, State@1} end. -file("src/lightspeed/async.gleam", 218). -spec start_pending(list(async_entry(GIG)), integer(), list(async_entry(GIG))) -> {integer(), list(async_entry(GIG))}. start_pending(Entries, Next_ref, Entries_rev) -> case Entries of [] -> {Next_ref, Entries_rev}; [Entry | Rest] -> case erlang:element(3, Entry) of pending_disconnected -> start_pending( Rest, Next_ref + 1, [{async_entry, erlang:element(2, Entry), {loading, Next_ref}} | Entries_rev] ); _ -> start_pending(Rest, Next_ref, [Entry | Entries_rev]) end end. -file("src/lightspeed/async.gleam", 66). ?DOC(" Mark runtime connected and start pending async assignments.\n"). -spec connect(runtime(GGD)) -> runtime(GGD). connect(Runtime) -> {Next_ref, Entries_rev} = start_pending( lists:reverse(erlang:element(4, Runtime)), erlang:element(3, Runtime), [] ), {runtime, true, Next_ref, Entries_rev}. -file("src/lightspeed/async.gleam", 74). ?DOC(" Mark runtime disconnected.\n"). -spec disconnect(runtime(GGG)) -> runtime(GGG). disconnect(Runtime) -> {runtime, false, erlang:element(3, Runtime), erlang:element(4, Runtime)}. -file("src/lightspeed/async.gleam", 145). ?DOC(" Stable state label for logs and assertions.\n"). -spec state_label(async_state(any())) -> binary(). state_label(State) -> case State of idle -> <<"idle"/utf8>>; pending_disconnected -> <<"pending_disconnected"/utf8>>; {loading, _} -> <<"loading"/utf8>>; {succeeded, _} -> <<"succeeded"/utf8>>; {failed, _} -> <<"failed"/utf8>>; {cancelled, _} -> <<"cancelled"/utf8>> end. -file("src/lightspeed/async.gleam", 253). -spec reverse_into(list(GIS), list(GIS)) -> list(GIS). reverse_into(Left, Right) -> case Left of [] -> Right; [Entry | Rest] -> reverse_into(Rest, [Entry | Right]) end. -file("src/lightspeed/async.gleam", 177). -spec update_state( list(async_entry(GHN)), binary(), fun((async_state(GHN)) -> {ok, async_state(GHN)} | {error, async_error()}), list(async_entry(GHN)) ) -> {ok, list(async_entry(GHN))} | {error, async_error()}. update_state(Entries_rev, Key, With, Seen_rev) -> case Entries_rev of [] -> {error, {unknown_task, Key}}; [Entry | Rest] -> case erlang:element(2, Entry) =:= Key of false -> update_state(Rest, Key, With, [Entry | Seen_rev]); true -> case With(erlang:element(3, Entry)) of {error, Error} -> {error, Error}; {ok, State} -> {ok, reverse_into( Seen_rev, [{async_entry, erlang:element(2, Entry), State} | Rest] )} end end end. -file("src/lightspeed/async.gleam", 165). -spec transition( runtime(GHE), binary(), binary(), fun((async_state(GHE)) -> {ok, async_state(GHE)} | {error, async_error()}) ) -> {runtime(GHE), {ok, nil} | {error, async_error()}}. transition(Runtime, Key, _, With) -> case update_state(erlang:element(4, Runtime), Key, With, []) of {error, Error} -> {Runtime, {error, Error}}; {ok, Entries_rev} -> {{runtime, erlang:element(2, Runtime), erlang:element(3, Runtime), Entries_rev}, {ok, nil}} end. -file("src/lightspeed/async.gleam", 79). ?DOC(" Resolve one async assignment with a success value.\n"). -spec succeed(runtime(GGJ), binary(), GGJ) -> {runtime(GGJ), {ok, nil} | {error, async_error()}}. succeed(Runtime, Key, Value) -> transition(Runtime, Key, <<"succeed"/utf8>>, fun(State) -> case State of {loading, _} -> {ok, {succeeded, Value}}; _ -> {error, {invalid_transition, Key, state_label(State), <<"succeed"/utf8>>}} end end). -file("src/lightspeed/async.gleam", 98). ?DOC(" Resolve one async assignment with a failure.\n"). -spec fail(runtime(GGO), binary(), binary()) -> {runtime(GGO), {ok, nil} | {error, async_error()}}. fail(Runtime, Key, Reason) -> transition(Runtime, Key, <<"fail"/utf8>>, fun(State) -> case State of {loading, _} -> {ok, {failed, Reason}}; _ -> {error, {invalid_transition, Key, state_label(State), <<"fail"/utf8>>}} end end). -file("src/lightspeed/async.gleam", 117). ?DOC(" Cancel one async assignment.\n"). -spec cancel(runtime(GGT), binary(), binary()) -> {runtime(GGT), {ok, nil} | {error, async_error()}}. cancel(Runtime, Key, Reason) -> transition(Runtime, Key, <<"cancel"/utf8>>, fun(State) -> case State of pending_disconnected -> {ok, {cancelled, Reason}}; {loading, _} -> {ok, {cancelled, Reason}}; _ -> {error, {invalid_transition, Key, state_label(State), <<"cancel"/utf8>>}} end end). -file("src/lightspeed/async.gleam", 239). -spec find_state(list(async_entry(GIN)), binary()) -> gleam@option:option(async_state(GIN)). find_state(Entries_rev, Key) -> case Entries_rev of [] -> none; [Entry | Rest] -> case erlang:element(2, Entry) =:= Key of true -> {some, erlang:element(3, Entry)}; false -> find_state(Rest, Key) end end. -file("src/lightspeed/async.gleam", 137). ?DOC(" Lookup current state for one task key.\n"). -spec state(runtime(GGY), binary()) -> gleam@option:option(async_state(GGY)). state(Runtime, Key) -> find_state(erlang:element(4, Runtime), Key). -file("src/lightspeed/async.gleam", 157). ?DOC(" Stable error string for assertions and logs.\n"). -spec error_to_string(async_error()) -> binary(). error_to_string(Error) -> case Error of {unknown_task, Key} -> <<"unknown_task:"/utf8, Key/binary>>; {invalid_transition, Key@1, State, Action} -> <<<<<<<<<<"invalid_transition:"/utf8, Key@1/binary>>/binary, ":"/utf8>>/binary, State/binary>>/binary, ":"/utf8>>/binary, Action/binary>> end.