1 import Base 2 import ./execution_deferred_settings.bend as Settings 3 import ./dependency_plan.bend as Plan 4 import ./dependency_executor.bend as Exec 5 import ./execution_publication_order.bend as Order 6 7 type BoundaryKind is Data: 8 Sync{ids:List<&2,U32>} 9 Final{} 10 type Boundary is Data: 11 ApplyEntered{kind:BoundaryKind,requested:List<&2,U32>} 12 ApplyReturned{kind:BoundaryKind,remaining:List<&2,U32>} 13 type TraceState is Data: 14 Off{} 15 On{reverse:List<&2,Boundary>} 16 type Metadata is Data: 17 Metadata{syncs:List<&2,U32>,publication:List<&2,U32>} 18 type Context<-Actual:Type> is Type: 19 Context{state:Actual,unapplied:List<&2,U32>,metadata:Metadata,trace:TraceState} 20 type Outcome<-Actual:Type,Error:Data,Out:Data> is Type: 21 Outcome{result:Exec.ExecutionResult,unapplied:List<&2,U32>} 22 type Observed<-Actual:Type,-Error:Data,-Out:Data> is Type: 23 Observed{outcome:Outcome,boundaries:List<&2,Boundary>} 24 def is_sync(metadata:Metadata,id:U32) -> Bool: 25 match metadata: 26 case Metadata{syncs,_}:Settings.member(id,syncs) 27 def publication(metadata:Metadata) -> List<&2,U32>: 28 match metadata: 29 case Metadata{_,order}:order 30 def sync_entered(state:TraceState,id:U32,unapplied:List<&2,U32>) -> TraceState: 31 match state: 32 case Off{}:Off{} 33 case On{reverse}:On{ApplyEntered{Sync{[id]},unapplied} <> reverse} 34 def sync_returned(state:TraceState,id:U32,unapplied:List<&2,U32>) -> TraceState: 35 match state: 36 case Off{}:Off{} 37 case On{reverse}:On{ApplyReturned{Sync{[id]},unapplied} <> reverse} 38 def final_entered(state:TraceState,unapplied:List<&2,U32>) -> TraceState: 39 match state: 40 case Off{}:Off{} 41 case On{reverse}:On{ApplyEntered{Final{},unapplied} <> reverse} 42 def final_returned(state:TraceState,unapplied:List<&2,U32>) -> TraceState: 43 match state: 44 case Off{}:Off{} 45 case On{reverse}:On{ApplyReturned{Final{},unapplied} <> reverse} 46 def boundaries(state:TraceState) -> List<&2,Boundary>: 47 match state: 48 case Off{}:[] 49 case On{reverse}:List.reverse(&2,Boundary,reverse) 50 def include(+id:U32,+ids:List<&2,U32>) -> List<&2,U32>: 51 Bool.pick(List<&2,U32>,Settings.member(id,ids),ids,id <> ids) 52 def admitted(~Error:Data,~Out:Data,+status:Exec.Invocation,id:U32,ids:List<&2,U32>) -> List<&2,U32>: 53 match status: 54 case Exec.Completed{_}:include(id,ids) 55 case Exec.BodyError{_,_}:include(id,ids) 56 case Exec.AdmissionRefused{}:ids 57 def condition_returned(~Actual:Type,~Error:Data,syncs:Metadata,unapplied:List<&2,U32>,trace:TraceState,result:Actual & Exec.Condition) -> Context & Exec.Condition: 58 match result: 59 case (state,value):(Context{state,unapplied,syncs,trace},value) 60 def condition_adapter(~Actual:Type,~Error:Data,~condition:Actual -> U32 -> Actual & Exec.Condition,context:Context,id:U32) -> Context & Exec.Condition: 61 match context: 62 case Context{state,unapplied,syncs,trace}:condition_returned(~Actual,~Error,syncs,unapplied,trace,condition(state,id)) 63 def dispatch_returned(~Actual:Type,~Error:Data,~Out:Data,syncs:Metadata,unapplied:List<&2,U32>,trace:TraceState,id:U32,result:Actual & Exec.Invocation) -> Context & Exec.Invocation: 64 match result: 65 case (state,+status):(Context{state,admitted(~Error,~Out,status,id,unapplied),syncs,trace},status) 66 def dispatch_id(~Actual:Type,~Error:Data,~Out:Data,~dispatch:Actual -> U32 -> Actual & Exec.Invocation,context:Context,+id:U32) -> Context & Exec.Invocation: 67 match context: 68 case Context{state,unapplied,syncs,trace}:dispatch_returned(~Actual,~Error,~Out,syncs,unapplied,trace,id,dispatch(state,id)) 69 def dispatch_adapter(~Actual:Type,~Error:Data,~Out:Data,~dispatch:Actual -> U32 -> Actual & Exec.Invocation,context:Context,id:U32) -> Context & Exec.Invocation: 70 dispatch_id(~Actual,~Error,~Out,~dispatch,context,id) 71 def handled(~Actual:Type,syncs:Metadata,unapplied:List<&2,U32>,trace:TraceState,result:Actual & Exec.Handling) -> Context & Exec.Handling: 72 match result: 73 case (state,handling):(Context{state,unapplied,syncs,trace},handling) 74 def handler_adapter(~Actual:Type,~Error:Data,~handler:Actual -> Error -> Actual & Exec.Handling,context:Context,error:Error) -> Context & Exec.Handling: 75 match context: 76 case Context{state,unapplied,syncs,trace}:handled(~Actual,syncs,unapplied,trace,handler(state,error)) 77 def applied(~Actual:Type,syncs:Metadata,id:U32,trace:TraceState,result:Actual & List<&2,U32>) -> Context: 78 match result: 79 case (state,+unapplied):Context{state,unapplied,syncs,sync_returned(trace,id,unapplied)} 80 def synchronize(~Actual:Type,~apply:List<&2,U32> -> Actual -> Actual & List<&2,U32>,context:Context,+id:U32) -> Context: 81 match context: 82 case Context{state,+unapplied,+syncs,trace}:applied(~Actual,syncs,id,sync_entered(trace,id,unapplied),Order.apply(~Actual,~apply,publication(syncs),unapplied,state)) 83 84 def selected(~Actual:Type,~Error:Data,~Out:Data,~condition:Actual -> U32 -> Actual & Exec.Condition,~dispatch:Actual -> U32 -> Actual & Exec.Invocation,~handler:Actual -> Error -> Actual & Exec.Handling,~apply:List<&2,U32> -> Actual -> Actual & List<&2,U32>,next:Context -> List<&2,Exec.Observation> -> Exec.ExecutionResult,String,Error,Out>,context:Context,+id:U32,events:List<&2,Exec.Observation>,isSync:Bool) -> Exec.ExecutionResult,String,Error,Out>: 85 match isSync: 86 case True{}:next(synchronize(~Actual,~apply,context,id),events) 87 case False{}:Exec.conditioned(~Context,~String,~Error,~Out,~dispatch_adapter(~Actual,~Error,~Out,~dispatch),~handler_adapter(~Actual,~Error,~handler),next,condition_adapter(~Actual,~Error,~condition,context,id),id,events) 88 def step(~Actual:Type,~Error:Data,~Out:Data,~condition:Actual -> U32 -> Actual & Exec.Condition,~dispatch:Actual -> U32 -> Actual & Exec.Invocation,~handler:Actual -> Error -> Actual & Exec.Handling,~apply:List<&2,U32> -> Actual -> Actual & List<&2,U32>,next:Context -> List<&2,Exec.Observation> -> Exec.ExecutionResult,String,Error,Out>,context:Context,+id:U32,events:List<&2,Exec.Observation>) -> Exec.ExecutionResult,String,Error,Out>: 89 match context: 90 case Context{state,unapplied,+syncs,trace}:selected(~Actual,~Error,~Out,~condition,~dispatch,~handler,~apply,next,Context{state,unapplied,syncs,trace},id,events,is_sync(syncs,id)) 91 # Synthetic sync IDs apply buffers before the next condition and produce no body event. 92 def execute(~Actual:Type,~Error:Data,~Out:Data,~condition:Actual -> U32 -> Actual & Exec.Condition,~dispatch:Actual -> U32 -> Actual & Exec.Invocation,~handler:Actual -> Error -> Actual & Exec.Handling,~apply:List<&2,U32> -> Actual -> Actual & List<&2,U32>,order:List<&2,Plan.Node>,context:Context,events:List<&2,Exec.Observation>) -> Exec.ExecutionResult,String,Error,Out>: 93 match order: 94 case []:Exec.Finished{context,events} 95 case Plan.Node{id,_} <> rest:step(~Actual,~Error,~Out,~condition,~dispatch,~handler,~apply,context => events => execute(~Actual,~Error,~Out,~condition,~dispatch,~handler,~apply,rest,context,events),context,id,events) 96 def planned(~Actual:Type,~Error:Data,~Out:Data,~condition:Actual -> U32 -> Actual & Exec.Condition,~dispatch:Actual -> U32 -> Actual & Exec.Invocation,~handler:Actual -> Error -> Actual & Exec.Handling,~apply:List<&2,U32> -> Actual -> Actual & List<&2,U32>,plan:Plan.Build,context:Context) -> Exec.ExecutionResult,String,Error,Out>: 97 match plan: 98 case Plan.Rejected{reason}:Exec.Invalid{context,reason} 99 case Plan.Planned{order,_}:execute(~Actual,~Error,~Out,~condition,~dispatch,~handler,~apply,order,context,[]) 100 def final_applied(~Actual:Type,~Error:Data,~Out:Data,trace:TraceState,events:List<&2,Exec.Observation>,result:Actual & List<&2,U32>) -> Observed: 101 match result: 102 case (state,+unapplied):Observed{Outcome{Exec.Finished{state,events},unapplied},boundaries(final_returned(trace,unapplied))} 103 def finish(~Actual:Type,~Error:Data,~Out:Data,~apply:List<&2,U32> -> Actual -> Actual & List<&2,U32>,order:List<&2,U32>,finalApply:Bool,state:Actual,+unapplied:List<&2,U32>,trace:TraceState,events:List<&2,Exec.Observation>) -> Observed: 104 match finalApply: 105 case False{}:Observed{Outcome{Exec.Finished{state,events},unapplied},boundaries(trace)} 106 case True{}:final_applied(~Actual,~Error,~Out,final_entered(trace,unapplied),events,Order.apply(~Actual,~apply,order,unapplied,state)) 107 def finished(~Actual:Type,~Error:Data,~Out:Data,~apply:List<&2,U32> -> Actual -> Actual & List<&2,U32>,finalApply:Bool,result:Exec.ExecutionResult,String,Error,Out>) -> Observed: 108 match result: 109 case Exec.Finished{Context{state,unapplied,syncs,trace},events}:finish(~Actual,~Error,~Out,~apply,publication(syncs),finalApply,state,unapplied,trace,events) 110 case Exec.Stopped{Context{state,unapplied,_,trace},error,events}:Observed{Outcome{Exec.Stopped{state,error,events},unapplied},boundaries(trace)} 111 case Exec.Invalid{Context{state,unapplied,_,trace},reason}:Observed{Outcome{Exec.Invalid{state,reason},unapplied},boundaries(trace)} 112 def run_ordered(~Actual:Type,~Error:Data,~Out:Data,~condition:Actual -> U32 -> Actual & Exec.Condition,~dispatch:Actual -> U32 -> Actual & Exec.Invocation,~handler:Actual -> Error -> Actual & Exec.Handling,~apply:List<&2,U32> -> Actual -> Actual & List<&2,U32>,trace:TraceState,settings:Settings.Settings,syncs:List<&2,U32>,order:List<&2,U32>,plan:Plan.Build,state:Actual,unapplied:List<&2,U32>) -> Observed: 113 match settings: 114 case Settings.Settings{_,finalApply,_,_}:finished(~Actual,~Error,~Out,~apply,finalApply,planned(~Actual,~Error,~Out,~condition,~dispatch,~handler,~apply,plan,Context{state,unapplied,Metadata{syncs,order},trace})) 115 def run_mode(~Actual:Type,~Error:Data,~Out:Data,~condition:Actual -> U32 -> Actual & Exec.Condition,~dispatch:Actual -> U32 -> Actual & Exec.Invocation,~handler:Actual -> Error -> Actual & Exec.Handling,~apply:List<&2,U32> -> Actual -> Actual & List<&2,U32>,trace:TraceState,settings:Settings.Settings,+syncs:List<&2,U32>,+plan:Plan.Build,state:Actual,unapplied:List<&2,U32>) -> Observed: 116 run_ordered(~Actual,~Error,~Out,~condition,~dispatch,~handler,~apply,trace,settings,syncs,Order.from_plan(plan,syncs),plan,state,unapplied) 117 def run_observed(~Actual:Type,~Error:Data,~Out:Data,~condition:Actual -> U32 -> Actual & Exec.Condition,~dispatch:Actual -> U32 -> Actual & Exec.Invocation,~handler:Actual -> Error -> Actual & Exec.Handling,~apply:List<&2,U32> -> Actual -> Actual & List<&2,U32>,settings:Settings.Settings,syncs:List<&2,U32>,plan:Plan.Build,state:Actual,unapplied:List<&2,U32>) -> Observed: 118 run_mode(~Actual,~Error,~Out,~condition,~dispatch,~handler,~apply,On{[]},settings,syncs,plan,state,unapplied) 119 def unobserved(~Actual:Type,~Error:Data,~Out:Data,value:Observed) -> Outcome: 120 match value: 121 case Observed{outcome,_}:outcome 122 def run(~Actual:Type,~Error:Data,~Out:Data,~condition:Actual -> U32 -> Actual & Exec.Condition,~dispatch:Actual -> U32 -> Actual & Exec.Invocation,~handler:Actual -> Error -> Actual & Exec.Handling,~apply:List<&2,U32> -> Actual -> Actual & List<&2,U32>,settings:Settings.Settings,syncs:List<&2,U32>,plan:Plan.Build,state:Actual,unapplied:List<&2,U32>) -> Outcome: 123 unobserved(~Actual,~Error,~Out,run_mode(~Actual,~Error,~Out,~condition,~dispatch,~handler,~apply,Off{},settings,syncs,plan,state,unapplied))