relation_commands.bend

bendvy-ecs-core@0.1.0.1 · 115 lines · 0 definitions

1import Base
2import bendvy-ecs-core@0.1.0.1/trace_relation.bend as TraceRel
3import bendvy-ecs-core@0.1.0.1/deferred_command.bend as Deferred
4import bendvy-ecs-core@0.1.0.1/trace_facts.bend as TraceFacts
5import entity_key.bend as Key
6import relation_types.bend as G
7import relation_graph.bend as C
8import world.bend as W
9import transaction.bend as X
10
11# Experiment-only transport: never duplicates or inspects arbitrary component owners.
12# This initial seam implements relate/unrelate, not linked cleanup or keyed retention.
13type Store<S: Data,Components: Type> is Type:
14  Store{components: Components,graph: G.Graph<S>}
15type Notice<S: Data,Original: Data> is Data:
16  Original{event: Original}
17  RelationFailed{failure: G.Failure<S>}
18  ComponentRemoved{id:Key.Key}
19  CleanupPaused{frames: List<&2,G.CleanupFrame<S>>}
20type QueueStatus is Data:
21  Queued{}
22  MissingEntity{}
23def empty(~S: Data,~C: Type,components: C) -> Store<S,C>:
24  Store{components,G.Graph{[],[]}}
25def graph_read(~S: Data,~C: Type,store: Store<S,C>) -> Store<S,C> & G.Graph<S>:
26  match store:
27    case Store{components,+graph}: (Store{components,graph},graph)
28def graph_replace(~S: Data,~C: Type,store: Store<S,C>,replacement: G.Graph<S>) -> Store<S,C>:
29  match store:
30    case Store{components,_}: Store{components,replacement}
31def relate_result(~S: Data,~C: Type,result: G.CoreResult<S>,components: C) -> Store<S,C> & Maybe<&2,G.Error>:
32  match result:
33    case G.CoreResult{graph,error}: (Store{components,graph},error)
34def store_relate(~S: Data,~C: Type,store: Store<S,C>,descriptor: G.Descriptor<S>,source:Key.Key,target:Key.Key,sourceLive: Bool,targetLive: Bool) -> Store<S,C> & Maybe<&2,G.Error>:
35  match store:
36    case Store{components,graph}: relate_result(~S,~C,C.relate(~S,graph,descriptor,source,target,sourceLive,targetLive),components)
37def publish_relate(~S: Data,~C: Type,~R: Type,~E: Data,observed: W.World<S,Store<S,C>,R,Notice<S,E>> & Maybe<&2,G.Error>,descriptor: G.Descriptor<S>,source:Key.Key,target:Key.Key) -> W.World<S,Store<S,C>,R,Notice<S,E>>:
38  match observed:
39    case (world,None{}): world
40    case (world,Some{error}): W.event_publish(~S,~Store<S,C>,~R,~Notice<S,E>,world,[RelationFailed{G.Failure{descriptor,G.Relate{},source,target,error}}])
41def apply_live_result(~S: Data,~C: Type,~R: Type,~E: Data,checked: W.World<S,Store<S,C>,R,Notice<S,E>> & Bool,+descriptor: G.Descriptor<S>,+source:Key.Key,+target:Key.Key,sourceLive: Bool) -> W.World<S,Store<S,C>,R,Notice<S,E>> & Maybe<&2,G.Error>:
42  (world,targetLive) = checked
43  W.with_store(~S,~Store<S,C>,~R,~Notice<S,E>,~Maybe<&2,G.Error>,store => store_relate(~S,~C,store,descriptor,source,target,sourceLive,targetLive),world)
44def apply_source_result(~S: Data,~C: Type,~R: Type,~E: Data,checked: W.World<S,Store<S,C>,R,Notice<S,E>> & Bool,descriptor: G.Descriptor<S>,source:Key.Key,target:Key.Key,targetHandle: W.Handle<S>) -> W.World<S,Store<S,C>,R,Notice<S,E>> & Maybe<&2,G.Error>:
45  (world,sourceLive) = checked
46  apply_live_result(~S,~C,~R,~E,W.valid(~S,~Store<S,C>,~R,~Notice<S,E>,world,targetHandle),descriptor,source,target,sourceLive)
47def apply_relate_result(~S: Data,~C: Type,~R: Type,~E: Data,world: W.World<S,Store<S,C>,R,Notice<S,E>>,descriptor: G.Descriptor<S>,+source: W.Handle<S>,+target: W.Handle<S>) -> W.World<S,Store<S,C>,R,Notice<S,E>> & Maybe<&2,G.Error>:
48  match source target:
49    case W.Handle{+sn,+sid} W.Handle{+tn,+tid}: apply_source_result(~S,~C,~R,~E,W.valid(~S,~Store<S,C>,~R,~Notice<S,E>,world,W.Handle{sn,sid}),descriptor,sid,tid,W.Handle{tn,tid})
50def apply_relate(~S:Data,~C:Type,~R:Type,~E:Data,world:W.World<S,Store<S,C>,R,Notice<S,E>>,+descriptor:G.Descriptor<S>,+source:W.Handle<S>,+target:W.Handle<S>) -> W.World<S,Store<S,C>,R,Notice<S,E>>:
51  publish_relate(~S,~C,~R,~E,apply_relate_result(~S,~C,~R,~E,world,descriptor,source,target),descriptor,W.handle_key(~S,source),W.handle_key(~S,target))
52def applied_relate_traced(~S:Data,~C:Type,~R:Type,~E:Data,trace:TraceFacts.State,+descriptor:G.Descriptor<S>,+source:W.Handle<S>,+target:W.Handle<S>,result:W.World<S,Store<S,C>,R,Notice<S,E>> & Maybe<&2,G.Error>) -> W.World<S,Store<S,C>,R,Notice<S,E>> & TraceFacts.State:
53  match result:
54    case (world,+error):(publish_relate(~S,~C,~R,~E,(world,error),descriptor,W.handle_key(~S,source),W.handle_key(~S,target)),TraceRel.relate_applied(~S,trace,descriptor,source,target,error))
55def relate_command(~S:Data,~C:Type,~R:Type,~E:Data,enabled:Bool,+descriptor:G.Descriptor<S>,+source:W.Handle<S>,+target:W.Handle<S>) -> Deferred.Command<W.World<S,Store<S,C>,R,Notice<S,E>>>:
56  match enabled:
57    case False{}:Deferred.Raw{world=>apply_relate(~S,~C,~R,~E,world,descriptor,source,target)}
58    case True{}:Deferred.Observed{trace=>world=>applied_relate_traced(~S,~C,~R,~E,trace,descriptor,source,target,apply_relate_result(~S,~C,~R,~E,world,descriptor,source,target))}
59def relate_staged(~S:Data,~C:Type,~R:Type,~E:Data,+descriptor:G.Descriptor<S>,+source:W.Handle<S>,+target:W.Handle<S>,tx:X.Tx<W.World<S,Store<S,C>,R,Notice<S,E>>,Notice<S,E>>) -> X.Tx<W.World<S,Store<S,C>,R,Notice<S,E>>,Notice<S,E>>:
60  match tx:
61    case X.Tx{world,undo,commands,events,+trace}:X.Tx{world,undo,relate_command(~S,~C,~R,~E,TraceFacts.enabled(trace),descriptor,source,target) <> commands,events,TraceRel.relate(~S,trace,descriptor,TraceFacts.StageOperation{},source,target,TraceFacts.Attempted{})}
62def relate_refused(~S:Data,~C:Type,~R:Type,~E:Data,descriptor:G.Descriptor<S>,source:W.Handle<S>,target:W.Handle<S>,tx:X.Tx<W.World<S,Store<S,C>,R,Notice<S,E>>,Notice<S,E>>) -> X.Tx<W.World<S,Store<S,C>,R,Notice<S,E>>,Notice<S,E>>:
63  match tx:
64    case X.Tx{world,undo,commands,events,trace}:X.Tx{world,undo,commands,events,TraceRel.relate(~S,trace,descriptor,TraceFacts.StageOperation{},source,target,TraceFacts.Refused{"MissingEntity"})}
65def queue_checked(~S: Data,~C: Type,~R: Type,~E: Data,same: Bool,tx: X.Tx<W.World<S,Store<S,C>,R,Notice<S,E>>,Notice<S,E>>,descriptor: G.Descriptor<S>,source: W.Handle<S>,target: W.Handle<S>) -> X.Tx<W.World<S,Store<S,C>,R,Notice<S,E>>,Notice<S,E>> & QueueStatus:
66  match same:
67    case False{}: (relate_refused(~S,~C,~R,~E,descriptor,source,target,tx),MissingEntity{})
68    case True{}: (relate_staged(~S,~C,~R,~E,descriptor,source,target,tx),Queued{})
69def queue_namespaced(~S: Data,~C: Type,~R: Type,~E: Data,checked: W.World<S,Store<S,C>,R,Notice<S,E>> & U32,undo: List<(W.World<S,Store<S,C>,R,Notice<S,E>> -> W.World<S,Store<S,C>,R,Notice<S,E>>)>,commands:List<Deferred.Command<W.World<S,Store<S,C>,R,Notice<S,E>>>>,events: List<&2,Notice<S,E>>,trace:TraceFacts.State,descriptor: G.Descriptor<S>,source: W.Handle<S>,target: W.Handle<S>) -> X.Tx<W.World<S,Store<S,C>,R,Notice<S,E>>,Notice<S,E>> & QueueStatus:
70  match checked source target:
71    case (world,+namespace) W.Handle{+sn,+sid} W.Handle{+tn,+tid}: queue_checked(~S,~C,~R,~E,Bool.and(U32.is_eq(namespace,sn),U32.is_eq(namespace,tn)),X.Tx{world,undo,commands,events,trace},descriptor,W.Handle{sn,sid},W.Handle{tn,tid})
72def queue_relate(~S: Data,~C: Type,~R: Type,~E: Data,tx: X.Tx<W.World<S,Store<S,C>,R,Notice<S,E>>,Notice<S,E>>,descriptor: G.Descriptor<S>,source: W.Handle<S>,target: W.Handle<S>) -> X.Tx<W.World<S,Store<S,C>,R,Notice<S,E>>,Notice<S,E>> & QueueStatus:
73  match tx:
74    case X.Tx{world,undo,commands,events,trace}: queue_namespaced(~S,~C,~R,~E,W.namespace(~S,~Store<S,C>,~R,~Notice<S,E>,world),undo,commands,events,trace,descriptor,source,target)
75def store_unrelate(~S: Data,~C: Type,store: Store<S,C>,descriptor: G.Descriptor<S>,source:Key.Key) -> Store<S,C> & Unit:
76  match store:
77    case Store{components,graph}: (Store{components,C.unrelate(~S,graph,descriptor,source)},Unit{})
78def discard_unit(~S: Data,~C: Type,~R: Type,~E: Data,result: W.World<S,Store<S,C>,R,Notice<S,E>> & Unit) -> W.World<S,Store<S,C>,R,Notice<S,E>>:
79  (world,_) = result
80  world
81def apply_unrelate(~S: Data,~C: Type,~R: Type,~E: Data,world: W.World<S,Store<S,C>,R,Notice<S,E>>,descriptor: G.Descriptor<S>,source: W.Handle<S>) -> W.World<S,Store<S,C>,R,Notice<S,E>>:
82  match source:
83    case W.Handle{_,id}: discard_unit(~S,~C,~R,~E,W.with_store(~S,~Store<S,C>,~R,~Notice<S,E>,~Unit,store => store_unrelate(~S,~C,store,descriptor,id),world))
84def unrelate_command(~S:Data,~C:Type,~R:Type,~E:Data,enabled:Bool,+descriptor:G.Descriptor<S>,+source:W.Handle<S>) -> Deferred.Command<W.World<S,Store<S,C>,R,Notice<S,E>>>:
85  match enabled:
86    case False{}:Deferred.Raw{world=>apply_unrelate(~S,~C,~R,~E,world,descriptor,source)}
87    case True{}:Deferred.Observed{trace=>world=>(apply_unrelate(~S,~C,~R,~E,world,descriptor,source),TraceRel.unrelate(~S,trace,descriptor,TraceFacts.ApplyOperation{},source,TraceFacts.Applied{}))}
88def unrelate_staged(~S:Data,~C:Type,~R:Type,~E:Data,+descriptor:G.Descriptor<S>,+source:W.Handle<S>,tx:X.Tx<W.World<S,Store<S,C>,R,Notice<S,E>>,Notice<S,E>>) -> X.Tx<W.World<S,Store<S,C>,R,Notice<S,E>>,Notice<S,E>>:
89  match tx:
90    case X.Tx{world,undo,commands,events,+trace}:X.Tx{world,undo,unrelate_command(~S,~C,~R,~E,TraceFacts.enabled(trace),descriptor,source) <> commands,events,TraceRel.unrelate(~S,trace,descriptor,TraceFacts.StageOperation{},source,TraceFacts.Attempted{})}
91def unrelate_refused(~S:Data,~C:Type,~R:Type,~E:Data,descriptor:G.Descriptor<S>,source:W.Handle<S>,tx:X.Tx<W.World<S,Store<S,C>,R,Notice<S,E>>,Notice<S,E>>) -> X.Tx<W.World<S,Store<S,C>,R,Notice<S,E>>,Notice<S,E>>:
92  match tx:
93    case X.Tx{world,undo,commands,events,trace}:X.Tx{world,undo,commands,events,TraceRel.unrelate(~S,trace,descriptor,TraceFacts.StageOperation{},source,TraceFacts.Refused{"MissingEntity"})}
94def queue_clear_checked(~S: Data,~C: Type,~R: Type,~E: Data,same: Bool,tx: X.Tx<W.World<S,Store<S,C>,R,Notice<S,E>>,Notice<S,E>>,descriptor: G.Descriptor<S>,source: W.Handle<S>) -> X.Tx<W.World<S,Store<S,C>,R,Notice<S,E>>,Notice<S,E>> & QueueStatus:
95  match same:
96    case False{}: (unrelate_refused(~S,~C,~R,~E,descriptor,source,tx),MissingEntity{})
97    case True{}: (unrelate_staged(~S,~C,~R,~E,descriptor,source,tx),Queued{})
98def queue_clear_namespaced(~S: Data,~C: Type,~R: Type,~E: Data,checked: W.World<S,Store<S,C>,R,Notice<S,E>> & U32,undo: List<(W.World<S,Store<S,C>,R,Notice<S,E>> -> W.World<S,Store<S,C>,R,Notice<S,E>>)>,commands:List<Deferred.Command<W.World<S,Store<S,C>,R,Notice<S,E>>>>,events: List<&2,Notice<S,E>>,trace:TraceFacts.State,descriptor: G.Descriptor<S>,source: W.Handle<S>) -> X.Tx<W.World<S,Store<S,C>,R,Notice<S,E>>,Notice<S,E>> & QueueStatus:
99  match checked source:
100    case (world,namespace) W.Handle{+sn,+sid}: queue_clear_checked(~S,~C,~R,~E,U32.is_eq(namespace,sn),X.Tx{world,undo,commands,events,trace},descriptor,W.Handle{sn,sid})
101def queue_unrelate(~S: Data,~C: Type,~R: Type,~E: Data,tx: X.Tx<W.World<S,Store<S,C>,R,Notice<S,E>>,Notice<S,E>>,descriptor: G.Descriptor<S>,source: W.Handle<S>) -> X.Tx<W.World<S,Store<S,C>,R,Notice<S,E>>,Notice<S,E>> & QueueStatus:
102  match tx:
103    case X.Tx{world,undo,commands,events,trace}: queue_clear_namespaced(~S,~C,~R,~E,W.namespace(~S,~Store<S,C>,~R,~Notice<S,E>,world),undo,commands,events,trace,descriptor,source)
104def store_inverse(~S: Data,~C: Type,store: Store<S,C>,descriptor: G.Descriptor<S>,target:Key.Key) -> Store<S,C> & List<&2,Key.Key>:
105  match store:
106    case Store{components,+graph}: (Store{components,graph},C.inverse(~S,graph,descriptor,target))
107def inverse_present(~S: Data,~C: Type,~R: Type,~E: Data,result: W.World<S,Store<S,C>,R,Notice<S,E>> & List<&2,Key.Key>) -> W.World<S,Store<S,C>,R,Notice<S,E>> & Maybe<&2,List<&2,Key.Key>>:
108  (world,sources) = result
109  (world,Some{sources})
110def inverse_checked(~S: Data,~C: Type,~R: Type,~E: Data,checked: W.World<S,Store<S,C>,R,Notice<S,E>> & Bool,descriptor: G.Descriptor<S>,target: W.Handle<S>) -> W.World<S,Store<S,C>,R,Notice<S,E>> & Maybe<&2,List<&2,Key.Key>>:
111  match checked target:
112    case (world,False{}) _: (world,None{})
113    case (world,True{}) W.Handle{_,id}: inverse_present(~S,~C,~R,~E,W.with_store(~S,~Store<S,C>,~R,~Notice<S,E>,~List<&2,Key.Key>,store => store_inverse(~S,~C,store,descriptor,id),world))
114def inverse(~S: Data,~C: Type,~R: Type,~E: Data,world: W.World<S,Store<S,C>,R,Notice<S,E>>,descriptor: G.Descriptor<S>,+target: W.Handle<S>) -> W.World<S,Store<S,C>,R,Notice<S,E>> & Maybe<&2,List<&2,Key.Key>>:
115  inverse_checked(~S,~C,~R,~E,W.valid(~S,~Store<S,C>,~R,~Notice<S,E>,world,target),descriptor,target)