1 import ./persistence_declaration.bend as Decl 2 import ./bundle_delivery.bend as Delivery 3 import Base 4 import entity_key.bend as Key 5 import ./decode_frame.bend as F 6 import ./decode_requests.bend as Request 7 import ./decode_owned_journal.bend as Journal 8 import ./ordinary_declaration.bend as Identity 9 import ./decode_data.bend as D 10 import ./world.bend as W 11 import ./local.bend as Local 12 import ./transaction.bend as T 13 import ./commands.bend as Commands 14 import ./bundle_batch.bend as Batch 15 16 # State/sink adapters are application-selected, closed typed functions. A failed 17 # run returns its Local owner and no output, exactly like existing Local.Outcome. 18 def registered(~S:Data,~C:Type,~R:Type,~E:Data,~L:Type,~A:Type,~Error:Data,~Out:Type,~runner:W.World -> L -> A -> Local.Outcome,L,Error,Out>,world:W.World,name:String,access:List<&2,String>,local:L) -> Local.Registered: 19 Local.register(~S,~C,~R,~E,~L,~A,~Error,~Out,~runner,world,name,access,local) 20 21 def succeeded(~World:Type,~L:Type,~Error:Data,~Out:Type,world:World,result:L & Out) -> Local.Outcome: 22 match result: 23 case (local,output):Local.Succeeded{world,local,output} 24 25 def committed(~World:Type,~L:Type,~A:Type,~Rows:Data,~Error:Data,~Out:Type,~success:L -> A -> Rows -> L & Out,~failure:L -> A -> L,local:L,args:A,rows:Rows,result:T.Returned) -> Local.Outcome: 26 match result: 27 case T.Returned{world,T.Success{}}:succeeded(~World,~L,~Error,~Out,world,success(local,args,rows)) 28 case T.Returned{world,T.Failure{error}}:Local.Failed{world,failure(local,args),error} 29 30 def recovered(~S:Data,~World:Type,~L:Type,~A:Type,~P:Type,~Q:Type,~Error:Data,~Out:Type,~recover:L -> A -> List> -> List> -> L,error:Error,local:L,args:A,prepared:List>>,pending:List>,result:Journal.Returned,Q>) -> Local.Outcome: 31 match result: 32 case Journal.Returned{world,owners,more}:Local.Failed{world,recover(local,args,List.append(&1,Request.Packet

,owners,Batch.originals(~S,~Request.Packet

,prepared)),List.append(&1,Journal.Pending,pending,more)),error} 33 34 def abort(~S:Data,~C:Type,~R:Type,~E:Data,~P:Type,~Q:Type,~identity:Identity.Declaration,~project:P -> P & D.Raw,~L:Type,~A:Type,~Error:Data,~Out:Type,~recover:L -> A -> List> -> List> -> L,error:Error,local:L,args:A,frame:F.Frame) -> Local.Outcome,L,Error,Out>: 35 match frame: 36 case F.Frame{Request.Owner{Batch.Batch{tx,prepared},_},_,_,_,receipts,pending}:recovered(~S,~W.World,~L,~A,~P,~Q,~Error,~Out,~recover,error,local,args,prepared,pending,Journal.abort(~W.World,~E,~Request.Packet

,~Q,receipts,tx)) 37 38 # Non-empty deferred packets require the separate deferred completion route. 39 # Pending is never silently accepted as a completed rollback. 40 def traversal(~S:Data,~C:Type,~R:Type,~E:Data,~P:Type,~Q:Type,~identity:Identity.Declaration,~project:P -> P & D.Raw,~L:Type,~A:Type,~Rows:Data,~Error:Data,~Out:Type,~success:L -> A -> Rows -> L & Out,~failure:L -> A -> L,~recover:L -> A -> List> -> List> -> L,rejected:Error,local:L,result:F.Frame & (A & (T.Outcome & Rows))) -> Local.Outcome,L,Error,Out>: 41 match result: 42 case (F.Frame{Request.Owner{Batch.Batch{tx,[]},_},_,_,_,_,[]},(args,(T.Success{},rows))):committed(~W.World,~L,~A,~Rows,~Error,~Out,~success,~failure,local,args,rows,Commands.tx_finish(~S,~C,~R,~E,~Error,tx,T.Success{})) 43 case (frame,(args,(T.Success{},_))):abort(~S,~C,~R,~E,~P,~Q,~identity,~project,~L,~A,~Error,~Out,~recover,rejected,local,args,frame) 44 case (frame,(args,(T.Failure{error},_))):abort(~S,~C,~R,~E,~P,~Q,~identity,~project,~L,~A,~Error,~Out,~recover,error,local,args,frame) 45 46 def deferred(~S:Data,~C:Type,~R:Type,~E:Data,~P:Type,~Error:Data,~L:Type,~Out:Type,~recover:L -> Out -> List> -> L,local:L,output:Out,result:Batch.Finished,Error>) -> Local.Outcome,L,Error,Out>: 47 match result: 48 case Batch.Committed{world}:Local.Succeeded{world,local,output} 49 case Batch.Failed{world,packets,error}:Local.Failed{world,recover(local,output,packets),error} 50 51 # Construction uses the same retained nominal descriptor as the grants. 52 def begin_owner(~S:Data,~C:Type,~R:Type,~E:Data,~P:Type,~identity:Identity.Declaration,~project:P -> P & D.Raw,world:W.World,codec:Decl.Constructed) -> Request.Owner: 53 Request.Owner{Batch.begin(~S,~C,~R,~E,~Request.Packet

,T.begin(~W.World,~E,world)),codec} 54 def begin_frame(~S:Data,~C:Type,~R:Type,~E:Data,~P:Type,~Q:Type,~identity:Identity.Declaration,~project:P -> P & D.Raw,world:W.World,codec:Decl.Constructed) -> F.Frame: 55 F.Frame{begin_owner(~S,~C,~R,~E,~P,~identity,~project,world,codec),W.Handle{0,Key.EntityKey{0,0}},None{},None{},[],[]} 56 def finish_deferred(~S:Data,~C:Type,~R:Type,~E:Data,~P:Type,~Error:Data,~identity:Identity.Declaration,~project:P -> P & D.Raw,~attempt:W.World -> W.Handle -> Request.Packet

-> Delivery.Delivery,Request.Packet

>,~delivery_recover:W.World -> Request.Packet

-> W.WorldError -> W.World,~L:Type,~Out:Type,~recover:L -> Out -> List> -> L,local:L,output:Out,owner:Request.Owner,outcome:T.Outcome) -> Local.Outcome,L,Error,Out>: 57 deferred(~S,~C,~R,~E,~P,~Error,~L,~Out,~recover,local,output,Request.finish(~S,~C,~R,~E,~P,~Error,~identity,~project,~attempt,~delivery_recover,owner,outcome))