1 import Base 2 import ./execution_lifecycle_notices.bend as Notice 3 import ./world.bend as W 4 import ./entity_allocator.bend as A 5 import ./entity_key.bend as K 6 import ./clock_state.bend as Clock 7 import ./change_tick.bend as Tick 8 import ./deferred_command.bend as Deferred 9 import ./execution_reservation_authority.bend as Authority 10 11 type Invocation<-S:Data> is Type: 12 Invocation{namespace:U32,allocator:A.Allocator,admitted:Maybe<&2,U32>,permit:Authority.Permit} 13 type Scope<-S:Data,-C:Type,-R:Type> is Type: 14 Scope{store:C,resource:R,handles:List<&2,W.Handle>,tick:Tick.Tick,prior:Maybe<&2,Tick.Tick>,lifecycleView:Notice.View} 15 type Administration<-S:Data,-C:Type,-R:Type,-E:Data> is Type: 16 Administration{events:List<&2,E>,pending:List>>,registrations:List<&2,W.RegistrationMeta>,nextSystemId:U32,clock:Clock.State,lifecycle:Notice.Journal} 17 def separated_snapshot(~S:Data,~C:Type,~R:Type,~E:Data,namespace:U32,allocator:A.Allocator,store:C,resource:R,events:List<&2,E>,pending:List>>,registrations:List<&2,W.RegistrationMeta>,nextSystemId:U32,clock:Clock.State,handles:List<&2,W.Handle>,tick:Tick.Tick,snapshot:Notice.Journal & Notice.View) -> Administration & (Invocation & Scope): 18 match snapshot: 19 case (lifecycle,lifecycleView):(Administration{events,pending,registrations,nextSystemId,clock,lifecycle},(Invocation{namespace,allocator,None{},Authority.Unauthorized{}},Scope{store,resource,handles,tick,None{},lifecycleView})) 20 def separated(~S:Data,~C:Type,~R:Type,~E:Data,tick:Tick.Tick,observed:W.World & List<&2,W.Handle>) -> Administration & (Invocation & Scope): 21 match observed: 22 case (W.World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock,lifecycle},handles):separated_snapshot(~S,~C,~R,~E,namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock,handles,tick,Notice.snapshot(~S,lifecycle)) 23 def separate(~S:Data,~C:Type,~R:Type,~E:Data,world:W.World,tick:Tick.Tick) -> Administration & (Invocation & Scope): 24 separated(~S,~C,~R,~E,tick,W.handles(~S,~C,~R,~E,world)) 25 def reassemble(~S:Data,~C:Type,~R:Type,~E:Data,admin:Administration,invocation:Invocation,scope:Scope) -> W.World: 26 match admin invocation scope: 27 case Administration{events,pending,registrations,nextSystemId,clock,lifecycle} Invocation{namespace,allocator,_,_} Scope{store,resource,_,_,_,+lifecycleView}:W.World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock,lifecycle} 28 def same(~S:Data,left:W.Handle,right:W.Handle) -> Bool: 29 match left right: 30 case W.Handle{ln,lk} W.Handle{rn,rk}:Bool.and(U32.is_eq(ln,rn),K.equal(lk,rk)) 31 def member(~S:Data,+handle:W.Handle,handles:List<&2,W.Handle>) -> Bool: 32 match handles: 33 case []:False{} 34 case current <> rest:Bool.or(same(~S,handle,current),member(~S,handle,rest)) 35 36 # The cursor belongs to this admitted system, independently of the shared clock. 37 def window(~S:Data,~C:Type,~R:Type,scope:Scope,prior:Maybe<&2,Tick.Tick>) -> Scope: 38 match scope: 39 case Scope{store,resource,handles,tick,_,+lifecycleView}:Scope{store,resource,handles,tick,prior,lifecycleView} 40 41 def admit(~S:Data,+id:U32,grant:Authority.Grant,invocation:Invocation) -> Invocation: 42 match invocation: 43 case Invocation{+namespace,allocator,_,_}:Invocation{namespace,allocator,Some{id},Authority.qualified(Authority.Context{namespace,id,grant})} 44 def reserved_pending(-S:Data,+namespace:U32,authorized:Maybe<&2,U32>,permit:Authority.Permit,handle:W.Handle,result:A.Allocator & Bool) -> Invocation & W.Reservation: 45 match result: 46 case (allocator,True{}):(Invocation{namespace,allocator,authorized,permit},W.Reserved{handle}) 47 case (allocator,False{}):(Invocation{namespace,allocator,authorized,permit},W.ReservationRejected{W.MissingEntity{}}) 48 def reserved(-S:Data,+namespace:U32,authorized:Maybe<&2,U32>,permit:Authority.Permit,result:A.Allocator & A.Reservation) -> Invocation & W.Reservation: 49 match result: 50 case (allocator,A.Exhausted{}):(Invocation{namespace,allocator,authorized,permit},W.ReservationRejected{W.CapacityExceeded{}}) 51 case (allocator,A.Reserved{+key}):reserved_pending(S,namespace,authorized,permit,W.Handle{namespace,key},A.set(allocator,key,A.Pending{})) 52 def reserve_allowed(-S:Data,allowed:Bool,invocation:Invocation) -> Invocation & W.Reservation: 53 match allowed invocation: 54 case False{} invocation:(invocation,W.ReservationRejected{W.ReservationUnauthorized{}}) 55 case True{} Invocation{namespace,allocator,authorized,permit}:reserved(S,namespace,authorized,permit,A.reserve(allocator)) 56 def reserve_invocation(-S:Data,invocation:Invocation) -> Invocation & W.Reservation: 57 match invocation: 58 case Invocation{+namespace,allocator,+authorized,+permit}:reserve_allowed(S,Authority.admitted(permit,namespace,authorized),Invocation{namespace,allocator,authorized,permit}) 59 def request(~S:Data,token:Authority.Granted,invocation:Invocation) -> Invocation & W.Reservation: 60 match token: 61 case Authority.Granted{}:reserve_invocation(S,invocation)