execution_event_family.bend

bendvy-ecs-core@0.1.0.3 · 114 lines · 30 definitions

1import Base
2import bendvy-ecs-core@0.1.0.3/owned_event_log.bend as Log
3
4type Family<-S:Data,-P:Type,-key:String> is Type:
5  Family{identity:U32,open:Bool,log:Log.Log<P>,previous:List<&2,Nat>,current:List<&2,Nat>,nextReader:U32,active:List<&2,U32>,droppedThrough:Nat}
6type Reader<-S:Data,-P:Type,-key:String> is Type:
7  Reader{identity:U32,id:U32,cursor:Nat}
8type Creation<-S:Data,-P:Type,-key:String> is Type:
9  Created{family:Family<S,P,key>}
10  CreationRefused{}
11type Start is Data:
12  Retained{}
13  Future{}
14type Refusal is Data:
15  Closed{}
16  ForeignLog{}
17  Inactive{}
18  ReaderLimit{}
19  MissingPayload{}
20type Publication<-P:Type> is Type:
21  Published{id:Nat}
22  PublicationRefused{payload:P}
23type Registration<-S:Data,-P:Type,-key:String> is Type:
24  Registered{reader:Reader<S,P,key>}
25  RegistrationRefused{reason:Refusal}
26type Reading<-S:Data,-P:Type,-key:String,V:Data> is Type:
27  Item{reader:Reader<S,P,key>,id:Nat,value:V,missed:Nat}
28  Empty{reader:Reader<S,P,key>,missed:Nat}
29  ReadRefused{reader:Reader<S,P,key>,reason:Refusal}
30type Removal<-S:Data,-P:Type,-key:String> is Type:
31  Removed{reader:Reader<S,P,key>}
32  RemovalRefused{reader:Reader<S,P,key>,reason:Refusal}
33type Snapshot is Data:
34  Snapshot{identity:U32,open:Bool,next:Nat,previous:List<&2,Nat>,current:List<&2,Nat>,nextReader:U32,active:List<&2,U32>,droppedThrough:Nat}
35
36def created(~S:Data,~P:Type,~key:String,+identity:U32,valid:Bool) -> Creation<S,P,key>:
37  match valid:
38    case False{}:CreationRefused{}
39    case True{}:Created{Family{identity,True{},Log.empty(~P),[],[],1,[],0n}}
40def allocated(~S:Data,~P:Type,~key:String,+identity:U32) -> Creation<S,P,key>:
41  created(~S,~P,~key,identity,Bool.and(U32.is_lt(0,identity),U32.is_lt(identity,4294967295)))
42def has(+ids:List<&2,U32>,+wanted:U32) -> Bool:
43  match ids:
44    case []:False{}
45    case id <> rest:Bool.or(U32.is_eq(id,wanted),has(rest,wanted))
46def without_selected(equal:Bool,id:U32,rest:List<&2,U32>) -> List<&2,U32>:
47  match equal:
48    case True{}:rest
49    case False{}:id <> rest
50def without(ids:List<&2,U32>,+wanted:U32) -> List<&2,U32>:
51  match ids:
52    case []:[]
53    case +id <> rest:without_selected(U32.is_eq(id,wanted),id,without(rest,wanted))
54def published(~S:Data,~P:Type,~key:String,identity:U32,previous:List<&2,Nat>,current:List<&2,Nat>,nextReader:U32,active:List<&2,U32>,dropped:Nat,result:Log.Log<P> & Nat) -> Family<S,P,key> & Publication<P>:
55  match result:
56    case (log,+id):(Family{identity,True{},log,previous,List.append(&2,Nat,current,[id]),nextReader,active,dropped},Published{id})
57# Publication updates the owned log immediately, as Bevy Messages.write does.
58# https://github.com/bevyengine/bevy/blob/ad678262ce53b5d142fe49ee5e08caff6f00ab60/crates/bevy_ecs/src/message/messages.rs#L120-L143
59# A later handled body error does not stage or undo this already-authored send.
60def publish(~S:Data,~P:Type,~key:String,family:Family<S,P,key>,payload:P) -> Family<S,P,key> & Publication<P>:
61  match family:
62    case Family{identity,False{},log,previous,current,nextReader,active,dropped}:(Family{identity,False{},log,previous,current,nextReader,active,dropped},PublicationRefused{payload})
63    case Family{identity,True{},log,previous,current,nextReader,active,dropped}:published(~S,~P,~key,identity,previous,current,nextReader,active,dropped,Log.append(~P,log,payload))
64def starting(start:Start,next:Nat) -> Nat:
65  match start:
66    case Retained{}:0n
67    case Future{}:Nat.sub(next,1n)
68def register_checked(~S:Data,~P:Type,~key:String,start:Start,available:Bool,family:Family<S,P,key>) -> Family<S,P,key> & Registration<S,P,key>:
69  match available family:
70    case False{} family:(family,RegistrationRefused{ReaderLimit{}})
71    case True{} Family{+identity,open,Log.Log{+next,rows},previous,current,+nextReader,active,dropped}:(Family{identity,open,Log.Log{next,rows},previous,current,U32.add(nextReader,1),List.append(&2,U32,active,[nextReader]),dropped},Registered{Reader{identity,nextReader,starting(start,next)}})
72def register(~S:Data,~P:Type,~key:String,start:Start,family:Family<S,P,key>) -> Family<S,P,key> & Registration<S,P,key>:
73  match family:
74    case Family{identity,False{},log,previous,current,nextReader,active,dropped}:(Family{identity,False{},log,previous,current,nextReader,active,dropped},RegistrationRefused{Closed{}})
75    case Family{identity,True{},log,previous,current,+nextReader,active,dropped}:register_checked(~S,~P,~key,start,U32.is_lt(nextReader,4294967295),Family{identity,True{},log,previous,current,nextReader,active,dropped})
76def admission_identity(same:Bool,active:Bool) -> Maybe<&2,Refusal>:
77  match same active:
78    case False{} _:Some{ForeignLog{}}
79    case True{} False{}:Some{Inactive{}}
80    case True{} True{}:None{}
81def admission(open:Bool,identity:U32,actual:U32,id:U32,active:List<&2,U32>) -> Maybe<&2,Refusal>:
82  match open:
83    case False{}:Some{Closed{}}
84    case True{}:admission_identity(U32.is_eq(identity,actual),has(active,id))
85def remove_admitted(~S:Data,~P:Type,~key:String,refusal:Maybe<&2,Refusal>,family:Family<S,P,key>,reader:Reader<S,P,key>) -> Family<S,P,key> & Removal<S,P,key>:
86  match refusal family reader:
87    case Some{reason} family reader:(family,RemovalRefused{reader,reason})
88    case None{} Family{identity,open,log,previous,current,nextReader,active,dropped} Reader{actual,+id,cursor}:(Family{identity,open,log,previous,current,nextReader,without(active,id),dropped},Removed{Reader{actual,id,cursor}})
89def remove(~S:Data,~P:Type,~key:String,family:Family<S,P,key>,reader:Reader<S,P,key>) -> Family<S,P,key> & Removal<S,P,key>:
90  match family reader:
91    case Family{+identity,+open,log,previous,current,nextReader,+active,dropped} Reader{+actual,+id,cursor}:remove_admitted(~S,~P,~key,admission(open,identity,actual,id,active),Family{identity,open,log,previous,current,nextReader,active,dropped},Reader{actual,id,cursor})
92def highest(ids:List<&2,Nat>,+initial:Nat) -> Nat:
93  match ids:
94    case []:initial
95    case id <> rest:highest(rest,Nat.max(initial,id))
96def updated(~S:Data,~P:Type,~key:String,identity:U32,current:List<&2,Nat>,nextReader:U32,active:List<&2,U32>,dropped:Nat,result:Log.Log<P> & List<Log.Row<P>>) -> Family<S,P,key> & List<Log.Row<P>>:
97  match result:
98    case (log,retired):(Family{identity,True{},log,current,[],nextReader,active,dropped},retired)
99# Messages.update_drain returns the previous generation's actual payload owners.
100# https://github.com/bevyengine/bevy/blob/ad678262ce53b5d142fe49ee5e08caff6f00ab60/crates/bevy_ecs/src/message/messages.rs#L187-L218
101# Bend returns retained rows explicitly instead of claiming an automatic IO finalizer.
102def update(~S:Data,~P:Type,~key:String,family:Family<S,P,key>) -> Family<S,P,key> & List<Log.Row<P>>:
103  match family:
104    case Family{identity,False{},log,previous,current,nextReader,active,dropped}:(Family{identity,False{},log,previous,current,nextReader,active,dropped},[])
105    case Family{identity,True{},log,previous,+current,nextReader,active,dropped}:updated(~S,~P,~key,identity,current,nextReader,active,highest(previous,dropped),Log.retain(~P,log,current))
106def shutdown_returned(~S:Data,~P:Type,~key:String,identity:U32,nextReader:U32,dropped:Nat,result:Log.Log<P> & List<Log.Row<P>>) -> Family<S,P,key> & List<Log.Row<P>>:
107  match result:
108    case (log,rows):(Family{identity,False{},log,[],[],nextReader,[],dropped},rows)
109def shutdown(~S:Data,~P:Type,~key:String,family:Family<S,P,key>) -> Family<S,P,key> & List<Log.Row<P>>:
110  match family:
111    case Family{identity,_,log,previous,current,nextReader,_,dropped}:shutdown_returned(~S,~P,~key,identity,nextReader,highest(List.append(&2,Nat,previous,current),dropped),Log.drain(~P,log))
112def snapshot(~S:Data,~P:Type,~key:String,family:Family<S,P,key>) -> Family<S,P,key> & Snapshot:
113  match family:
114    case Family{+identity,+open,Log.Log{+next,rows},+previous,+current,+nextReader,+active,+dropped}:(Family{identity,open,Log.Log{next,rows},previous,current,nextReader,active,dropped},Snapshot{identity,open,next,previous,current,nextReader,active,dropped})