transaction.bend
bendvy-ecs-core@0.1.0.4 · 131 lines · 18 definitions
1import Base
2import bendvy-ecs-core@0.1.0.4/deferred_command.bend as Deferred
3import bendvy-ecs-core@0.1.0.4/trace_facts.bend as TraceFacts
4
5
6
7
8
9
10
11type Tx<W: Type, E: Data> is Type:
12 Tx{world: W, undo: List<&1, (W -> W)>, commands:List<&1, Deferred.Command<W>>, events: List<&2, E>,trace:TraceFacts.State}
13
14
15
16type Outcome<Error: Data> is Data:
17 Success{}
18 Failure{error: Error}
19
20
21
22type Returned<W: Type, Error: Data> is Type:
23 Returned{world: W, outcome: Outcome<Error>}
24
25
26
27def begin(~W: Type, ~E: Data, world: W) -> Tx<W, E>:
28 Tx{world, [], [], [],TraceFacts.Off{}}
29
30
31
32
33def add_undo(~W: Type, ~E: Data, tx: Tx<W, E>, inverse: W -> W) -> Tx<W, E>:
34 match tx:
35 case Tx{world, undo, commands, events,trace}:
36 Tx{world, inverse <> undo, commands, events,trace}
37
38
39
40
41
42def stage_command(~W:Type,~E:Data,tx:Tx<W,E>,command:Deferred.Command<W>) -> Tx<W,E>:
43 match tx:
44 case Tx{world,undo,commands,events,trace}:Tx{world,undo,command <> commands,events,trace}
45
46
47
48def stage(~W: Type, ~E: Data, tx: Tx<W, E>, command: W -> W) -> Tx<W, E>:
49 match tx:
50 case Tx{world, undo, commands, events,trace}:
51 Tx{world, undo, Deferred.Raw{command} <> commands, events,trace}
52
53
54
55
56def emit(~W: Type, ~E: Data, tx: Tx<W, E>, event: E) -> Tx<W, E>:
57 match tx:
58 case Tx{world, undo, commands, events,trace}:
59 Tx{world, undo, commands, event <> events,trace}
60
61
62
63
64def rollback(~W: Type, undo: List<&1, (W -> W)>, world: W) -> W:
65 match undo:
66 case Nil{}:
67 world
68 case Con{inverse, rest}:
69 rollback(~W, rest, inverse(world))
70
71def finish_world(~W: Type, ~E: Data, ~Error: Data,
72 ~enqueue: W -> List<&1,Deferred.Command<W>> -> W,
73 ~publish: W -> List<&2, E> -> W,
74 world: W, undo: List<&1, (W -> W)>, commands:List<&1, Deferred.Command<W>>, events: List<&2, E>, outcome: Outcome<Error>
75) -> Returned<W, Error>:
76 match outcome:
77 case Success{}:
78 committed = enqueue(world, List.reverse(&1,Deferred.Command<W>,commands))
79 Returned{publish(committed, List.reverse(&2, E, events)), Success{}}
80 case Failure{error}:
81 Returned{rollback(~W, undo, world), Failure{error}}
82
83
84
85
86
87
88def finish(~W: Type, ~E: Data, ~Error: Data,
89 ~enqueue: W -> List<&1,Deferred.Command<W>> -> W,
90 ~publish: W -> List<&2, E> -> W,
91 tx: Tx<W, E>, outcome: Outcome<Error>
92) -> Returned<W, Error>:
93 match tx:
94 case Tx{world, undo, commands, events,trace}:
95 finish_world(~W, ~E, ~Error, ~enqueue, ~publish, world, undo, commands, events, outcome)
96
97
98
99def begin_observed(~W:Type,~E:Data,world:W) -> Tx<W,E>:
100 Tx{world,[],[],[],TraceFacts.On{[]}}
101
102
103def trace_enabled(~W:Type,~E:Data,tx:Tx<W,E>) -> Tx<W,E> & Bool:
104 match tx:
105 case Tx{world,undo,commands,events,+trace}:(Tx{world,undo,commands,events,trace},TraceFacts.enabled(trace))
106
107
108def record(~W:Type,~E:Data,tx:Tx<W,E>,fact:TraceFacts.Fact) -> Tx<W,E>:
109 match tx:
110 case Tx{world,undo,commands,events,trace}:Tx{world,undo,commands,events,TraceFacts.append(trace,fact)}
111def committed(~Error:Data,outcome:Outcome<Error>) -> Bool:
112 match outcome:
113 case Success{}:True{}
114 case Failure{_}:False{}
115
116
117
118def finish_observed(~W:Type,~E:Data,~Error:Data,~enqueue:W -> List<&1,Deferred.Command<W>> -> W,~publish:W -> List<&2,E> -> W,tx:Tx<W,E>,+outcome:Outcome<Error>) -> Returned<W,Error> & TraceFacts.State:
119 match tx:
120 case Tx{world,undo,commands,events,trace}:(finish_world(~W,~E,~Error,~enqueue,~publish,world,undo,commands,events,outcome),TraceFacts.settle(trace,committed(~Error,outcome)))
121
122
123
124
125def begin_with_trace(~W:Type,~E:Data,world:W,trace:TraceFacts.State) -> Tx<W,E>:
126 Tx{world,[],[],[],trace}
127
128
129def annotate_newest(~W:Type,~E:Data,tx:Tx<W,E>,before:TraceFacts.Value,after:TraceFacts.Value) -> Tx<W,E>:
130 match tx:
131 case Tx{world,undo,commands,events,trace}:Tx{world,undo,commands,events,TraceFacts.annotate_newest(trace,before,after)}