ordinary_capture_query.bend

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

1import Base
2import bendvy-ecs-core@0.1.0.0/change_tick.bend as Tick
3import bendvy-ecs-core@0.1.0.0/world.bend as W
4import bendvy-ecs-core@0.1.0.0/compose.bend as Q
5import bendvy-ecs-core@0.1.0.0/capture_query.bend as Fold
6import bendvy-ecs-core@0.1.0.0/ordinary_query_declaration.bend as Decl
7import bendvy-ecs-core@0.1.0.0/ordinary_system.bend as Ordinary
8import bendvy-ecs-core@0.1.0.0/local.bend as Local
9import bendvy-ecs-core@0.1.0.0/captures.bend as Capture
10import bendvy-ecs-core@0.1.0.0/transaction.bend as T
11# Capture lifecycle reuses Local; each completed run consumes its captured tick.
12# Advanced lowering of the closed query declaration into its typed grant
13# and membership predicate; it performs no traversal or capture mutation.
14def plan(~S:Data,~C:Type,~R:Type,~E:Data,~L:Type,~Ops:Type -> Type,~A:Data,~U:Data,~Out:Data,~query:Decl.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>)>,~body:@-H:Type -> @-caps:Ops(H) -> L -> A -> H -> H & (L & (T.Outcome<U> & Out))) -> Q.Plan<S,C,R,E,Ops>:
15  Q.Plan{Decl.grant(~S,~Q.Frame<S,C,R,E>,~Ops(Q.Frame<S,C,R,E>),query),Decl.selector(~S,~Q.Frame<S,C,R,E>,~Ops(Q.Frame<S,C,R,E>),query)}
16def finished(~S:Data,~C:Type,~R:Type,~E:Data,~L:Type,~U:Data,~Out:Data,result:Fold.Executed<W.World<S,C,R,E>,L,Q.Error<U>,Out>) -> Local.Outcome<W.World<S,C,R,E>,L,Q.Error<U>,List<&2,Out>>:
17  match result:
18    case Fold.Executed{world,capture,T.Success{},values}:Local.Succeeded{world,capture,values}
19    case Fold.Executed{world,capture,T.Failure{error},_}:Local.Failed{world,capture,error}
20# Advanced captured-query runner with explicit (args,cursor). Threads L
21# through selected rows while the ECS transaction journals World changes.
22# Failure retains returned capture but discards row outputs. Bypasses runtime
23# registration checks; ordinary callers use define/run or App capture add.
24def runner(~S:Data,~C:Type,~R:Type,~E:Data,~L:Type,~Ops:Type -> Type,~A:Data,~U:Data,~Out:Data,~query:Decl.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>)>,~body:@-H:Type -> @-caps:Ops(H) -> L -> A -> H -> H & (L & (T.Outcome<U> & Out)),world:W.World<S,C,R,E>,capture:L,args:A & Maybe<&2,Tick.Tick>) -> Local.Outcome<W.World<S,C,R,E>,L,Q.Error<U>,List<&2,Out>>:
25  match args:
26    case (args,cursor):finished(~S,~C,~R,~E,~L,~U,~Out,Fold.each_since(~S,~C,~R,~E,~L,~U,~Out,~Ops,~A,~plan(~S,~C,~R,~E,~L,~Ops,~A,~U,~Out,~query,~body),~body,args,cursor,capture,world))
27# Runtime-bound captured-query owner: a Local instance owns affine capture L
28# and a separate cursor tracks query lifecycle visibility. Keep both returned
29# parts together across runs; raw constructors are trusted administration.
30type Owner<-S:Data,-C:Type,-R:Type,-E:Data,-L:Type,-Ops:Type -> Type,-A:Data,-U:Data,-Out:Data,-query:Decl.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>)>,-body:@-H:Type -> @-caps:Ops(H) -> L -> A -> H -> H & (L & (T.Outcome<U> & Out))> is Type:
31  Owner{instance:Local.Instance<S,C,R,E,L,A & Maybe<&2,Tick.Tick>,Q.Error<U>,List<&2,Out>,runner(~S,~C,~R,~E,~L,~Ops,~A,~U,~Out,~query,~body)>,cursor:Maybe<&2,Tick.Tick>}
32# Registered returns World and captured-query owner; Rejected returns
33# World and initial capture L without invoking the query body.
34type Registration<World:Type,Owned:Type,L:Type> is Type:
35  Registered{world:World,owner:Owned}
36  Rejected{world:World,capture:L}
37# Completed returns World, retained capture owner and ordered row outputs
38# or query error. Refused returns World/owner and original Data args before
39# body execution. Capture state survives body failure; failed row outputs do not.
40type Run<World:Type,Owned:Type,A:Data,Error:Data,Out:Data> is Type:
41  Completed{world:World,owner:Owned,result:Result<Error,List<&2,Out>>}
42  Refused{world:World,owner:Owned,args:A}
43# Removed returns World and detached affine capture after deregistration.
44# RemovalRejected returns World and original owner. No finalizer is invoked
45# here: caller decides how to reuse or dispose the returned capture.
46type Removal<World:Type,Owned:Type,L:Type> is Type:
47  Removed{world:World,capture:L}
48  RemovalRejected{world:World,owner:Owned}
49def registered(~S:Data,~C:Type,~R:Type,~E:Data,~L:Type,~Ops:Type -> Type,~A:Data,~U:Data,~Out:Data,~query:Decl.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>)>,~body:@-H:Type -> @-caps:Ops(H) -> L -> A -> H -> H & (L & (T.Outcome<U> & Out)),result:Local.Registered<S,C,R,E,L,A & Maybe<&2,Tick.Tick>,Q.Error<U>,List<&2,Out>,runner(~S,~C,~R,~E,~L,~Ops,~A,~U,~Out,~query,~body)>) -> Registration<W.World<S,C,R,E>,Owner<S,C,R,E,L,Ops,A,U,Out,query,body>,L>:
50  match result:
51    case Local.Registered{world,instance}:Registered{world,Owner{instance,None{}}}
52    case Local.RegistrationRejected{world,capture}:Rejected{world,capture}
53# Register a captured query with access derived from the same declaration.
54# Consumes capture; refusal returns it with World. Success owns a real Local
55# registration and initializes an absent query cursor. No body runs at setup.
56# Example: examples/captured-query/app.bend.
57def define(~S:Data,~C:Type,~R:Type,~E:Data,~L:Type,~Ops:Type -> Type,~A:Data,~U:Data,~Out:Data,~query:Decl.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>)>,~body:@-H:Type -> @-caps:Ops(H) -> L -> A -> H -> H & (L & (T.Outcome<U> & Out)),world:W.World<S,C,R,E>,name:String,capture:L) -> Registration<W.World<S,C,R,E>,Owner<S,C,R,E,L,Ops,A,U,Out,query,body>,L>:
58  registered(~S,~C,~R,~E,~L,~Ops,~A,~U,~Out,~query,~body,Capture.register(~S,~C,~R,~E,~L,~(A & Maybe<&2,Tick.Tick>),~Q.Error<U>,~List<&2,Out>,~runner(~S,~C,~R,~E,~L,~Ops,~A,~U,~Out,~query,~body),world,name,Ordinary.access(~S,Decl.clauses(~S,~Q.Frame<S,C,R,E>,~Ops(Q.Frame<S,C,R,E>),query)),capture))
59def returned(~S:Data,~C:Type,~R:Type,~E:Data,~L:Type,~Ops:Type -> Type,~A:Data,~U:Data,~Out:Data,~query:Decl.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>)>,~body:@-H:Type -> @-caps:Ops(H) -> L -> A -> H -> H & (L & (T.Outcome<U> & Out)),cursor:Maybe<&2,Tick.Tick>,result:Local.Run<S,C,R,E,L,A & Maybe<&2,Tick.Tick>,Q.Error<U>,List<&2,Out>,runner(~S,~C,~R,~E,~L,~Ops,~A,~U,~Out,~query,~body)>) -> Run<W.World<S,C,R,E>,Owner<S,C,R,E,L,Ops,A,U,Out,query,body>,A,Q.Error<U>,Out>:
60  match result:
61    case Local.Completed{world,instance,Done{values},tick}:Completed{world,Owner{instance,Some{tick}},Done{values}}
62    case Local.Completed{world,instance,Fail{error},tick}:Completed{world,Owner{instance,Some{tick}},Fail{error}}
63    case Local.Refused{world,instance,(args,_)}:Refused{world,Owner{instance,cursor},args}
64# Execute the checked captured-query registration at its retained cursor.
65# Completed success/error consume the captured execution tick; refusal preserves it.
66# Query failure rolls back recorded World changes but retains capture changes;
67# registration refusal returns original args without running body. Deferred
68# commands remain invisible until explicit barriers.
69def run(~S:Data,~C:Type,~R:Type,~E:Data,~L:Type,~Ops:Type -> Type,~A:Data,~U:Data,~Out:Data,~query:Decl.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>)>,~body:@-H:Type -> @-caps:Ops(H) -> L -> A -> H -> H & (L & (T.Outcome<U> & Out)),owner:Owner<S,C,R,E,L,Ops,A,U,Out,query,body>,world:W.World<S,C,R,E>,args:A) -> Run<W.World<S,C,R,E>,Owner<S,C,R,E,L,Ops,A,U,Out,query,body>,A,Q.Error<U>,Out>:
70  match owner:
71    case Owner{instance,+cursor}:returned(~S,~C,~R,~E,~L,~Ops,~A,~U,~Out,~query,~body,cursor,Capture.run(~S,~C,~R,~E,~L,~(A & Maybe<&2,Tick.Tick>),~Q.Error<U>,~List<&2,Out>,~runner(~S,~C,~R,~E,~L,~Ops,~A,~U,~Out,~query,~body),instance,world,(args,cursor)))
72# No callback entry: preserve capture and the existing query reader cursor.
73# Return the same captured owner and World without invoking the body.
74# Both capture state and query cursor remain unchanged.
75def skip(~S:Data,~C:Type,~R:Type,~E:Data,~L:Type,~Ops:Type -> Type,~A:Data,~U:Data,~Out:Data,~query:Decl.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>)>,~body:@-H:Type -> @-caps:Ops(H) -> L -> A -> H -> H & (L & (T.Outcome<U> & Out)),owner:Owner<S,C,R,E,L,Ops,A,U,Out,query,body>,world:W.World<S,C,R,E>) -> Owner<S,C,R,E,L,Ops,A,U,Out,query,body> & W.World<S,C,R,E>:
76  (owner,world)
77def removed(~S:Data,~C:Type,~R:Type,~E:Data,~L:Type,~Ops:Type -> Type,~A:Data,~U:Data,~Out:Data,~query:Decl.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>)>,~body:@-H:Type -> @-caps:Ops(H) -> L -> A -> H -> H & (L & (T.Outcome<U> & Out)),cursor:Maybe<&2,Tick.Tick>,result:Local.Disposal<S,C,R,E,L,A & Maybe<&2,Tick.Tick>,Q.Error<U>,List<&2,Out>,runner(~S,~C,~R,~E,~L,~Ops,~A,~U,~Out,~query,~body),L>) -> Removal<W.World<S,C,R,E>,Owner<S,C,R,E,L,Ops,A,U,Out,query,body>,L>:
78  match result:
79    case Local.Disposed{world,capture}:Removed{world,capture}
80    case Local.DisposalRejected{world,instance}:RemovalRejected{world,Owner{instance,cursor}}
81# Remove the matching registration and return its actual affine capture.
82# Refusal returns the original owner for retry; success returns Removed with
83# World/capture. Does not invoke a user finalizer or reset unrelated systems.
84def unregister(~S:Data,~C:Type,~R:Type,~E:Data,~L:Type,~Ops:Type -> Type,~A:Data,~U:Data,~Out:Data,~query:Decl.Declaration<S,Q.Frame<S,C,R,E>,Ops(Q.Frame<S,C,R,E>)>,~body:@-H:Type -> @-caps:Ops(H) -> L -> A -> H -> H & (L & (T.Outcome<U> & Out)),owner:Owner<S,C,R,E,L,Ops,A,U,Out,query,body>,world:W.World<S,C,R,E>) -> Removal<W.World<S,C,R,E>,Owner<S,C,R,E,L,Ops,A,U,Out,query,body>,L>:
85  match owner:
86    case Owner{instance,cursor}:removed(~S,~C,~R,~E,~L,~Ops,~A,~U,~Out,~query,~body,cursor,Capture.unregister(~S,~C,~R,~E,~L,~(A & Maybe<&2,Tick.Tick>),~Q.Error<U>,~List<&2,Out>,~runner(~S,~C,~R,~E,~L,~Ops,~A,~U,~Out,~query,~body),instance,world))