captured_schedule_composition.bend
bendvy-ecs-core@0.1.0.0 · 75 lines · 0 definitions
1import Base
2import bendvy-ecs-core@0.1.0.0/world.bend as W
3import bendvy-ecs-core@0.1.0.0/schedule.bend as Sch
4import bendvy-ecs-core@0.1.0.0/schedule_provision.bend as SP
5# Closed typed composition carries independently authored owners, never a copied
6# closure or a caller-maintained dispatcher enumeration.
7# Detached actual registration identity used by heterogeneous composition.
8# Includes namespace/ID/name/access for validation; not a substitute for the
9# affine owner or an authorization token on its own.
10type Identity is Data:
11 Identity{namespace:U32,id:U32,name:String,access:List<&2,String>}
12# Dispatch result retaining World and heterogeneous owner on completion,
13# skip, failure or refusal. Error values are detached; owner restoration and
14# transaction behavior belong to the selected registered runner.
15type Outcome<World:Type,Owner:Type,Error:Data> is Type:
16 Completed{world:World,owner:Owner}
17 Skipped{world:World,owner:Owner}
18 Failed{world:World,owner:Owner,error:Error}
19 Refused{world:World,owner:Owner}
20# Detached heterogeneous error sum used when composing registered systems.
21# LeftError and RightError identify the originating error branch; it carries
22# neither the World nor affine system owners, which return separately.
23type Choice<L:Data,R:Data> is Data:
24 LeftError{error:L}
25 RightError{error:R}
26def ids(items:List<&2,Identity>) -> List<&2,U32>:
27 match items:
28 case []:[]
29 case Identity{_,id,_,_} <> rest:id <> ids(rest)
30def member(items:List<&2,Identity>,+wanted:U32) -> Bool:
31 match items:
32 case []:False{}
33 case Identity{_,id,_,_} <> rest:Bool.or(U32.is_eq(id,wanted),member(rest,wanted))
34def identities_valid(+namespace:U32,+registered:List<&2,W.RegistrationMeta>,items:List<&2,Identity>,+seen:List<&2,U32>) -> Bool:
35 match items:
36 case []:True{}
37 case Identity{ns,+id,name,access} <> rest:Bool.and(U32.is_eq(namespace,ns),Bool.and(W.registration_list_matches(registered,id,name,access),Bool.and(Bool.not(Sch.contains(seen,id)),identities_valid(namespace,registered,rest,id <> seen))))
38def pair_catalog_done(~L:Type,~R:Type,left:L,entries:List<&2,Identity>,result:R & List<&2,Identity>) -> (L & R) & List<&2,Identity>:
39 match result:
40 case (right,more):((left,right),List.append(&2,Identity,entries,more))
41def pair_catalog_left(~L:Type,~R:Type,~right:R -> R & List<&2,Identity>,other:R,result:L & List<&2,Identity>) -> (L & R) & List<&2,Identity>:
42 match result:
43 case (owner,entries):pair_catalog_done(~L,~R,owner,entries,right(other))
44# Advanced owner-threading catalog composition in left/right order.
45# Returns both affine owners and appended identities without executing bodies.
46# Supplied catalog callbacks must preserve actual registration correspondence.
47def pair_catalog(~L:Type,~R:Type,~left:L -> L & List<&2,Identity>,~right:R -> R & List<&2,Identity>,owners:L & R) -> (L & R) & List<&2,Identity>:
48 match owners:
49 case (a,b):pair_catalog_left(~L,~R,~right,b,left(a))
50def left_returned(~World:Type,~L:Type,~R:Type,~LE:Data,~RE:Data,right:R,result:Outcome<World,L,LE>) -> Outcome<World,L & R,Choice<LE,RE>>:
51 match result:
52 case Completed{world,left}:Completed{world,(left,right)}
53 case Skipped{world,left}:Skipped{world,(left,right)}
54 case Failed{world,left,error}:Failed{world,(left,right),LeftError{error}}
55 case Refused{world,left}:Refused{world,(left,right)}
56def right_returned(~World:Type,~L:Type,~R:Type,~LE:Data,~RE:Data,left:L,result:Outcome<World,R,RE>) -> Outcome<World,L & R,Choice<LE,RE>>:
57 match result:
58 case Completed{world,right}:Completed{world,(left,right)}
59 case Skipped{world,right}:Skipped{world,(left,right)}
60 case Failed{world,right,error}:Failed{world,(left,right),RightError{error}}
61 case Refused{world,right}:Refused{world,(left,right)}
62def pair_selected(~World:Type,~L:Type,~R:Type,~LE:Data,~RE:Data,~left:L -> World -> U32 -> Outcome<World,L,LE>,~right:R -> World -> U32 -> Outcome<World,R,RE>,found:Bool,a:L,b:R,world:World,id:U32) -> Outcome<World,L & R,Choice<LE,RE>>:
63 match found:
64 case True{}:left_returned(~World,~L,~R,~LE,~RE,b,left(a,world,id))
65 case False{}:right_returned(~World,~L,~R,~LE,~RE,a,right(b,world,id))
66def pair_cataloged(~World:Type,~L:Type,~R:Type,~LE:Data,~RE:Data,~left:L -> World -> U32 -> Outcome<World,L,LE>,~right:R -> World -> U32 -> Outcome<World,R,RE>,b:R,world:World,+id:U32,result:L & List<&2,Identity>) -> Outcome<World,L & R,Choice<LE,RE>>:
67 match result:
68 case (a,entries):pair_selected(~World,~L,~R,~LE,~RE,~left,~right,member(entries,id),a,b,world,id)
69# Advanced heterogeneous dispatch using the left catalog to choose a branch.
70# Retains both owners, wraps errors as LeftError/RightError and preserves skip/
71# refusal outcomes. The selected dispatcher performs registration validation;
72# metadata membership alone confers no authority and adds no rollback.
73def pair_dispatch(~World:Type,~L:Type,~R:Type,~LE:Data,~RE:Data,~catalog:L -> L & List<&2,Identity>,~left:L -> World -> U32 -> Outcome<World,L,LE>,~right:R -> World -> U32 -> Outcome<World,R,RE>,owners:L & R,world:World,id:U32) -> Outcome<World,L & R,Choice<LE,RE>>:
74 match owners:
75 case (a,b):pair_cataloged(~World,~L,~R,~LE,~RE,~left,~right,b,world,id,catalog(a))