check.bend

bendvy-ecs-core@0.1.0.3 · 96 lines · 20 definitions

1import Base
2import inspector.bend as I
3import inspector_query_projection.bend as Q
4import world.bend as W
5import component.bend as C
6import column.bend as Col
7import capabilities.bend as Cap
8
9# Trusted declaration setup receives a nominal cursor-free frame. The public
10# query grant exposes neither lifecycle filters nor added/changed observations.
11# Machine conditions belong to #55; services/streams have no grant here.
12# Trusted cursor-free Check frame owning World. Ordinary condition bodies
13# receive opaque H with read capabilities, not raw world constructors.
14# No lifecycle cursor or event reader is allocated by this frame.
15type Frame<-S:Data,-Store:Type,-R:Type,-E:Data> is Type:
16  Frame{world:W.World<S,Store,R,E>}
17# Condition query membership: Required excludes absent components; Optional
18# retains live rows with explicit absence. No Added/Changed mode is offered.
19type PlainSelection is Data:
20  Required{}
21  Optional{}
22# Detached condition-query row: entity handle plus component Access<V>.
23# Does not expose added/changed flags or an affine component payload.
24type Row<S:Data,V:Data> is Data:
25  Row{entity:W.Handle<S>,value:C.Access<V>}
26# Preflight failure listing required runtime resources absent from the plan.
27# Check body is not invoked when this error is returned.
28type Error is Data:
29  MissingRuntimeRequirements{resources:List<&2,String>}
30# Trusted setup pairing runtime-requirement observation with read grants.
31# required must return World; arbitrary callback mutations are not isolated
32# by the Check abstraction. Bodies receive only the declared Ops(H).
33type Plan<-S:Data,-Store:Type,-R:Type,-E:Data,-Ops:Type -> Type> is Type:
34  Plan{required:W.World<S,Store,R,E> -> W.World<S,Store,R,E> & List<&2,String>,caps:Ops(Frame<S,Store,R,E>)}
35# Check outcome retaining World with either a preflight Error or Bool.
36# False is a successful condition result, distinct from missing requirements.
37type Checked<S:Data,Store:Type,R:Type,E:Data> is Type:
38  Checked{world:W.World<S,Store,R,E>,result:Result<&2,&2,Error,Bool>}
39
40def selection(value:PlainSelection) -> Q.Selection:
41  match value:
42    case Required{}:Q.Required{}
43    case Optional{}:Q.Optional{}
44def plain_row(~S:Data,~V:Data,value:Q.Row<S,V>) -> Row<S,V>:
45  match value:
46    case Q.Row{entity,I.Value{access,_,_}}:Row{entity,access}
47def plain_rows(~S:Data,~V:Data,values:List<&2,Q.Row<S,V>>) -> List<&2,Row<S,V>>:
48  match values:
49    case []:[]
50    case value <> rest:plain_row(~S,~V,value) <> plain_rows(~S,~V,rest)
51def query_done(~S:Data,~Store:Type,~R:Type,~E:Data,~V:Data,result:I.Frame<S,Store,R,E> & List<&2,Q.Row<S,V>>) -> Frame<S,Store,R,E> & List<&2,Row<S,V>>:
52  match result:
53    case (I.Frame{world,_},rows):(Frame{world},plain_rows(~S,~V,rows))
54def query_read(~S:Data,~Store:Type,~R:Type,~E:Data,~Rest:Type,~Payload:Type,~V:Data,~Token:Data,~take:Store -> Rest & Col.Column<S,Payload>,~put:Rest -> Col.Column<S,Payload> -> Store,~project:Payload -> Payload & V,~family:C.Family<S,Store,Rest,Payload,V,Token,take,put,project>,~mode:PlainSelection,frame:Frame<S,Store,R,E>) -> Frame<S,Store,R,E> & List<&2,Row<S,V>>:
55  match frame:
56    case Frame{world}:query_done(~S,~Store,~R,~E,~V,Q.scan(~S,~Store,~R,~E,~Rest,~Payload,~V,~Token,~take,~put,~project,~family,~selection(mode),I.Frame{world,None{}}))
57# Build a read-only component query for Required or Optional membership.
58# Canonical scan returns detached Access rows in its live-handle traversal order,
59# without lifecycle flags or consuming registered system cursors. project must
60# preserve payload owners; raw family lenses remain trusted schema setup.
61def query_grant(~S:Data,~Store:Type,~R:Type,~E:Data,~Rest:Type,~Payload:Type,~V:Data,~Token:Data,~take:Store -> Rest & Col.Column<S,Payload>,~put:Rest -> Col.Column<S,Payload> -> Store,~project:Payload -> Payload & V,~family:C.Family<S,Store,Rest,Payload,V,Token,take,put,project>,~mode:PlainSelection) -> Cap.ValueRead<Frame<S,Store,R,E>,List<&2,Row<S,V>>>:
62  Cap.ValueRead{frame => query_read(~S,~Store,~R,~E,~Rest,~Payload,~V,~Token,~take,~put,~project,~family,~mode,frame)}
63def resource_done(~S:Data,~Store:Type,~R:Type,~E:Data,~V:Data,result:W.World<S,Store,R,E> & V) -> Frame<S,Store,R,E> & V:
64  (world,value)=result
65  (Frame{world},value)
66def resource_read(~S:Data,~Store:Type,~R:Type,~E:Data,~V:Data,~project:R -> R & V,frame:Frame<S,Store,R,E>) -> Frame<S,Store,R,E> & V:
67  match frame:
68    case Frame{world}:resource_done(~S,~Store,~R,~E,~V,W.observe_resource(~S,~Store,~R,~E,~V,~project,world))
69# Build read-only access to a detached resource Data view. project threads
70# affine R back unchanged in ownership; no replacement or event-read grant
71# is provided and no resource projection runs during declaration construction.
72def resource_grant(~S:Data,~Store:Type,~R:Type,~E:Data,~V:Data,~project:R -> R & V) -> Cap.ValueRead<Frame<S,Store,R,E>,V>:
73  Cap.ValueRead{frame => resource_read(~S,~Store,~R,~E,~V,~project,frame)}
74
75def completed(~S:Data,~Store:Type,~R:Type,~E:Data,result:Frame<S,Store,R,E> & Bool) -> Checked<S,Store,R,E>:
76  match result:
77    case (Frame{world},value):Checked{world,Done{value}}
78def ready(~S:Data,~Store:Type,~R:Type,~E:Data,~Ops:Type -> Type,~A:Data,~body:@-H:Type -> @-caps:Ops(H) -> A -> H -> H & Bool,~caps:Ops(Frame<S,Store,R,E>),args:A,result:W.World<S,Store,R,E> & List<&2,String>) -> Checked<S,Store,R,E>:
79  match result:
80    case (world,[]):completed(~S,~Store,~R,~E,Cap.invoke(~Ops,~A,~Bool,~body,~Frame<S,Store,R,E>,~caps,args,Frame{world}))
81    case (world,name <> rest):Checked{world,Fail{MissingRuntimeRequirements{name <> rest}}}
82def required_field(~S:Data,~Store:Type,~R:Type,~E:Data,~Ops:Type -> Type,plan:Plan<S,Store,R,E,Ops>) -> W.World<S,Store,R,E> -> W.World<S,Store,R,E> & List<&2,String>:
83  match plan:
84    case Plan{required,_}:required
85def caps_field(~S:Data,~Store:Type,~R:Type,~E:Data,~Ops:Type -> Type,plan:Plan<S,Store,R,E,Ops>) -> Ops(Frame<S,Store,R,E>):
86  match plan:
87    case Plan{_,caps}:caps
88# Check runtime requirements, then evaluate a cursor-free Bool body through
89# its declared capabilities. Missing requirements return Checked with Fail
90# without invoking body; otherwise Done contains True or False. World is
91# returned on both paths, including any changes made by trusted requirement
92# callbacks. Check itself advances no system/lifecycle/event cursor or clock.
93# No automatic transaction rollback applies to arbitrary setup callbacks.
94# Condition contract and consumers: docs/parity/inspect.md.
95def run(~S:Data,~Store:Type,~R:Type,~E:Data,~Ops:Type -> Type,~A:Data,~body:@-H:Type -> @-caps:Ops(H) -> A -> H -> H & Bool,~plan:Plan<S,Store,R,E,Ops>,args:A,world:W.World<S,Store,R,E>) -> Checked<S,Store,R,E>:
96  ready(~S,~Store,~R,~E,~Ops,~A,~body,~caps_field(~S,~Store,~R,~E,~Ops,plan),args,required_field(~S,~Store,~R,~E,~Ops,plan)(world))