1 import Base 2 import ../types/model.bend as T 3 import ./cache.bend as S 4 import ./clock.bend as Clock 5 import ./public_commands.bend as P 6 7 # A caller may catch a failure and issue the next command. Each result retains 8 # the partial state and exact unused provider events. No failure becomes success. 9 type Trace<-K: Data, -V: Data> is Data: 10 Finished{state: S.Model, remaining: List<&2, Clock.ClockEvent>, observations: List<&2, P.CmdResult>, requests: Nat} 11 12 def state(-K: Data, -V: Data, result: P.CmdResult) -> S.Model: 13 match result: 14 case P.Returned{s, reply, events, count}: s 15 case P.Failed{s, error, events, count}: s 16 17 def remaining(-K: Data, -V: Data, result: P.CmdResult) -> List<&2, Clock.ClockEvent>: 18 match result: 19 case P.Returned{s, reply, events, count}: events 20 case P.Failed{s, error, events, count}: events 21 22 def requests(-K: Data, -V: Data, result: P.CmdResult) -> Nat: 23 match result: 24 case P.Returned{s, reply, events, count}: count 25 case P.Failed{s, error, events, count}: count 26 27 def prepend(-K: Data, -V: Data, +result: P.CmdResult, rest: Trace) -> Trace: 28 Finished{s, events, observations, count} = rest 29 Finished{s, events, Con{result, observations}, Nat.add(requests(K, V, result), count)} 30 31 def run(~K: Data, ~same: K -> K -> Bool, -V: Data, commands: List<&2, S.Command>, s: S.Model, +zero_key: K, +zero_value: V, events: List<&2, Clock.ClockEvent>) -> Trace: 32 match commands: 33 case Nil{}: Finished{s, events, Nil{}, 0n} 34 case Con{command, tail}: 35 +result = P.execute(~K, ~same, V, s, zero_key, zero_value, events, command) 36 prepend(K, V, result, run(~K, ~same, V, tail, state(K, V, result), zero_key, zero_value, remaining(K, V, result)))