1 import Base 2 import ./execution_save_data.bend as Saved 3 import ./execution_save_recipe.bend as Recipe 4 import ./execution_composer_layout.bend as Layout 5 import ./chunk_column.bend as Column 6 import ./chunk_shape.bend as Part 7 import ./execution_query_identity.bend as Index 8 import ./lifecycle.bend as Life 9 import ./decode_data.bend as D 10 import ./decode_size.bend as Size 11 12 type Mode is Data: 13 Plain{} 14 Transient{} 15 Constructed{codec:D.Codec} 16 def field(+key:String,stamp:Maybe<&2,Life.Stamp>,value:Maybe<&2,Recipe.Field>) -> Saved.Fields: 17 match value: 18 case None{}:Saved.Fields{[Saved.Field{key,False{},Saved.Absent{},stamp}],None{}} 19 case Some{Recipe.Omitted{}}:Saved.Fields{[Saved.Field{key,True{},Saved.Omitted{},stamp}],None{}} 20 case Some{Recipe.Saved{D.Field{_,raw}}}:Saved.Fields{[Saved.Field{key,True{},Saved.Persisted{raw},stamp}],None{}} 21 case Some{Recipe.Refused{reason}}:Saved.error(reason) 22 def checked(-P:Type,owner:P,key:String,+codec:D.Codec,+fuel:Nat,checked:D.Checked) -> P & Recipe.Field: 23 match checked: 24 case D.Accepted{raw}:(owner,Recipe.Saved{D.Field{key,D.canonical(fuel,codec,raw)}}) 25 case D.Rejected{error}:(owner,Recipe.Refused{Recipe.InvalidProjection{key,error}}) 26 def budgeted(-P:Type,owner:P,key:String,+codec:D.Codec,+raw:D.Raw,+fuel:Nat) -> P & Recipe.Field: 27 checked(P,owner,key,codec,fuel,D.validate(fuel,D.Continue{[D.Work{codec,raw,"$"}]},raw)) 28 def projected(-P:Type,key:String,+codec:D.Codec,result:P & D.Raw) -> P & Recipe.Field: 29 match result: 30 case (owner,+raw):budgeted(P,owner,key,codec,raw,Size.budget(codec,raw)) 31 def describe(-P:Type,mode:Mode,key:String,project:P -> P & D.Raw,owner:P) -> P & Recipe.Field: 32 match mode: 33 case Plain{}:(owner,Recipe.Refused{Recipe.PlainUnserializable{key}}) 34 case Transient{}:(owner,Recipe.Omitted{}) 35 case Constructed{codec}:projected(P,key,codec,project(owner)) 36 def viewed_returned(-P:Type,-V:Data,view:V,result:P & Recipe.Field) -> Layout.Viewed & Recipe.Field: 37 match result: 38 case (owner,field):(Layout.Viewed{owner,view},field) 39 def viewed(-P:Type,-V:Data,mode:Mode,key:String,project:P -> P & D.Raw,stored:Layout.Viewed) -> Layout.Viewed & Recipe.Field: 40 match stored: 41 case Layout.Viewed{owner,view}:viewed_returned(P,V,view,describe(P,mode,key,project,owner)) 42 def restored_value(-S:Data,-P:Type,values:Array>,stamps:Array,index:U32,stamp:Life.Stamp,result:P & Recipe.Field) -> Column.Column & (Maybe<&2,Recipe.Field> & Maybe<&2,Life.Stamp>): 43 match result: 44 case (owner,field):(Column.Leaf{Array.set(Maybe<&1,P>,values,index,Some{owner}),stamps},(Some{field},Some{stamp})) 45 def taken(-S:Data,-P:Type,project:P -> P & Recipe.Field,stamps:Array,index:U32,stamp:Life.Stamp,result:Array> & Maybe<&1,P>) -> Column.Column & (Maybe<&2,Recipe.Field> & Maybe<&2,Life.Stamp>): 46 match result: 47 case (values,None{}):(Column.Leaf{values,stamps},(None{},Some{stamp})) 48 case (values,Some{owner}):restored_value(S,P,values,stamps,index,stamp,project(owner)) 49 def stamp_read(-S:Data,-P:Type,project:P -> P & Recipe.Field,values:Array>,+index:U32,result:Array & Life.Stamp) -> Column.Column & (Maybe<&2,Recipe.Field> & Maybe<&2,Life.Stamp>): 50 match result: 51 case (stamps,stamp):taken(S,P,project,stamps,index,stamp,Array.swap(Maybe<&1,P>,values,index,None{})) 52 def leaf(-S:Data,-P:Type,project:P -> P & Recipe.Field,values:Array>,stamps:Array,+index:U32,allowed:Bool) -> Column.Column & (Maybe<&2,Recipe.Field> & Maybe<&2,Life.Stamp>): 53 match allowed: 54 case False{}:(Column.Leaf{values,stamps},(None{},None{})) 55 case True{}:stamp_read(S,P,project,values,index,Array.get(Life.Stamp,stamps,index)) 56 def branches(-S:Data,-P:Type,half:U32,leftResult:Column.Column & (Maybe<&2,Recipe.Field> & Maybe<&2,Life.Stamp>),rightResult:Column.Column & (Maybe<&2,Recipe.Field> & Maybe<&2,Life.Stamp>),first:Bool) -> Column.Column & (Maybe<&2,Recipe.Field> & Maybe<&2,Life.Stamp>): 57 match leftResult rightResult first: 58 case (left,value), (right,_), True{}:(Column.Branch{half,left,right},value) 59 case (left,_), (right,value), False{}:(Column.Branch{half,left,right},value) 60 def branch(-S:Data,-P:Type,left:Maybe<&1,P -> P & Recipe.Field> -> Column.Column & (Maybe<&2,Recipe.Field> & Maybe<&2,Life.Stamp>),right:Maybe<&1,P -> P & Recipe.Field> -> Column.Column & (Maybe<&2,Recipe.Field> & Maybe<&2,Life.Stamp>),half:U32,project:P -> P & Recipe.Field,first:Bool) -> Column.Column & (Maybe<&2,Recipe.Field> & Maybe<&2,Life.Stamp>): 61 match first: 62 case True{}:branches(S,P,half,left(Some{project}),right(None{}),True{}) 63 case False{}:branches(S,P,half,left(None{}),right(Some{project}),False{}) 64 def project_column(-S:Data,-P:Type,column:Column.Column,+index:U32,project:Maybe<&1,P -> P & Recipe.Field>) -> Column.Column & (Maybe<&2,Recipe.Field> & Maybe<&2,Life.Stamp>): 65 match column project: 66 case column None{}:(column,(None{},None{})) 67 case Column.Leaf{values,stamps} Some{project}:leaf(S,P,project,values,stamps,index,U32.is_lt(index,8)) 68 case Column.Branch{+half,left,right} Some{project}:branch(S,P,project_column(S,P,left,index),project_column(S,P,right,U32.sub(index,half)),half,project,U32.is_lt(index,half)) 69 def component_returned(-S:Data,-P:Type,-V:Data,+key:String,-origin:Layout.Layout,result:Column.Column> & (Maybe<&2,Recipe.Field> & Maybe<&2,Life.Stamp>)) -> Layout.ColumnSlot,key,origin> & Saved.Fields: 70 match result: 71 case (column,(value,stamp)):(Layout.ColumnSlot{column},field(key,stamp,value)) 72 def component_offset(-S:Data,-P:Type,-V:Data,+key:String,-origin:Layout.Layout,mode:Mode,project:P -> P & D.Raw,column:Column.Column>,offset:Maybe<&2,U32>) -> Layout.ColumnSlot,key,origin> & Saved.Fields: 73 match offset: 74 case None{}:(Layout.ColumnSlot{column},Saved.error(Recipe.MalformedColumn{key})) 75 case Some{index}:component_returned(S,P,V,key,origin,project_column(S,Layout.Viewed,column,index,Some{stored => viewed(P,V,mode,key,project,stored)})) 76 def component_valid(-S:Data,-P:Type,-V:Data,+key:String,-origin:Layout.Layout,mode:Mode,project:P -> P & D.Raw,column:Column.Column>,logical:U32,valid:Bool) -> Layout.ColumnSlot,key,origin> & Saved.Fields: 77 match valid: 78 case False{}:(Layout.ColumnSlot{column},Saved.error(Recipe.MalformedColumn{key})) 79 case True{}:component_offset(S,P,V,key,origin,mode,project,column,Index.physical_index(logical)) 80 def component_inspected(-S:Data,-P:Type,-V:Data,+key:String,-origin:Layout.Layout,mode:Mode,project:P -> P & D.Raw,logical:U32,result:Column.Column> & Part.Inspection) -> Layout.ColumnSlot,key,origin> & Saved.Fields: 81 match result: 82 case (column,Part.Inspection{_,capacity,valid}):component_valid(S,P,V,key,origin,mode,project,column,logical,Bool.and(valid,U32.is_le(capacity,Column.maximum_capacity()))) 83 def component(-S:Data,-P:Type,-V:Data,+key:String,-origin:Layout.Layout,mode:Mode,project:P -> P & D.Raw,slot:Layout.ColumnSlot,key,origin>,logical:U32) -> Layout.ColumnSlot,key,origin> & Saved.Fields: 84 match slot: 85 case Layout.ColumnSlot{column}:component_inspected(S,P,V,key,origin,mode,project,logical,Part.inspect(S,Layout.Viewed,column)) 86 def resource_returned(-S:Data,-P:Type,-V:Data,+key:String,-origin:Layout.Layout,view:V,+stamp:Life.Stamp,result:P & Recipe.Field) -> Layout.ResourceSlot,key,origin> & Saved.Fields: 87 match result: 88 case (owner,value):(Layout.ResourceSlot{Layout.Viewed{owner,view},stamp},field(key,Some{stamp},Some{value})) 89 def resource(-S:Data,-P:Type,-V:Data,+key:String,-origin:Layout.Layout,mode:Mode,project:P -> P & D.Raw,slot:Layout.ResourceSlot,key,origin>) -> Layout.ResourceSlot,key,origin> & Saved.Fields: 90 match slot: 91 case Layout.ResourceSlot{Layout.Viewed{owner,view},stamp}:resource_returned(S,P,V,key,origin,view,stamp,describe(P,mode,key,project,owner))