1 import Base 2 import entity_key.bend as Key 3 import ./persistence_declaration.bend as Persist 4 import ./decode_data.bend as D 5 import ./ordinary_component_binding.bend as Binding 6 import ./ordinary_declaration.bend as Identity 7 import ./column.bend as Col 8 import ./world.bend as W 9 import ./ordinary_schema.bend as Schema 10 import ./schema_fragments.bend as Fragment 11 import ./ordinary_schema_provision.bend as Ordinary 12 import ./ordinary_schema_dump.bend as Dump 13 # Consume the SAME operational Binding; no second identity/lens debug input. 14 # Existing schema-authoring lenses remain trusted, not universal identity proofs. 15 def counted(~C:Type,total:U32,next:C -> U32 -> C & U32,result:C & Bool) -> C & U32: 16 match result: 17 case (store,True{}):next(store,U32.add(total,1)) 18 case (store,False{}):next(store,total) 19 def has_returned(~S:Data,~C:Type,~Rest:Type,~P:Type,~put:Rest -> Col.Column -> C,rest:Rest,result:Col.Column & Bool) -> C & Bool: 20 match result: 21 case (column,present):(put(rest,column),present) 22 def has_taken(~S:Data,~C:Type,~Rest:Type,~P:Type,~put:Rest -> Col.Column -> C,id:U32,result:Rest & Col.Column) -> C & Bool: 23 match result: 24 case (rest,column):has_returned(~S,~C,~Rest,~P,~put,rest,Col.has(~S,~P,column,id)) 25 # Trusted storage presence adapter using the operational column lenses. 26 # Returns store and Bool for a slot index, without World/handle validation. 27 # Ordinary callers provide live handles through the population/dump route. 28 def has(~S:Data,~C:Type,~Rest:Type,~P:Type,~take:C -> Rest & Col.Column,~put:Rest -> Col.Column -> C,store:C,id:U32) -> C & Bool:has_taken(~S,~C,~Rest,~P,~put,id,take(store)) 29 def count_loop(~S:Data,~C:Type,~Rest:Type,~P:Type,~take:C -> Rest & Col.Column,~put:Rest -> Col.Column -> C,handles:List<&2,W.Handle>,store:C,total:U32) -> C & U32: 30 match handles: 31 case []:(store,total) 32 case W.Handle{_,Key.EntityKey{id,_}} <> rest:counted(~C,total,store=>total=>count_loop(~S,~C,~Rest,~P,~take,~put,rest,store,total),has(~S,~C,~Rest,~P,~take,~put,store,id)) 33 def count_returned(~C:Type,result:C & U32) -> C & List<&2,Maybe<&2,U32>>: 34 match result: 35 case (store,total):(store,[Some{total}]) 36 # Trusted population callback counting this bound component among supplied 37 # handles and returning the retained store with one Some count slot. 38 # Does not validate namespaces/generations; use the matching ordinary traversal. 39 def count(~S:Data,~C:Type,~Rest:Type,~P:Type,~take:C -> Rest & Col.Column,~put:Rest -> Col.Column -> C,store:C,handles:List<&2,W.Handle>) -> C & List<&2,Maybe<&2,U32>>:count_returned(~C,count_loop(~S,~C,~Rest,~P,~take,~put,handles,store,0)) 40 def rendered(~P:Type,~V:Data,~render:V -> String,result:P & V) -> P & String: 41 match result: 42 case (owner,value):(owner,render(value)) 43 # Thread a component payload through view and render its detached Data V. 44 # view must return P; render owns no affine payload. Does not access a World. 45 def present(~P:Type,~V:Data,~view:P -> P & V,~render:V -> String,owner:P) -> P & String:rendered(~P,~V,~render,view(owner)) 46 def view_returned(~S:Data,~C:Type,~Rest:Type,~P:Type,~put:Rest -> Col.Column -> C,rest:Rest,result:Col.Column & Maybe<&2,String>) -> C & List<&2,Maybe<&2,String>>: 47 match result: 48 case (column,value):(put(rest,column),[value]) 49 def view_taken(~S:Data,~C:Type,~Rest:Type,~P:Type,~V:Data,~put:Rest -> Col.Column -> C,~view:P -> P & V,~render:V -> String,id:U32,result:Rest & Col.Column) -> C & List<&2,Maybe<&2,String>>: 50 match result: 51 case (rest,column):view_returned(~S,~C,~Rest,~P,~put,rest,Col.view(~S,~P,~String,~present(~P,~V,~view,~render),column,id)) 52 # Trusted component-display callback for a raw slot index, returning store 53 # and one optional rendered-value slot. Missing component remains None; 54 # handle validity is established by the enclosing World dump traversal. 55 def values(~S:Data,~C:Type,~Rest:Type,~P:Type,~V:Data,~take:C -> Rest & Col.Column,~put:Rest -> Col.Column -> C,~view:P -> P & V,~render:V -> String,store:C,id:U32) -> C & List<&2,Maybe<&2,String>>:view_taken(~S,~C,~Rest,~P,~V,~put,~view,~render,id,take(store)) 56 def no_resource(value:Unit) -> Unit & List<&2,Maybe<&2,String>>:(value,[None{}]) 57 # Build dump/population provisioning from the SAME operational binding. 58 # Identity, lenses and view are not repeated as debug metadata. render handles 59 # detached V; payload/store ownership stays threaded through trusted callbacks. 60 # Does not read a World or validate arbitrary lens laws during construction. 61 def component(~S:Data,~C:Type,~Rest:Type,~P:Type,~V:Data,~Token:Data,~take:C -> Rest & Col.Column,~put:Rest -> Col.Column -> C,~view:P -> P & V,~render:V -> String,~empty:Unit -> C,binding:Binding.Binding) -> Dump.Provision: 62 match binding: 63 case Binding.Binding{+identity,_}:Dump.Provision{Ordinary.Provision{Schema.Schema{[Fragment.Entry{Fragment.Component{},Identity.key(~S,~P,identity),Identity.key(~S,~P,identity)}]}}} 64 def joined(~C:Type,~V:Data,before:List<&2,Maybe<&2,V>>,result:C & List<&2,Maybe<&2,V>>) -> C & List<&2,Maybe<&2,V>>: 65 match result: 66 case (store,after):(store,List.append(&2,Maybe<&2,V>,before,after)) 67 def next_count(~S:Data,~C:Type,~right:C -> List<&2,W.Handle> -> C & List<&2,Maybe<&2,U32>>,handles:List<&2,W.Handle>,result:C & List<&2,Maybe<&2,U32>>) -> C & List<&2,Maybe<&2,U32>>: 68 match result: 69 case (store,before):joined(~C,~U32,before,right(store,handles)) 70 def append_count(~S:Data,~C:Type,~left:C -> List<&2,W.Handle> -> C & List<&2,Maybe<&2,U32>>,~right:C -> List<&2,W.Handle> -> C & List<&2,Maybe<&2,U32>>,store:C,handles:List<&2,W.Handle>) -> C & List<&2,Maybe<&2,U32>>: 71 +handles=handles 72 next_count(~S,~C,~right,handles,left(store,handles)) 73 def next_values(~C:Type,~right:C -> U32 -> C & List<&2,Maybe<&2,String>>,id:U32,result:C & List<&2,Maybe<&2,String>>) -> C & List<&2,Maybe<&2,String>>: 74 match result: 75 case (store,before):joined(~C,~String,before,right(store,id)) 76 def append_values(~C:Type,~left:C -> U32 -> C & List<&2,Maybe<&2,String>>,~right:C -> U32 -> C & List<&2,Maybe<&2,String>>,store:C,id:U32) -> C & List<&2,Maybe<&2,String>>: 77 +id=id 78 next_values(~C,~right,id,left(store,id)) 79 def next_resources(~right:Unit -> Unit & List<&2,Maybe<&2,String>>,result:Unit & List<&2,Maybe<&2,String>>) -> Unit & List<&2,Maybe<&2,String>>: 80 match result: 81 case (owner,before):joined(~Unit,~String,before,right(owner)) 82 def append_resources(~left:Unit -> Unit & List<&2,Maybe<&2,String>>,~right:Unit -> Unit & List<&2,Maybe<&2,String>>,owner:Unit) -> Unit & List<&2,Maybe<&2,String>>:next_resources(~right,left(owner)) 83 # Append two component provisions over the same aggregate store owner. 84 # Combines their entry/count/display order without constructing a storage 85 # product. Supplied bindings must consistently refer to that same owner shape. 86 def append(~S:Data,~C:Type,~empty:Unit -> C,~lc:C -> List<&2,W.Handle> -> C & List<&2,Maybe<&2,U32>>,~rc:C -> List<&2,W.Handle> -> C & List<&2,Maybe<&2,U32>>,~lv:C -> U32 -> C & List<&2,Maybe<&2,String>>,~rv:C -> U32 -> C & List<&2,Maybe<&2,String>>,~lr:Unit -> Unit & List<&2,Maybe<&2,String>>,~rr:Unit -> Unit & List<&2,Maybe<&2,String>>,left:Dump.Provision,right:Dump.Provision) -> Dump.Provision: 87 match left right: 88 case Dump.Provision{Ordinary.Provision{Schema.Schema{left}}} Dump.Provision{Ordinary.Provision{Schema.Schema{right}}}:Dump.Provision{Ordinary.Provision{Schema.Schema{List.append(&2,Fragment.Entry,left,right)}}} 89 # Resource identity is supplied once through the existing ordinary declaration. 90 def trailing_none(~C:Type,~V:Data,result:C & List<&2,Maybe<&2,V>>) -> C & List<&2,Maybe<&2,V>>: 91 match result: 92 case (store,before):(store,List.append(&2,Maybe<&2,V>,before,[None{}])) 93 def resource_count(~S:Data,~C:Type,~count:C -> List<&2,W.Handle> -> C & List<&2,Maybe<&2,U32>>,store:C,handles:List<&2,W.Handle>) -> C & List<&2,Maybe<&2,U32>>:trailing_none(~C,~U32,count(store,handles)) 94 def resource_values(~C:Type,~read:C -> U32 -> C & List<&2,Maybe<&2,String>>,store:C,id:U32) -> C & List<&2,Maybe<&2,String>>:trailing_none(~C,~String,read(store,id)) 95 def resource_returned(~R:Type,before:List<&2,Maybe<&2,String>>,result:R & String) -> R & List<&2,Maybe<&2,String>>: 96 match result: 97 case (owner,text):(owner,List.append(&2,Maybe<&2,String>,before,[Some{text}])) 98 def resource_prefix(~R:Type,~show:R -> R & String,owner:R,result:Unit & List<&2,Maybe<&2,String>>) -> R & List<&2,Maybe<&2,String>>: 99 match result: 100 case (_,before):resource_returned(~R,before,show(owner)) 101 # Advanced resource-display callback composing prior Unit resource slots 102 # with an owner-preserving renderer for R. Returns R and ordered optional text 103 # slots; arbitrary render effects are trusted, not a World transaction. 104 def resources(~R:Type,~before:Unit -> Unit & List<&2,Maybe<&2,String>>,~show:R -> R & String,owner:R) -> R & List<&2,Maybe<&2,String>>:resource_prefix(~R,~show,owner,before(Unit{})) 105 # Extend component provisioning with one ordinary resource declaration and 106 # owner-preserving renderer. Adds None component/count slots for that resource; 107 # it is not counted as a component. Does not construct R or inspect World. 108 def with_resource(~S:Data,~C:Type,~R:Type,~empty:Unit -> C,~count:C -> List<&2,W.Handle> -> C & List<&2,Maybe<&2,U32>>,~read:C -> U32 -> C & List<&2,Maybe<&2,String>>,~before:Unit -> Unit & List<&2,Maybe<&2,String>>,~show:R -> R & String,resource:Schema.Resource,base:Dump.Provision) -> Dump.Provision: 109 match resource base: 110 case Schema.Resource{+key} Dump.Provision{Ordinary.Provision{Schema.Schema{entries}}}:Dump.Provision{Ordinary.Provision{Schema.Schema{List.append(&2,Fragment.Entry,entries,[Fragment.Entry{Fragment.Resource{},key,key}])}}} 111 112 # Rebase existing operational schema entries onto the SAME aggregate owner. 113 # Trusted advanced adapter rebasing a schema onto matching aggregate 114 # storage/display callbacks. Caller must preserve entry/slot consistency; 115 # metadata alone does not prove lens identity or create component authority. 116 def component_schema(~S:Data,~C:Type,~Rest:Type,~P:Type,~V:Data,~Token:Data,~take:C -> Rest & Col.Column,~put:Rest -> Col.Column -> C,~view:P -> P & V,~render:V -> String,~empty:Unit -> C,schema:Schema.Schema,Unit>) -> Dump.Provision: 117 match schema: 118 case Schema.Schema{entries}:Dump.Provision{Ordinary.Provision{Schema.Schema{entries}}} 119 # Build component provisioning with plain classification from the same 120 # operational binding and identity-bound persistence extension. Derives count 121 # and display routes; classification does not itself execute codecs or snapshots. 122 def component_plain(~S:Data,~C:Type,~Rest:Type,~P:Type,~V:Data,~Token:Data,~take:C -> Rest & Col.Column,~put:Rest -> Col.Column -> C,~view:P -> P & V,~render:V -> String,~empty:Unit -> C,~binding:Binding.Binding,extension:Persist.Plain) -> Dump.Provision:component_schema(~S,~C,~Rest,~P,~V,~Token,~take,~put,~view,~render,~empty,Schema.component_plain(~S,~P,~Binding.identity(~S,~C,~Rest,~P,~V,~Token,~take,~put,~view,binding),extension)) 123 # Build component provisioning with transient classification from the same 124 # operational binding and identity-bound persistence extension. Derives count 125 # and display routes; classification does not itself execute codecs or snapshots. 126 def component_transient(~S:Data,~C:Type,~Rest:Type,~P:Type,~V:Data,~Token:Data,~take:C -> Rest & Col.Column,~put:Rest -> Col.Column -> C,~view:P -> P & V,~render:V -> String,~empty:Unit -> C,~binding:Binding.Binding,extension:Persist.Transient) -> Dump.Provision:component_schema(~S,~C,~Rest,~P,~V,~Token,~take,~put,~view,~render,~empty,Schema.component_transient(~S,~P,~Binding.identity(~S,~C,~Rest,~P,~V,~Token,~take,~put,~view,binding),extension)) 127 # Build component provisioning with constructed classification from the same 128 # operational binding and identity-bound persistence extension. Derives count 129 # and display routes; classification does not itself execute codecs or snapshots. 130 def component_constructed(~S:Data,~C:Type,~Rest:Type,~P:Type,~V:Data,~Token:Data,~take:C -> Rest & Col.Column,~put:Rest -> Col.Column -> C,~view:P -> P & V,~render:V -> String,~empty:Unit -> C,~binding:Binding.Binding,~project:P -> P & D.Raw,extension:Persist.Constructed) -> Dump.Provision:component_schema(~S,~C,~Rest,~P,~V,~Token,~take,~put,~view,~render,~empty,Schema.component_constructed(~S,~P,~Binding.identity(~S,~C,~Rest,~P,~V,~Token,~take,~put,~view,binding),~project,extension)) 131 # Trusted advanced adapter appending resource schema entries to an existing 132 # dump provision with matching resource/count/display callbacks. Does not 133 # validate forged callback/entry relationships or create resource payloads. 134 def resource_schema(~S:Data,~C:Type,~R:Type,~empty:Unit -> C,~count:C -> List<&2,W.Handle> -> C & List<&2,Maybe<&2,U32>>,~read:C -> U32 -> C & List<&2,Maybe<&2,String>>,~before:Unit -> Unit & List<&2,Maybe<&2,String>>,~show:R -> R & String,schema:Schema.Schema,base:Dump.Provision) -> Dump.Provision: 135 match schema base: 136 case Schema.Schema{added} Dump.Provision{Ordinary.Provision{Schema.Schema{entries}}}:Dump.Provision{Ordinary.Provision{Schema.Schema{List.append(&2,Fragment.Entry,entries,added)}}} 137 # Extend dump provisioning with a constructed resource declaration and its 138 # owner-preserving presentation. Uses the identity-bound persistence extension; 139 # creates metadata/slots, not a resource payload or a saved value. 140 def with_resource_constructed(~S:Data,~C:Type,~R:Type,~empty:Unit -> C,~count:C -> List<&2,W.Handle> -> C & List<&2,Maybe<&2,U32>>,~read:C -> U32 -> C & List<&2,Maybe<&2,String>>,~before:Unit -> Unit & List<&2,Maybe<&2,String>>,~show:R -> R & String,~identity:Identity.Declaration,~project:R -> R & D.Raw,extension:Persist.Constructed,base:Dump.Provision) -> Dump.Provision:resource_schema(~S,~C,~R,~empty,~count,~read,~before,~show,Schema.resource_constructed(~S,~R,~identity,~project,extension),base) 141 # Extend dump provisioning with a plain resource declaration and its 142 # owner-preserving presentation. Uses the identity-bound persistence extension; 143 # creates metadata/slots, not a resource payload or a saved value. 144 def with_resource_plain(~S:Data,~C:Type,~R:Type,~empty:Unit -> C,~count:C -> List<&2,W.Handle> -> C & List<&2,Maybe<&2,U32>>,~read:C -> U32 -> C & List<&2,Maybe<&2,String>>,~before:Unit -> Unit & List<&2,Maybe<&2,String>>,~show:R -> R & String,~identity:Identity.Declaration,extension:Persist.Plain,base:Dump.Provision) -> Dump.Provision:resource_schema(~S,~C,~R,~empty,~count,~read,~before,~show,Schema.resource_plain(~S,~R,~identity,extension),base) 145 # Extend dump provisioning with a transient resource declaration and its 146 # owner-preserving presentation. Uses the identity-bound persistence extension; 147 # creates metadata/slots, not a resource payload or a saved value. 148 def with_resource_transient(~S:Data,~C:Type,~R:Type,~empty:Unit -> C,~count:C -> List<&2,W.Handle> -> C & List<&2,Maybe<&2,U32>>,~read:C -> U32 -> C & List<&2,Maybe<&2,String>>,~before:Unit -> Unit & List<&2,Maybe<&2,String>>,~show:R -> R & String,~identity:Identity.Declaration,extension:Persist.Transient,base:Dump.Provision) -> Dump.Provision:resource_schema(~S,~C,~R,~empty,~count,~read,~before,~show,Schema.resource_transient(~S,~R,~identity,extension),base)