ordinary_app_resource_field_declaration.bend
bendvy-ecs-core@0.1.0.0 · 144 lines · 0 definitions
1import Base
2import bendvy-ecs-core@0.1.0.0/schema_fragments.bend as Fragments
3import bendvy-ecs-core@0.1.0.0/relation_commands.bend as RelationWorld
4import bendvy-ecs-core@0.1.0.0/relation_providers.bend as RelationOps
5import bendvy-ecs-core@0.1.0.0/ordinary_app_relation.bend as Relation
6import bendvy-ecs-core@0.1.0.0/relation_failure_reader.bend as RelationDecl
7import bendvy-ecs-core@0.1.0.0/relation_types.bend as RelationTypes
8import bendvy-ecs-core@0.1.0.0/ordinary_app_observation_data.bend as DTO
9import bendvy-ecs-core@0.1.0.0/machine.bend as Machine
10import bendvy-ecs-core@0.1.0.0/ordinary_machine_declaration.bend as MachineDecl
11import bendvy-ecs-core@0.1.0.0/ordinary_machine_operations.bend as MachineOps
12import bendvy-ecs-core@0.1.0.0/inspector.bend as Inspect
13import bendvy-ecs-core@0.1.0.0/capabilities.bend as Cap
14import bendvy-ecs-core@0.1.0.0/ordinary_query_declaration.bend as Query
15import bendvy-ecs-core@0.1.0.0/resource_field_binding.bend as Binding
16import bendvy-ecs-core@0.1.0.0/resource_field.bend as Lens
17import bendvy-ecs-core@0.1.0.0/ordinary_resource_field_system.bend as Field
18import bendvy-ecs-core@0.1.0.0/ordinary_schema.bend as Schema
19import bendvy-ecs-core@0.1.0.0/owner_product.bend as Product
20import bendvy-ecs-core@0.1.0.0/world.bend as W
21import bendvy-ecs-core@0.1.0.0/transaction.bend as T
22# Same canonical field binding drives the grant and detached owning observation.
23# App declaration for a selected resource field or a declared machine/relation.
24# Combines an operational grant with its owner-threading Data observation and
25# renderer. Schema and resource path are fixed by the typed constructors below;
26# there is no live resource owner in this declaration. Ordinary resource-field
27# operations and explicit recoverable operations are distinct APIs; see
28# ordinary-recovery-resource-field for returned recovery owners.
29type Declaration<-S:Data,-C:Type,-R:Type,-E:Data,-Ops:Type -> Type,-V:Data> is Type:
30 Declaration{ordinary:Field.Declaration<S,T.Tx<W.World<S,C,R,E>,E>,Ops(T.Tx<W.World<S,C,R,E>,E>)>,observe:W.World<S,C,R,E> -> W.World<S,C,R,E> & V,render:V -> String}
31# Operation-family alias for reading one declared field as a Data view.
32# The resource identity remains in the grant type, so equal payload types do not
33# make distinct schema resource declarations interchangeable.
34def read_ops(~S:Data,~P:Type,~identity:Schema.Resource<S,P>,~V:Data,H:Type) -> Type:
35 Field.Read<S,P,identity,H,V>
36# Operation-family alias for reading and replacing one declared field P.
37# Replacement consumes P; the enclosing resource and affine sibling owners stay
38# inside the opaque callback owner H.
39def write_ops(~S:Data,~P:Type,~identity:Schema.Resource<S,P>,~V:Data,H:Type) -> Type:
40 Field.Write<S,P,identity,H,V>
41# Declare selected-field read access through the canonical binding.
42# lens, identity and binding must describe the same field of resource owner R;
43# view threads the selected P back with Data V. The observer uses that same lens
44# and view, returning the World and siblings rather than exposing live aliases.
45# Construct bindings with resource-field-binding; do not supply a metadata-only
46# name as authority. No field operation runs while building this declaration.
47def read(~S:Data,~C:Type,~R:Type,~E:Data,~P:Type,~Rest:Type,~V:Data,~lens:Product.Lens<R,P,Rest>,~identity:Schema.Resource<S,P>,~binding:Binding.Binding<S,R,P,Rest,lens,identity>,~view:P -> P & V,~render:V -> String) -> Declaration<S,C,R,E,read_ops(~S,~P,~identity,~V),V>:
48 Declaration{Field.read(~S,~C,~R,~E,~P,~Rest,~V,~lens,~identity,~binding,~view),W.observe_resource(~S,~C,~R,~E,~V,~Lens.project(~R,~P,~Rest,~V,~lens,~view)),render}
49# Declare selected-field read/replacement access through the canonical binding.
50# The setter journals the displaced field and threads siblings through the lens;
51# a failed transaction restores its recorded field owner. With tracing enabled,
52# the declared view/render functions supply before/after resource observations.
53# view returns P with its observation; render receives only detached V and
54# returns String. This is not general rollback for projector side effects or IO. For explicit displaced/rejected owner
55# recovery, use ordinary-recovery-resource-field rather than this declaration.
56def write(~S:Data,~C:Type,~R:Type,~E:Data,~P:Type,~Rest:Type,~V:Data,~lens:Product.Lens<R,P,Rest>,~identity:Schema.Resource<S,P>,~binding:Binding.Binding<S,R,P,Rest,lens,identity>,~view:P -> P & V,~render:V -> String) -> Declaration<S,C,R,E,write_ops(~S,~P,~identity,~V),V>:
57 Declaration{Field.Declaration{Field.Write{Lens.write_observed(~S,~C,~R,~E,~P,~Rest,~V,~lens,~view,~render,~Schema.resource_key(~S,~P,identity))},[Query.Clause{Schema.resource_key(~S,~P,identity),Query.Write{}}]},W.observe_resource(~S,~C,~R,~E,~V,~Lens.project(~R,~P,~Rest,~V,~lens,~view)),render}
58# Advanced App projection: consume this declaration and obtain its operational
59# field grant and access clauses. This does not register a system or run a write.
60def ordinary(~S:Data,~C:Type,~R:Type,~E:Data,~Ops:Type -> Type,~V:Data,declaration:Declaration<S,C,R,E,Ops,V>) -> Field.Declaration<S,T.Tx<W.World<S,C,R,E>,E>,Ops(T.Tx<W.World<S,C,R,E>,E>)>:
61 match declaration:
62 case Declaration{ordinary,_,_}:ordinary
63# Advanced App projection: consume this declaration to obtain its World-returning
64# Data observer. Observing uses the declared projection; no live owner is copied.
65def observer(~S:Data,~C:Type,~R:Type,~E:Data,~Ops:Type -> Type,~V:Data,declaration:Declaration<S,C,R,E,Ops,V>) -> W.World<S,C,R,E> -> W.World<S,C,R,E> & V:
66 match declaration:
67 case Declaration{_,observe,_}:observe
68# Obtain the declared V -> String renderer, consuming the declaration.
69# The renderer receives only a Data view, not the selected affine field.
70def renderer(~S:Data,~C:Type,~R:Type,~E:Data,~Ops:Type -> Type,~V:Data,declaration:Declaration<S,C,R,E,Ops,V>) -> V -> String:
71 match declaration:
72 case Declaration{_,_,render}:render
73
74def names(~S:Data,clauses:List<&2,Query.Clause<S>>) -> String:
75 match clauses:
76 case []:""
77 case Query.Clause{key,_} <> []:key
78 case Query.Clause{key,_} <> rest:key ++ "," ++ names(~S,rest)
79# Return clause keys in declaration order, comma-separated, consuming the
80# carrier. The returned display string is not a schema identity or capability.
81def name(~S:Data,~C:Type,~R:Type,~E:Data,~Ops:Type -> Type,~V:Data,declaration:Declaration<S,C,R,E,Ops,V>) -> String:
82 names(~S,Field.clauses(~S,~T.Tx<W.World<S,C,R,E>,E>,~Ops(T.Tx<W.World<S,C,R,E>,E>),ordinary(~S,~C,~R,~E,~Ops,~V,declaration)))
83# App-facing alias of renderer for the same declaration and Data view.
84# Consumes the carrier; it performs no read, write or registration itself.
85def presenter(~S:Data,~C:Type,~R:Type,~E:Data,~Ops:Type -> Type,~V:Data,declaration:Declaration<S,C,R,E,Ops,V>) -> V -> String:
86 renderer(~S,~C,~R,~E,~Ops,~V,declaration)
87
88# The same declared machine supplies its grant, access name and current observer.
89# Operation-family alias for reading a declared machine's CurrentView and
90# submitting QueueInput. The write input is a queued transition request, not a
91# replacement for the complete resource owner or immediate transition execution.
92def machine_ops(~S:Data,~K:Data,~V:Data,H:Type) -> Type:
93 Cap.ValueWrite<H,Machine.QueueInput<V>,Machine.CurrentView<S,K,V>>
94def machine_presented(~S:Data,~K:Data,~V:Data,~C:Type,~R:Type,~E:Data,result:Inspect.Frame<S,C,R,E> & Machine.CurrentView<S,K,V>) -> W.World<S,C,R,E> & Machine.CurrentView<S,K,V>:
95 match result:
96 case (Inspect.Frame{world,_},view):(world,view)
97# Advanced observation route for the declared machine's current value.
98# Returns (World, CurrentView), including Unavailable when the slot has no value;
99# uses a fresh inspector cursor and does not run queued transitions.
100def machine_observe(~S:Data,~K:Data,~V:Data,~C:Type,~R:Type,~E:Data,~take:R -> R & Machine.Slot<S,K,V>,~machine:MachineDecl.Declaration<S,K,V,R,take>,world:W.World<S,C,R,E>) -> W.World<S,C,R,E> & Machine.CurrentView<S,K,V>:
101 machine_presented(~S,~K,~V,~C,~R,~E,MachineDecl.get(~Inspect.Frame<S,C,R,E>,~S,~K,~V,~MachineDecl.inspect(~S,~K,~V,~C,~R,~E,~take,~machine),Inspect.Frame{world,None{}}))
102def machine_render(~S:Data,~K:Data,~V:Data,~render:V -> String,view:Machine.CurrentView<S,K,V>) -> String:
103 match view:
104 case Machine.Unavailable{}:"Unavailable"
105 case Machine.Current{value}:"Current:" ++ render(value)
106# Build a resource-style App declaration for one declared state machine.
107# The same machine supplies the access key, current-value observer and queued
108# write operation. take/put select its Slot and same compares values. The grant
109# submits QueueInput through ordinary-machine-operations; constructing or reading
110# this declaration does not apply a queued transition. See
111# ordinary-machine-declaration and ordinary-machine-operations for that boundary.
112def machine_write(~S:Data,~K:Data,~V:Data,~C:Type,~R:Type,~E:Data,~take:R -> R & Machine.Slot<S,K,V>,~put:R -> Machine.Slot<S,K,V> -> R,~same:V -> V -> Bool,~machine:MachineDecl.Declaration<S,K,V,R,take>,~render:V -> String) -> Declaration<S,C,R,E,machine_ops(~S,~K,~V),Machine.CurrentView<S,K,V>>:
113 Declaration{Field.Declaration{MachineOps.write(~S,~K,~V,~C,~R,~E,~take,~put,~same,~machine),[Query.Clause{MachineDecl.name(~S,~K,~V,~R,~take,machine),Query.Write{}}]},machine_observe(~S,~K,~V,~C,~R,~E,~take,~machine),machine_render(~S,~K,~V,~render)}
114
115# Operation-family alias for a declared schema relation's writable operations.
116# The callback still threads its opaque owner; this is not a raw relation store.
117def relation_ops(~S:Data,H:Type) -> Type:RelationOps.Writable<H,S>
118def relation_name(~S:Data,declaration:RelationDecl.Declaration<S>) -> String:
119 match declaration:
120 case RelationDecl.Declaration{RelationTypes.Descriptor{_,name,_,_}}:name
121def relation_viewed(~S:Data,~C:Type,~R:Type,~E:Data,result:Relation.World(~S,~C,~R,~E) & DTO.Observation<Relation.View<S>>) -> Relation.World(~S,~C,~R,~E) & Relation.View<S>:
122 match result:
123 case (world,DTO.Observation{view,_}):(world,view)
124# Advanced observation route returning the relation World with the declared
125# relation's descriptor and projected rows. It uses the ordinary relation
126# observer; it does not consume an application failure-reader cursor.
127def relation_observe(~S:Data,~C:Type,~R:Type,~E:Data,~relation:RelationDecl.Declaration<S>,world:Relation.World(~S,~C,~R,~E)) -> Relation.World(~S,~C,~R,~E) & Relation.View<S>:
128 relation_viewed(~S,~C,~R,~E,Relation.observe(~S,~C,~R,~E,~relation,~Relation.builtin_row(~S),world))
129def relation_render(~S:Data,view:Relation.View<S>) -> String:
130 match view:
131 case Relation.View{descriptor,rows}:Relation.descriptor_text(~S,descriptor) ++ ":" ++ List.show(&2,Relation.Row(~S),Relation.builtin_row(~S),rows)
132# Build an App resource-style declaration for a canonical relation descriptor.
133# The World uses the relation Store wrapper and relation Notice event wrapper;
134# its write grant, access clause and observer come from that same descriptor.
135# This constructor does not execute relation commands or apply a barrier.
136# See ordinary-app-relation and relation-providers for execution and observation.
137def relation_write(~S:Data,~C:Type,~R:Type,~E:Data,~relation:RelationDecl.Declaration<S>) -> Declaration<S,RelationWorld.Store<S,C>,R,RelationWorld.Notice<S,E>,relation_ops(~S),Relation.View<S>>:
138 Declaration{Field.Declaration{RelationOps.provide_write(~S,~C,~R,~E,~Relation.descriptor(~S,relation)),[Query.Clause{relation_name(~S,relation),Query.Write{}}]},relation_observe(~S,~C,~R,~E,~relation),relation_render(~S)}
139# Schema-assembly projection: consume a relation declaration and emit entries
140# for its forward name followed by its inverse name. Entries describe schema
141# metadata; they do not create an edge, register a system or grant write access.
142def relation_entries(~S:Data,relation:RelationDecl.Declaration<S>) -> List<&2,Fragments.Entry<S>>:
143 match relation:
144 case RelationDecl.Declaration{RelationTypes.Descriptor{_,+name,+inverseName,_}}:[Fragments.Entry{Fragments.Relation{},name,name},Fragments.Entry{Fragments.Relation{},inverseName,inverseName}]