execution_recoverable_component.bend

bendvy-ecs-core@0.1.0.3 · 69 lines · 16 definitions

1import Base
2import bendvy-ecs-core@0.1.0.3/world.bend as W
3import bendvy-ecs-core@0.1.0.3/chunk_column.bend as Column
4import bendvy-ecs-core@0.1.0.3/execution_composer_layout.bend as Layout
5import bendvy-ecs-core@0.1.0.3/execution_layout_access.bend as Access
6import bendvy-ecs-core@0.1.0.3/execution_query_identity.bend as Identity
7import bendvy-ecs-core@0.1.0.3/execution_resource_policy.bend as Policy
8import bendvy-ecs-core@0.1.0.3/recoverable_component.bend as RC
9import bendvy-ecs-core@0.1.0.3/lifecycle.bend as Life
10import bendvy-ecs-core@0.1.0.3/change_tick.bend as Tick
11
12# Explicit recovery boundary; ordinary scheduling does not invoke this facility.
13type Exchange<-P:Type> is Type:
14  Exchanged{stamp:Life.Stamp,previous:Maybe<P>}
15  ExchangeRefused{incoming:Maybe<P>}
16def packed(~layout:Layout.Layout,~route:Layout.Route,incoming:Maybe<Layout.payload(layout,route)>) -> Maybe<Layout.stored(layout,route)>:
17  match incoming:
18    case None{}:None{}
19    case Some{owner}:Some{Layout.initialize(layout,route,owner)}
20def unpacked(~P:Type,~V:Data,incoming:Maybe<Layout.Viewed<P,V>>) -> Maybe<P>:
21  match incoming:
22    case None{}:None{}
23    case Some{Layout.Viewed{owner,_}}:Some{owner}
24def restore_optional(~S:Data,~P:Type,column:Column.Column<S,P>,index:U32,saved:Maybe<&2,Life.Stamp>) -> Column.Column<S,P>:
25  match saved:
26    case None{}:column
27    case Some{stamp}:Column.restore_stamp(~S,~P,column,index,stamp)
28def swapped(~S:Data,~layout:Layout.Layout,~route:Layout.Route,index:U32,prior:Life.Stamp,saved:Maybe<&2,Life.Stamp>,result:Column.SwapOutcome<S,Layout.stored(layout,route)>) -> Column.Column<S,Layout.stored(layout,route)> & Exchange<Layout.payload(layout,route)>:
29  match result:
30    case Column.Accepted{column,previous}:(restore_optional(~S,~Layout.stored(layout,route),column,index,saved),Exchanged{prior,unpacked(~Layout.payload(layout,route),~Layout.view(layout,route),previous)})
31    case Column.Rejected{column,incoming}:(column,ExchangeRefused{unpacked(~Layout.payload(layout,route),~Layout.view(layout,route),incoming)})
32def observed(~S:Data,~layout:Layout.Layout,~route:Layout.Route,+index:U32,incoming:Maybe<Layout.payload(layout,route)>,tick:Tick.Tick,saved:Maybe<&2,Life.Stamp>,result:Column.Column<S,Layout.stored(layout,route)> & Maybe<&2,Life.Stamp>) -> Column.Column<S,Layout.stored(layout,route)> & Exchange<Layout.payload(layout,route)>:
33  match result:
34    case (column,None{}):(column,ExchangeRefused{incoming})
35    case (column,Some{prior}):swapped(~S,~layout,~route,index,prior,saved,Column.swap_at(~S,~Layout.stored(layout,route),column,index,packed(~layout,~route,incoming),tick))
36def column_returned(~S:Data,~C:Type,~layout:Layout.Layout,~route:Layout.Route,~same:{C == Layout.columns(~S,layout) : Type},rest:Layout.column_rest(~S,layout,route),result:Column.Column<S,Layout.stored(layout,route)> & Exchange<Layout.payload(layout,route)>) -> C & Exchange<Layout.payload(layout,route)>:
37  match result:
38    case (column,result):(Access.column_put(~S,~C,~layout,~route,~same,rest,column),result)
39def column_taken(~S:Data,~C:Type,~layout:Layout.Layout,~route:Layout.Route,~same:{C == Layout.columns(~S,layout) : Type},+index:U32,incoming:Maybe<Layout.payload(layout,route)>,tick:Tick.Tick,saved:Maybe<&2,Life.Stamp>,result:Layout.column_rest(~S,layout,route) & Column.Column<S,Layout.stored(layout,route)>) -> C & Exchange<Layout.payload(layout,route)>:
40  match result:
41    case (rest,column):column_returned(~S,~C,~layout,~route,~same,rest,observed(~S,~layout,~route,index,incoming,tick,saved,Column.lifecycle(~S,~Layout.stored(layout,route),column,index)))
42def exchange(~S:Data,~C:Type,~layout:Layout.Layout,~route:Layout.Route,~same:{C == Layout.columns(~S,layout) : Type},index:U32,incoming:Maybe<Layout.payload(layout,route)>,tick:Tick.Tick,saved:Maybe<&2,Life.Stamp>,columns:C) -> C & Exchange<Layout.payload(layout,route)>:
43  column_taken(~S,~C,~layout,~route,~same,index,incoming,tick,saved,Access.column_take(~S,~C,~layout,~route,~same,columns))
44def replaced(~S:Data,~C:Type,~R:Type,~E:Data,~P:Type,handle:W.Handle<S>,result:W.World<S,C,R,E> & Exchange<P>) -> RC.Replacement<W.World<S,C,R,E>,S,P>:
45  match result:
46    case (world,Exchanged{stamp,previous}):RC.Applied{world,RC.Record{handle,stamp,previous}}
47    case (world,ExchangeRefused{incoming}):RC.Refused{world,incoming,W.CapacityExceeded{}}
48def timed(~S:Data,~C:Type,~R:Type,~E:Data,~layout:Layout.Layout,~route:Layout.Route,~same:{C == Layout.columns(~S,layout) : Type},handle:W.Handle<S>,index:U32,incoming:Maybe<Layout.payload(layout,route)>,result:W.World<S,C,R,E> & Tick.Tick) -> RC.Replacement<W.World<S,C,R,E>,S,Layout.payload(layout,route)>:
49  match result:
50    case (world,tick):replaced(~S,~C,~R,~E,~Layout.payload(layout,route),handle,W.with_store(~S,~C,~R,~E,~Exchange<Layout.payload(layout,route)>,exchange(~S,~C,~layout,~route,~same,index,incoming,tick,None{}),world))
51def offset(~S:Data,~C:Type,~R:Type,~E:Data,~layout:Layout.Layout,~route:Layout.Route,~same:{C == Layout.columns(~S,layout) : Type},incoming:Maybe<Layout.payload(layout,route)>,result:W.World<S,C,R,E> & Identity.Offset<S>) -> RC.Replacement<W.World<S,C,R,E>,S,Layout.payload(layout,route)>:
52  match result:
53    case (world,Identity.Physical{handle,index}):timed(~S,~C,~R,~E,~layout,~route,~same,handle,index,incoming,W.write_clock(~S,~C,~R,~E,world))
54    case (world,Identity.MissingEntity{_}):RC.Refused{world,incoming,W.MissingEntity{}}
55    case (world,Identity.OutsideStorage{_,_}):RC.Refused{world,incoming,W.CapacityExceeded{}}
56def replace(~S:Data,~C:Type,~R:Type,~E:Data,~layout:Layout.Layout,~route:Layout.Route,~same:{C == Layout.columns(~S,layout) : Type},~valid:{Layout.grant_valid(~layout,~route) == True{} : Bool},~ordinary:{Layout.policy(layout,route) == Policy.Ordinary{} : Policy.Policy},world:W.World<S,C,R,E>,handle:W.Handle<S>,incoming:Maybe<Layout.payload(layout,route)>) -> RC.Replacement<W.World<S,C,R,E>,S,Layout.payload(layout,route)>:
57  offset(~S,~C,~R,~E,~layout,~route,~same,incoming,Identity.world_offset(~S,~C,~R,~E,world,Column.maximum_capacity(),handle))
58def undone(~S:Data,~C:Type,~R:Type,~E:Data,~P:Type,handle:W.Handle<S>,saved:Life.Stamp,result:W.World<S,C,R,E> & Exchange<P>) -> W.World<S,C,R,E> & RC.Record<S,P>:
59  match result:
60    case (world,Exchanged{stamp,previous}):(world,RC.Record{handle,stamp,previous})
61    case (world,ExchangeRefused{incoming}):(world,RC.Record{handle,saved,incoming})
62def undo_offset(~S:Data,~C:Type,~R:Type,~E:Data,~layout:Layout.Layout,~route:Layout.Route,~same:{C == Layout.columns(~S,layout) : Type},+stamp:Life.Stamp,payload:Maybe<Layout.payload(layout,route)>,result:W.World<S,C,R,E> & Identity.Offset<S>) -> W.World<S,C,R,E> & RC.Record<S,Layout.payload(layout,route)>:
63  match result:
64    case (world,Identity.Physical{+handle,index}):undone(~S,~C,~R,~E,~Layout.payload(layout,route),handle,stamp,W.with_store(~S,~C,~R,~E,~Exchange<Layout.payload(layout,route)>,exchange(~S,~C,~layout,~route,~same,index,payload,Tick.zero(),Some{stamp}),world))
65    case (world,Identity.MissingEntity{handle}):(world,RC.Record{handle,stamp,payload})
66    case (world,Identity.OutsideStorage{handle,_}):(world,RC.Record{handle,stamp,payload})
67def undo(~S:Data,~C:Type,~R:Type,~E:Data,~layout:Layout.Layout,~route:Layout.Route,~same:{C == Layout.columns(~S,layout) : Type},~valid:{Layout.grant_valid(~layout,~route) == True{} : Bool},~ordinary:{Layout.policy(layout,route) == Policy.Ordinary{} : Policy.Policy},record:RC.Record<S,Layout.payload(layout,route)>,world:W.World<S,C,R,E>) -> W.World<S,C,R,E> & RC.Record<S,Layout.payload(layout,route)>:
68  match record:
69    case RC.Record{handle,stamp,payload}:undo_offset(~S,~C,~R,~E,~layout,~route,~same,stamp,payload,Identity.world_offset(~S,~C,~R,~E,world,Column.maximum_capacity(),handle))