relation_providers.bend

bendvy-ecs-core@0.1.0.0 · 76 lines · 0 definitions

1import Base
2import bendvy-ecs-core@0.1.0.0/deferred_command.bend as Deferred
3import bendvy-ecs-core@0.1.0.0/trace_facts.bend as TraceFacts
4import entity_key.bend as Key
5import relation_types.bend as G
6import relation_commands.bend as A
7import world.bend as W
8import transaction.bend as X
9import capabilities.bend as Cap
10
11# Descriptor is closed by schema provisioning; gameplay has no descriptor argument.
12# Inverse capability exposes only a snapshot query, never a setter for the table.
13type Targets<S: Data> is Data:
14  Targets{source: W.Handle<S>,target: W.Handle<S>}
15type ReadOnly<-H: Type,S: Data> is Type:
16  ReadOnly{inverse: Cap.Request<H,W.Handle<S>,Maybe<&2,List<&2,W.Handle<S>>>>}
17type Writable<-H: Type,S: Data> is Type:
18  Writable{inverse: Cap.Request<H,W.Handle<S>,Maybe<&2,List<&2,W.Handle<S>>>>,relate: Cap.Request<H,Targets<S>,A.QueueStatus>,unrelate: Cap.Request<H,W.Handle<S>,A.QueueStatus>}
19def read_field(~H: Type,~S: Data,caps: ReadOnly<H,S>) -> Cap.Request<H,W.Handle<S>,Maybe<&2,List<&2,W.Handle<S>>>>:
20  match caps:
21    case ReadOnly{inverse}: inverse
22def write_inverse_field(~H: Type,~S: Data,caps: Writable<H,S>) -> Cap.Request<H,W.Handle<S>,Maybe<&2,List<&2,W.Handle<S>>>>:
23  match caps:
24    case Writable{inverse,_,_}: inverse
25def relate_field(~H: Type,~S: Data,caps: Writable<H,S>) -> Cap.Request<H,Targets<S>,A.QueueStatus>:
26  match caps:
27    case Writable{_,relate,_}: relate
28def clear_field(~H: Type,~S: Data,caps: Writable<H,S>) -> Cap.Request<H,W.Handle<S>,A.QueueStatus>:
29  match caps:
30    case Writable{_,_,clear}: clear
31def read(~H: Type,~S: Data,~caps: ReadOnly<H,S>,owner: H,target: W.Handle<S>) -> H & Maybe<&2,List<&2,W.Handle<S>>>:
32  Cap.request(~H,~W.Handle<S>,~Maybe<&2,List<&2,W.Handle<S>>>,~read_field(~H,~S,caps),owner,target)
33def inverse(~H: Type,~S: Data,~caps: Writable<H,S>,owner: H,target: W.Handle<S>) -> H & Maybe<&2,List<&2,W.Handle<S>>>:
34  Cap.request(~H,~W.Handle<S>,~Maybe<&2,List<&2,W.Handle<S>>>,~write_inverse_field(~H,~S,caps),owner,target)
35def relate(~H: Type,~S: Data,~caps: Writable<H,S>,owner: H,targets: Targets<S>) -> H & A.QueueStatus:
36  Cap.request(~H,~Targets<S>,~A.QueueStatus,~relate_field(~H,~S,caps),owner,targets)
37def unrelate(~H: Type,~S: Data,~caps: Writable<H,S>,owner: H,source: W.Handle<S>) -> H & A.QueueStatus:
38  Cap.request(~H,~W.Handle<S>,~A.QueueStatus,~clear_field(~H,~S,caps),owner,source)
39def handle_ids(~S: Data,ids: List<&2,Key.Key>,+namespace: U32) -> List<&2,W.Handle<S>>:
40  match ids:
41    case []: []
42    case id <> rest: W.Handle{namespace,id} <> handle_ids(~S,rest,namespace)
43def handle_snapshot(~S: Data,value: Maybe<&2,List<&2,Key.Key>>,namespace: U32) -> Maybe<&2,List<&2,W.Handle<S>>>:
44  match value:
45    case None{}: None{}
46    case Some{ids}: Some{handle_ids(~S,ids,namespace)}
47def inverse_handles(~S: Data,~C: Type,~R: Type,~E: Data,result: W.World<S,A.Store<S,C>,R,A.Notice<S,E>> & Maybe<&2,List<&2,Key.Key>>,target: W.Handle<S>) -> W.World<S,A.Store<S,C>,R,A.Notice<S,E>> & Maybe<&2,List<&2,W.Handle<S>>>:
48  match result target:
49    case (world,value) W.Handle{ns,_}: (world,handle_snapshot(~S,value,ns))
50def inverse_tx_done(~S: Data,~C: Type,~R: Type,~E: Data,result: W.World<S,A.Store<S,C>,R,A.Notice<S,E>> & Maybe<&2,List<&2,W.Handle<S>>>,undo: List<(W.World<S,A.Store<S,C>,R,A.Notice<S,E>> -> W.World<S,A.Store<S,C>,R,A.Notice<S,E>>)>,commands:List<Deferred.Command<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>>>,events: List<&2,A.Notice<S,E>>,trace:TraceFacts.State) -> X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & Maybe<&2,List<&2,W.Handle<S>>>:
51  (world,value) = result
52  (X.Tx{world,undo,commands,events,trace},value)
53def inverse_tx(~S: Data,~C: Type,~R: Type,~E: Data,~descriptor: G.Descriptor<S>,tx: X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>>,target: W.Handle<S>) -> X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & Maybe<&2,List<&2,W.Handle<S>>>:
54  match tx target:
55    case X.Tx{world,undo,commands,events,trace} W.Handle{+ns,+id}: inverse_tx_done(~S,~C,~R,~E,inverse_handles(~S,~C,~R,~E,A.inverse(~S,~C,~R,~E,world,descriptor,W.Handle{ns,id}),W.Handle{ns,id}),undo,commands,events,trace)
56def relate_tx(~S: Data,~C: Type,~R: Type,~E: Data,~descriptor: G.Descriptor<S>,tx: X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>>,targets: Targets<S>) -> X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & A.QueueStatus:
57  match targets:
58    case Targets{source,target}: A.queue_relate(~S,~C,~R,~E,tx,descriptor,source,target)
59def clear_tx(~S: Data,~C: Type,~R: Type,~E: Data,~descriptor: G.Descriptor<S>,tx: X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>>,source: W.Handle<S>) -> X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & A.QueueStatus:
60  A.queue_unrelate(~S,~C,~R,~E,tx,descriptor,source)
61def provide_read(~S: Data,~C: Type,~R: Type,~E: Data,~descriptor: G.Descriptor<S>) -> ReadOnly<X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>>,S>:
62  ReadOnly{Cap.Request{inverse_tx(~S,~C,~R,~E,~descriptor)}}
63def provide_write(~S: Data,~C: Type,~R: Type,~E: Data,~descriptor: G.Descriptor<S>) -> Writable<X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>>,S>:
64  Writable{Cap.Request{inverse_tx(~S,~C,~R,~E,~descriptor)},Cap.Request{relate_tx(~S,~C,~R,~E,~descriptor)},Cap.Request{clear_tx(~S,~C,~R,~E,~descriptor)}}
65# Rank-two abstract owners with live affine capability bundles. Erased bundles
66# cannot be scrutinized in live code; the prior rejected sketches are retained.
67def relate_live(-H: Type,-S: Data,caps: Writable<H,S>,owner: H,args: Targets<S>) -> H & A.QueueStatus:
68  match caps:
69    case Writable{_,Cap.Request{relate},_}: relate(owner,args)
70def read_live(-H: Type,-S: Data,caps: ReadOnly<H,S>,owner: H,target: W.Handle<S>) -> H & Maybe<&2,List<&2,W.Handle<S>>>:
71  match caps:
72    case ReadOnly{Cap.Request{get}}: get(owner,target)
73def invoke_write(~S: Data,~C: Type,~R: Type,~E: Data,~descriptor: G.Descriptor<S>,~Out: Type,~body: @-H: Type -> Writable<H,S> -> Targets<S> -> H -> H & Out,args: Targets<S>,tx: X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>>) -> X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & Out:
74  body(X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>>,provide_write(~S,~C,~R,~E,~descriptor),args,tx)
75def invoke_read(~S: Data,~C: Type,~R: Type,~E: Data,~descriptor: G.Descriptor<S>,~Out: Type,~body: @-H: Type -> ReadOnly<H,S> -> W.Handle<S> -> H -> H & Out,target: W.Handle<S>,tx: X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>>) -> X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>> & Out:
76  body(X.Tx<W.World<S,A.Store<S,C>,R,A.Notice<S,E>>,A.Notice<S,E>>,provide_read(~S,~C,~R,~E,~descriptor),target,tx)