-module(pig@session_store@memory). -compile([no_auto_import, nowarn_unused_vars, nowarn_unused_function, nowarn_nomatch, inline]). -define(FILEPATH, "src/pig/session_store/memory.gleam"). -export([start/1, snapshot/1, store/1, stop/1]). -export_type([memory_store/0, store_message/0, state/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(" In-memory, actor-serialized implementation of the synchronous session store.\n"). -opaque memory_store() :: {memory_store, gleam@erlang@process:subject(store_message())}. -type store_message() :: {commit, pig@session_store:session_commit(), gleam@erlang@process:subject({ok, pig@session_store:session()} | {error, pig@session_store:session_error()})} | {snapshot, gleam@erlang@process:subject(pig@session_store:session())} | stop. -type state() :: {state, pig@session_store:session(), gleam@dict:dict(binary(), pig@session_store:session_commit())}. -file("src/pig/session_store/memory.gleam", 82). -spec apply_commit(state(), pig@session_store:session_commit()) -> {{ok, pig@session_store:session()} | {error, pig@session_store:session_error()}, state()}. apply_commit(State, Next) -> {session_commit, Id, Parent, Messages} = Next, case Messages of [] -> {{error, {invalid_commit, <<"a commit must contain at least one message"/utf8>>}}, State}; _ -> case gleam_stdlib:map_get(erlang:element(3, State), Id) of {ok, Previous} -> case (erlang:element(3, Previous) =:= Parent) andalso (erlang:element( 4, Previous ) =:= Messages) of true -> {{ok, erlang:element(2, State)}, State}; false -> {{error, {corrupt, <<"commit ID was reused with different contents"/utf8>>}}, State} end; {error, _} -> case Parent =:= erlang:element(2, erlang:element(2, State)) of false -> {{error, {parent_conflict, Parent, erlang:element( 2, erlang:element(2, State) )}}, State}; true -> Session = {session, {some, Id}, lists:append( erlang:element(3, erlang:element(2, State)), Messages )}, {{ok, Session}, {state, Session, gleam@dict:insert( erlang:element(3, State), Id, Next )}} end end end. -file("src/pig/session_store/memory.gleam", 67). -spec handle_message(state(), store_message()) -> gleam@otp@actor:next(state(), any()). handle_message(State, Message) -> case Message of {snapshot, Reply_to} -> gleam@erlang@process:send(Reply_to, erlang:element(2, State)), gleam@otp@actor:continue(State); {commit, Next, Reply_to@1} -> {Result, Next_state} = apply_commit(State, Next), gleam@erlang@process:send(Reply_to@1, Result), gleam@otp@actor:continue(Next_state); stop -> gleam@otp@actor:stop() end. -file("src/pig/session_store/memory.gleam", 29). ?DOC(" Start an in-memory store with `initial` as its durable session.\n"). -spec start(pig@session_store:session()) -> {ok, memory_store()} | {error, gleam@otp@actor:start_error()}. start(Initial) -> Builder = begin _pipe = gleam@otp@actor:new({state, Initial, maps:new()}), gleam@otp@actor:on_message(_pipe, fun handle_message/2) end, case gleam@otp@actor:start(Builder) of {ok, Started} -> {ok, {memory_store, erlang:element(3, Started)}}; {error, Error} -> {error, Error} end. -file("src/pig/session_store/memory.gleam", 59). -spec commit_session(memory_store(), pig@session_store:session_commit()) -> {ok, pig@session_store:session()} | {error, pig@session_store:session_error()}. commit_session(Handle, Next) -> {memory_store, Subject} = Handle, gleam@otp@actor:call( Subject, 5000, fun(Reply_to) -> {commit, Next, Reply_to} end ). -file("src/pig/session_store/memory.gleam", 48). ?DOC(" Return a consistent snapshot of the current session.\n"). -spec snapshot(memory_store()) -> pig@session_store:session(). snapshot(Handle) -> {memory_store, Subject} = Handle, gleam@otp@actor:call(Subject, 5000, fun(Field@0) -> {snapshot, Field@0} end). -file("src/pig/session_store/memory.gleam", 41). ?DOC(" Adapt an in-memory store to the public synchronous session-store contract.\n"). -spec store(memory_store()) -> pig@session_store:session_store(). store(Handle) -> {session_store, fun() -> {ok, snapshot(Handle)} end, fun(Next) -> commit_session(Handle, Next) end}. -file("src/pig/session_store/memory.gleam", 54). ?DOC(" Stop the store actor.\n"). -spec stop(memory_store()) -> nil. stop(Handle) -> {memory_store, Subject} = Handle, gleam@otp@actor:send(Subject, stop).