ordinary_binding_provision.bend

bendvy-ecs-core@0.1.0.1 · 148 lines · 0 definitions

1import Base
2import entity_key.bend as Key
3import bendvy-ecs-core@0.1.0.1/persistence_declaration.bend as Persist
4import bendvy-ecs-core@0.1.0.1/decode_data.bend as D
5import bendvy-ecs-core@0.1.0.1/ordinary_component_binding.bend as Binding
6import bendvy-ecs-core@0.1.0.1/ordinary_declaration.bend as Identity
7import bendvy-ecs-core@0.1.0.1/column.bend as Col
8import bendvy-ecs-core@0.1.0.1/world.bend as W
9import bendvy-ecs-core@0.1.0.1/ordinary_schema.bend as Schema
10import bendvy-ecs-core@0.1.0.1/schema_fragments.bend as Fragment
11import bendvy-ecs-core@0.1.0.1/ordinary_schema_provision.bend as Ordinary
12import bendvy-ecs-core@0.1.0.1/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.
15def 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)
19def has_returned(~S:Data,~C:Type,~Rest:Type,~P:Type,~put:Rest -> Col.Column<S,P> -> C,rest:Rest,result:Col.Column<S,P> & Bool) -> C & Bool:
20  match result:
21    case (column,present):(put(rest,column),present)
22def has_taken(~S:Data,~C:Type,~Rest:Type,~P:Type,~put:Rest -> Col.Column<S,P> -> C,id:U32,result:Rest & Col.Column<S,P>) -> 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.
28def has(~S:Data,~C:Type,~Rest:Type,~P:Type,~take:C -> Rest & Col.Column<S,P>,~put:Rest -> Col.Column<S,P> -> C,store:C,id:U32) -> C & Bool:has_taken(~S,~C,~Rest,~P,~put,id,take(store))
29def count_loop(~S:Data,~C:Type,~Rest:Type,~P:Type,~take:C -> Rest & Col.Column<S,P>,~put:Rest -> Col.Column<S,P> -> C,handles:List<&2,W.Handle<S>>,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))
33def 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.
39def count(~S:Data,~C:Type,~Rest:Type,~P:Type,~take:C -> Rest & Col.Column<S,P>,~put:Rest -> Col.Column<S,P> -> C,store:C,handles:List<&2,W.Handle<S>>) -> C & List<&2,Maybe<&2,U32>>:count_returned(~C,count_loop(~S,~C,~Rest,~P,~take,~put,handles,store,0))
40def 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.
45def present(~P:Type,~V:Data,~view:P -> P & V,~render:V -> String,owner:P) -> P & String:rendered(~P,~V,~render,view(owner))
46def view_returned(~S:Data,~C:Type,~Rest:Type,~P:Type,~put:Rest -> Col.Column<S,P> -> C,rest:Rest,result:Col.Column<S,P> & Maybe<&2,String>) -> C & List<&2,Maybe<&2,String>>:
47  match result:
48    case (column,value):(put(rest,column),[value])
49def view_taken(~S:Data,~C:Type,~Rest:Type,~P:Type,~V:Data,~put:Rest -> Col.Column<S,P> -> C,~view:P -> P & V,~render:V -> String,id:U32,result:Rest & Col.Column<S,P>) -> 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.
55def values(~S:Data,~C:Type,~Rest:Type,~P:Type,~V:Data,~take:C -> Rest & Col.Column<S,P>,~put:Rest -> Col.Column<S,P> -> 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))
56def 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.
61def component(~S:Data,~C:Type,~Rest:Type,~P:Type,~V:Data,~Token:Data,~take:C -> Rest & Col.Column<S,P>,~put:Rest -> Col.Column<S,P> -> C,~view:P -> P & V,~render:V -> String,~empty:Unit -> C,binding:Binding.Binding<S,C,Rest,P,V,Token,take,put,view>) -> Dump.Provision<S,C,Unit,empty,count(~S,~C,~Rest,~P,~take,~put),values(~S,~C,~Rest,~P,~V,~take,~put,~view,~render),no_resource>:
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)}]}}}
64def 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))
67def next_count(~S:Data,~C:Type,~right:C -> List<&2,W.Handle<S>> -> C & List<&2,Maybe<&2,U32>>,handles:List<&2,W.Handle<S>>,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))
70def append_count(~S:Data,~C:Type,~left:C -> List<&2,W.Handle<S>> -> C & List<&2,Maybe<&2,U32>>,~right:C -> List<&2,W.Handle<S>> -> C & List<&2,Maybe<&2,U32>>,store:C,handles:List<&2,W.Handle<S>>) -> C & List<&2,Maybe<&2,U32>>:
71  +handles=handles
72  next_count(~S,~C,~right,handles,left(store,handles))
73def 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))
76def 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))
79def 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))
82def 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.
86def append(~S:Data,~C:Type,~empty:Unit -> C,~lc:C -> List<&2,W.Handle<S>> -> C & List<&2,Maybe<&2,U32>>,~rc:C -> List<&2,W.Handle<S>> -> 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<S,C,Unit,empty,lc,lv,lr>,right:Dump.Provision<S,C,Unit,empty,rc,rv,rr>) -> Dump.Provision<S,C,Unit,empty,append_count(~S,~C,~lc,~rc),append_values(~C,~lv,~rv),append_resources(~lr,~rr)>:
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<S>,left,right)}}}
89# Resource identity is supplied once through the existing ordinary declaration.
90def 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{}]))
93def resource_count(~S:Data,~C:Type,~count:C -> List<&2,W.Handle<S>> -> C & List<&2,Maybe<&2,U32>>,store:C,handles:List<&2,W.Handle<S>>) -> C & List<&2,Maybe<&2,U32>>:trailing_none(~C,~U32,count(store,handles))
94def 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))
95def 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}]))
98def 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.
104def 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.
108def with_resource(~S:Data,~C:Type,~R:Type,~empty:Unit -> C,~count:C -> List<&2,W.Handle<S>> -> 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<S,R>,base:Dump.Provision<S,C,Unit,empty,count,read,before>) -> Dump.Provision<S,C,R,empty,resource_count(~S,~C,~count),resource_values(~C,~read),resources(~R,~before,~show)>:
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<S>,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.
116def component_schema(~S:Data,~C:Type,~Rest:Type,~P:Type,~V:Data,~Token:Data,~take:C -> Rest & Col.Column<S,P>,~put:Rest -> Col.Column<S,P> -> C,~view:P -> P & V,~render:V -> String,~empty:Unit -> C,schema:Schema.Schema<S,Col.Column<S,P>,Unit>) -> Dump.Provision<S,C,Unit,empty,count(~S,~C,~Rest,~P,~take,~put),values(~S,~C,~Rest,~P,~V,~take,~put,~view,~render),no_resource>:
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.
122def component_plain(~S:Data,~C:Type,~Rest:Type,~P:Type,~V:Data,~Token:Data,~take:C -> Rest & Col.Column<S,P>,~put:Rest -> Col.Column<S,P> -> C,~view:P -> P & V,~render:V -> String,~empty:Unit -> C,~binding:Binding.Binding<S,C,Rest,P,V,Token,take,put,view>,extension:Persist.Plain<S,P,Binding.identity(~S,~C,~Rest,~P,~V,~Token,~take,~put,~view,binding)>) -> Dump.Provision<S,C,Unit,empty,count(~S,~C,~Rest,~P,~take,~put),values(~S,~C,~Rest,~P,~V,~take,~put,~view,~render),no_resource>: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.
126def component_transient(~S:Data,~C:Type,~Rest:Type,~P:Type,~V:Data,~Token:Data,~take:C -> Rest & Col.Column<S,P>,~put:Rest -> Col.Column<S,P> -> C,~view:P -> P & V,~render:V -> String,~empty:Unit -> C,~binding:Binding.Binding<S,C,Rest,P,V,Token,take,put,view>,extension:Persist.Transient<S,P,Binding.identity(~S,~C,~Rest,~P,~V,~Token,~take,~put,~view,binding)>) -> Dump.Provision<S,C,Unit,empty,count(~S,~C,~Rest,~P,~take,~put),values(~S,~C,~Rest,~P,~V,~take,~put,~view,~render),no_resource>: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.
130def component_constructed(~S:Data,~C:Type,~Rest:Type,~P:Type,~V:Data,~Token:Data,~take:C -> Rest & Col.Column<S,P>,~put:Rest -> Col.Column<S,P> -> C,~view:P -> P & V,~render:V -> String,~empty:Unit -> C,~binding:Binding.Binding<S,C,Rest,P,V,Token,take,put,view>,~project:P -> P & D.Raw,extension:Persist.Constructed<S,P,Binding.identity(~S,~C,~Rest,~P,~V,~Token,~take,~put,~view,binding),project>) -> Dump.Provision<S,C,Unit,empty,count(~S,~C,~Rest,~P,~take,~put),values(~S,~C,~Rest,~P,~V,~take,~put,~view,~render),no_resource>: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.
134def resource_schema(~S:Data,~C:Type,~R:Type,~empty:Unit -> C,~count:C -> List<&2,W.Handle<S>> -> 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<S,Unit,R>,base:Dump.Provision<S,C,Unit,empty,count,read,before>) -> Dump.Provision<S,C,R,empty,resource_count(~S,~C,~count),resource_values(~C,~read),resources(~R,~before,~show)>:
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<S>,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.
140def with_resource_constructed(~S:Data,~C:Type,~R:Type,~empty:Unit -> C,~count:C -> List<&2,W.Handle<S>> -> 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<S,R>,~project:R -> R & D.Raw,extension:Persist.Constructed<S,R,identity,project>,base:Dump.Provision<S,C,Unit,empty,count,read,before>) -> Dump.Provision<S,C,R,empty,resource_count(~S,~C,~count),resource_values(~C,~read),resources(~R,~before,~show)>: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.
144def with_resource_plain(~S:Data,~C:Type,~R:Type,~empty:Unit -> C,~count:C -> List<&2,W.Handle<S>> -> 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<S,R>,extension:Persist.Plain<S,R,identity>,base:Dump.Provision<S,C,Unit,empty,count,read,before>) -> Dump.Provision<S,C,R,empty,resource_count(~S,~C,~count),resource_values(~C,~read),resources(~R,~before,~show)>: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.
148def with_resource_transient(~S:Data,~C:Type,~R:Type,~empty:Unit -> C,~count:C -> List<&2,W.Handle<S>> -> 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<S,R>,extension:Persist.Transient<S,R,identity>,base:Dump.Provision<S,C,Unit,empty,count,read,before>) -> Dump.Provision<S,C,R,empty,resource_count(~S,~C,~count),resource_values(~C,~read),resources(~R,~before,~show)>:resource_schema(~S,~C,~R,~empty,~count,~read,~before,~show,Schema.resource_transient(~S,~R,~identity,extension),base)