execution_lifetime_scope_store.bend

bendvy-ecs-core@0.1.0.3 · 83 lines · 21 definitions

1import Base
2import bendvy-ecs-core@0.1.0.3/lifetime_scope.bend as Scope
3import bendvy-ecs-core@0.1.0.3/world.bend as W
4import bendvy-ecs-core@0.1.0.3/entity_allocator.bend as Allocator
5import bendvy-ecs-core@0.1.0.3/entity_key.bend as Key
6
7# Canonical resource ownership is separate from component owners and liveness.
8# Bevy ad678262ce53b5d142fe49ee5e08caff6f00ab60 state_scoped.rs queues
9# despawns on state exit. Named namespace-bound scopes are Bend metadata.
10type Store<-S:Data> is Type:
11  Store{namespace:U32,members:List<&2,Scope.Member>}
12type View<-S:Data> is Data:
13  View{namespace:U32,members:List<&2,Scope.Member>}
14type Refusal is Data:
15  NamespaceMismatch{}
16  MissingEntity{}
17type Assignment<-S:Data> is Data:
18  Assigned{scope:Scope.Scope<S>,handle:W.Handle<S>}
19  AssignmentRefused{scope:Scope.Scope<S>,handle:W.Handle<S>,reason:Refusal}
20def fresh(~S:Data,namespace:U32) -> Store<S>:
21  Store{namespace,[]}
22def project(~S:Data,store:Store<S>) -> Store<S> & View<S>:
23  match store:
24    case Store{+namespace,+members}:(Store{namespace,members},View{namespace,members})
25def assigned(~S:Data,scope:Scope.Scope<S>,handle:W.Handle<S>,namespace:U32,members:List<&2,Scope.Member>,result:Allocator.Allocator & Bool) -> Allocator.Allocator & (Store<S> & Assignment<S>):
26  match scope handle result:
27    case scope handle, (allocator,False{}):(allocator,(Store{namespace,members},AssignmentRefused{scope,handle,MissingEntity{}}))
28    case Scope.Scope{+scopeNamespace,+name} W.Handle{+handleNamespace,+key}, (allocator,True{}):(allocator,(Store{namespace,List.append(&2,Scope.Member,Scope.without(members,key),[Scope.Member{name,key}])},Assigned{Scope.Scope{scopeNamespace,name},W.Handle{handleNamespace,key}}))
29def assign_checked(~S:Data,allowed:Bool,allocator:Allocator.Allocator,store:Store<S>,scope:Scope.Scope<S>,handle:W.Handle<S>) -> Allocator.Allocator & (Store<S> & Assignment<S>):
30  match allowed store handle:
31    case False{} store handle:(allocator,(store,AssignmentRefused{scope,handle,NamespaceMismatch{}}))
32    case True{} Store{namespace,members} W.Handle{+handleNamespace,+key}:assigned(~S,scope,W.Handle{handleNamespace,key},namespace,members,Allocator.checked(allocator,key,1))
33def assign(~S:Data,+actual:U32,allocator:Allocator.Allocator,store:Store<S>,scope:Scope.Scope<S>,handle:W.Handle<S>) -> Allocator.Allocator & (Store<S> & Assignment<S>):
34  match store scope handle:
35    case Store{+namespace,members} Scope.Scope{+scopeNamespace,+name} W.Handle{+handleNamespace,+key}:assign_checked(~S,Bool.and(U32.is_eq(actual,namespace),Bool.and(U32.is_eq(actual,scopeNamespace),U32.is_eq(actual,handleNamespace))),allocator,Store{namespace,members},Scope.Scope{scopeNamespace,name},W.Handle{handleNamespace,key})
36type Snapshot<-S:Data> is Data:
37  Selected{scope:Scope.Scope<S>,members:List<&2,Key.Key>}
38  SnapshotRefused{scope:Scope.Scope<S>}
39def snapshot_checked(~S:Data,allowed:Bool,store:Store<S>,scope:Scope.Scope<S>) -> Store<S> & Snapshot<S>:
40  match allowed store scope:
41    case False{} store scope:(store,SnapshotRefused{scope})
42    case True{} Store{namespace,+members} Scope.Scope{+scopeNamespace,+name}:(Store{namespace,members},Selected{Scope.Scope{scopeNamespace,name},Scope.select(members,name)})
43def snapshot(~S:Data,+actual:U32,store:Store<S>,scope:Scope.Scope<S>) -> Store<S> & Snapshot<S>:
44  match store scope:
45    case Store{+namespace,members} Scope.Scope{+scopeNamespace,+name}:snapshot_checked(~S,Bool.and(U32.is_eq(actual,namespace),U32.is_eq(actual,scopeNamespace)),Store{namespace,members},Scope.Scope{scopeNamespace,name})
46# Called only after canonical despawn succeeds, using the complete generation key.
47def removed(~S:Data,store:Store<S>,key:Key.Key) -> Store<S>:
48  match store:
49    case Store{namespace,members}:Store{namespace,Scope.without(members,key)}
50
51type Request<-S:Data> is Data:
52  Assign{scope:Scope.Scope<S>,handle:W.Handle<S>}
53  Select{scope:Scope.Scope<S>}
54  Forget{handle:W.Handle<S>}
55  Inspect{}
56type Outcome<-S:Data> is Data:
57  Assignment{result:Assignment<S>}
58  Selection{result:Snapshot<S>}
59  Forgotten{handle:W.Handle<S>}
60  Inspected{namespace:U32}
61  Refused{request:Request<S>}
62def assignment_returned(~S:Data,result:Allocator.Allocator & (Store<S> & Assignment<S>)) -> Allocator.Allocator & (Store<S> & Outcome<S>):
63  match result:
64    case (allocator,(store,result)):(allocator,(store,Assignment{result}))
65def selection_returned(~S:Data,allocator:Allocator.Allocator,result:Store<S> & Snapshot<S>) -> Allocator.Allocator & (Store<S> & Outcome<S>):
66  match result:
67    case (store,result):(allocator,(store,Selection{result}))
68def forgotten(~S:Data,allowed:Bool,allocator:Allocator.Allocator,store:Store<S>,+handle:W.Handle<S>) -> Allocator.Allocator & (Store<S> & Outcome<S>):
69  match allowed:
70    case False{}:(allocator,(store,Refused{Forget{handle}}))
71    case True{}:(allocator,(removed(~S,store,W.handle_key(~S,handle)),Forgotten{handle}))
72def forget_namespace(~S:Data,+actual:U32,allocator:Allocator.Allocator,store:Store<S>,handle:W.Handle<S>,namespace:U32) -> Allocator.Allocator & (Store<S> & Outcome<S>):
73  match store:
74    case Store{+stored,members}:forgotten(~S,Bool.and(U32.is_eq(actual,stored),U32.is_eq(actual,namespace)),allocator,Store{stored,members},handle)
75def inspected(~S:Data,allocator:Allocator.Allocator,store:Store<S>) -> Allocator.Allocator & (Store<S> & Outcome<S>):
76  match store:
77    case Store{+namespace,members}:(allocator,(Store{namespace,members},Inspected{namespace}))
78def apply(~S:Data,+actual:U32,allocator:Allocator.Allocator,store:Store<S>,request:Request<S>) -> Allocator.Allocator & (Store<S> & Outcome<S>):
79  match request:
80    case Inspect{}:inspected(~S,allocator,store)
81    case Assign{scope,handle}:assignment_returned(~S,assign(~S,actual,allocator,store,scope,handle))
82    case Select{scope}:selection_returned(~S,allocator,snapshot(~S,actual,store,scope))
83    case Forget{W.Handle{+namespace,+key}}:forget_namespace(~S,actual,allocator,store,W.Handle{namespace,key},namespace)