ordinary_resource_system.bend

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

1import Base
2import bendvy-ecs-core@0.1.0.1/trace_facts.bend as TraceFacts
3import bendvy-ecs-core@0.1.0.1/ordinary_schema.bend as Schema
4import bendvy-ecs-core@0.1.0.1/ordinary_query_declaration.bend as Query
5import bendvy-ecs-core@0.1.0.1/world.bend as W
6import bendvy-ecs-core@0.1.0.1/system.bend as Sys
7import bendvy-ecs-core@0.1.0.1/resource.bend as Res
8import bendvy-ecs-core@0.1.0.1/transaction.bend as T
9import bendvy-ecs-core@0.1.0.1/commands.bend as Cmd
10import bendvy-ecs-core@0.1.0.1/capabilities.bend as Cap
11# Static declaration: one ordinary identity supplies operational grant and metadata.
12# Current resource operations replace the entire Resources owner, not one field.
13# Retained whole-resource identity, access mode and operational grant. R may be
14# affine Type; this declaration does not narrow replacement to a selected field.
15# Raw declaration/adapters remain trusted, rather than authority created by strings.
16type Declaration<-S:Data,-R:Type,-H:Type,-Ops:Type> is Type:
17  Declaration{identity:Schema.Resource<S,R>,kind:Query.Mode,grant:Ops}
18# Build whole-resource read declaration exposing detached V through an owner-
19# returning projector. This supplies no setter and does not copy the actual R.
20def read(~S:Data,~C:Type,~R:Type,~E:Data,~V:Data,~project:R -> R & V,identity:Schema.Resource<S,R>) -> Declaration<S,R,T.Tx<W.World<S,C,R,E>,E>,Cap.ValueRead<T.Tx<W.World<S,C,R,E>,E>,V>>:
21  Declaration{identity,Query.Read{},Cap.ValueRead{Res.tx_get(~S,~C,~R,~E,~V,~project)}}
22# Build whole-R read/replacement declaration. Setter consumes incoming R and
23# journals displaced R for ordinary rollback; it returns no recovery receipt.
24def write(~S:Data,~C:Type,~R:Type,~E:Data,~V:Data,~project:R -> R & V,identity:Schema.Resource<S,R>) -> Declaration<S,R,T.Tx<W.World<S,C,R,E>,E>,Cap.ValueWrite<T.Tx<W.World<S,C,R,E>,E>,R,V>>:
25  Declaration{identity,Query.Write{},Cap.ValueWrite{Res.tx_get(~S,~C,~R,~E,~V,~project),Res.tx_replace(~S,~C,~R,~E)}}
26# Advanced declaration projection of operational caps; does not invoke them.
27def grant(~S:Data,~R:Type,~H:Type,~Ops:Type,declaration:Declaration<S,R,H,Ops>) -> Ops:
28  match declaration:
29    case Declaration{_,_,grant}:grant
30# Derive the resource key/mode clause from the same retained declaration.
31def clause(~S:Data,~R:Type,~H:Type,~Ops:Type,declaration:Declaration<S,R,H,Ops>) -> Query.Clause<S>:
32  match declaration:
33    case Declaration{identity,kind,_}:Query.Clause{Schema.resource_key(~S,~R,identity),kind}
34# Project the declared read/write mode without inspecting resource storage.
35def mode(~S:Data,~R:Type,~H:Type,~Ops:Type,declaration:Declaration<S,R,H,Ops>) -> Query.Mode:
36  match declaration:
37    case Declaration{_,kind,_}:kind
38# Description allocation is explicit observation work, not registration work.
39# Presentation adapter expanding access names into same-mode detached clauses.
40# Does not validate grants, allocate a registry or invoke a resource operation.
41def descriptions(~S:Data,+kind:Query.Mode,names:List<&2,String>) -> List<&2,Query.Clause<S>>:
42  match names:
43    case []:[]
44    case name <> rest:Query.Clause{name,kind} <> descriptions(~S,kind,rest)
45# Project the singleton operational resource name used for registration metadata.
46def access(~S:Data,value:Query.Clause<S>) -> List<&2,String>:
47  match value:
48    case Query.Clause{name,_}:[name]
49def returned(~S:Data,~C:Type,~R:Type,~E:Data,~Error:Data,~Out:Type,output:Out,result:T.Returned<W.World<S,C,R,E>,Error>) -> Sys.Outcome<W.World<S,C,R,E>,Error,Out>:
50  match result:
51    case T.Returned{world,T.Success{}}:Sys.Succeeded{world,output}
52    case T.Returned{world,T.Failure{error}}:Sys.Failed{world,error}
53def finished(~S:Data,~C:Type,~R:Type,~E:Data,~Error:Data,~Out:Type,result:T.Tx<W.World<S,C,R,E>,E> & (T.Outcome<Error> & Out)) -> Sys.Outcome<W.World<S,C,R,E>,Error,Out>:
54  match result:
55    case (tx,(outcome,output)):returned(~S,~C,~R,~E,~Error,~Out,output,Cmd.tx_finish(~S,~C,~R,~E,~Error,tx,outcome))
56# Invoke the opaque-owner body in one fresh ECS transaction with declaration caps.
57# Args and Out may own Type payloads. Success returns Out; failure rolls back
58# recorded ECS edits and discards Out. Deferred commands require a later barrier;
59# ordinary rollback is not owned recovery or reversal of external callback effects.
60def runner(~S:Data,~C:Type,~R:Type,~E:Data,~Ops:Type -> Type,~Args:Type,~Error:Data,~Out:Type,~declaration:Declaration<S,R,T.Tx<W.World<S,C,R,E>,E>,Ops(T.Tx<W.World<S,C,R,E>,E>)>,~body:@-H:Type -> @-caps:Ops(H) -> Args -> H -> H & (T.Outcome<Error> & Out),world:W.World<S,C,R,E>,args:Args) -> Sys.Outcome<W.World<S,C,R,E>,Error,Out>:
61  finished(~S,~C,~R,~E,~Error,~Out,Cap.invoke_owned(~Ops,~Args,~(T.Outcome<Error> & Out),~body,~T.Tx<W.World<S,C,R,E>,E>,~grant(~S,~R,~T.Tx<W.World<S,C,R,E>,E>,~Ops(T.Tx<W.World<S,C,R,E>,E>),declaration),args,T.begin(~W.World<S,C,R,E>,~E,world)))
62# Affine registry owner plus presentation slot, indexed by declared access mode.
63# Resource payload remains in World, not copied into this registration metadata.
64type Owner<-S:Data,-Registry:Type,-kind:Query.Mode> is Type:
65  Owner{registry:Registry,slot:String}
66# Registration result returning World in both branches; Defined retains registry
67# in Owner and Rejected has no newly allocated runner owner.
68type Defined<-S:Data,-World:Type,-Registry:Type,-kind:Query.Mode> is Type:
69  Defined{world:World,owner:Owner<S,Registry,kind>}
70  Rejected{world:World}
71def registered(~S:Data,~C:Type,~R:Type,~E:Data,~Args:Type,~Error:Data,~Out:Type,~kind:Query.Mode,~run:W.World<S,C,R,E> -> Args -> Sys.Outcome<W.World<S,C,R,E>,Error,Out>,slot:String,result:Sys.RegistrationResult<S,C,R,E,Args,Error,Out,run>) -> Defined<S,W.World<S,C,R,E>,Sys.Registry<S,C,R,E,Args,Error,Out,run>,kind>:
72  match result:
73    case Sys.RegistrationFailed{world}:Rejected{world}
74    case Sys.Registered{world,registry}:Defined{world,Owner{registry,slot}}
75# Register the declaration-bound runner with its derived access. slot is retained
76# for presentation and does not change operational resource authority. No body runs
77# at registration. See the named-app matched-feature fixture under test-fixtures.
78def define(~S:Data,~C:Type,~R:Type,~E:Data,~Ops:Type -> Type,~Args:Type,~Error:Data,~Out:Type,~declaration:Declaration<S,R,T.Tx<W.World<S,C,R,E>,E>,Ops(T.Tx<W.World<S,C,R,E>,E>)>,~body:@-H:Type -> @-caps:Ops(H) -> Args -> H -> H & (T.Outcome<Error> & Out),world:W.World<S,C,R,E>,name:String,slot:String) -> Defined<S,W.World<S,C,R,E>,Sys.Registry<S,C,R,E,Args,Error,Out,runner(~S,~C,~R,~E,~Ops,~Args,~Error,~Out,~declaration,~body)>,mode(~S,~R,~T.Tx<W.World<S,C,R,E>,E>,~Ops(T.Tx<W.World<S,C,R,E>,E>),declaration)>:
79  registered(~S,~C,~R,~E,~Args,~Error,~Out,~mode(~S,~R,~T.Tx<W.World<S,C,R,E>,E>,~Ops(T.Tx<W.World<S,C,R,E>,E>),declaration),~runner(~S,~C,~R,~E,~Ops,~Args,~Error,~Out,~declaration,~body),slot,Sys.register(~S,~C,~R,~E,~Args,~Error,~Out,~runner(~S,~C,~R,~E,~Ops,~Args,~Error,~Out,~declaration,~body),world,name,access(~S,clause(~S,~R,~T.Tx<W.World<S,C,R,E>,E>,~Ops(T.Tx<W.World<S,C,R,E>,E>),declaration))))
80# Registry's existing namespace and registration checks remain authoritative.
81# Run tracked registration, returning its full success/refusal result plus slot.
82# Refusal retains actual registry, World and Args under Sys.RunResult; successful
83# execution returns callback Out, while callback failure does not return Out.
84def run(~S:Data,~C:Type,~R:Type,~E:Data,~Args:Type,~Error:Data,~Out:Type,~kind:Query.Mode,~runner:W.World<S,C,R,E> -> Args -> Sys.Outcome<W.World<S,C,R,E>,Error,Out>,owner:Owner<S,Sys.Registry<S,C,R,E,Args,Error,Out,runner>,kind>,world:W.World<S,C,R,E>,args:Args) -> Sys.RunResult<S,C,R,E,Args,Error,Out,runner> & String:
85  match owner:
86    case Owner{registry,slot}:(Sys.run(~S,~C,~R,~E,~Args,~Error,~Out,~runner,registry,world,args),slot)
87
88# Called by an enabled debug bridge; actual Registry is borrowed and reconstructed.
89# Enabled-observation adapter returning actual Owner and detached access clauses.
90# Does not inspect resource payloads or grant access from the presentation slot.
91def describe(~S:Data,~C:Type,~R:Type,~E:Data,~Args:Type,~Error:Data,~Out:Type,~kind:Query.Mode,~runner:W.World<S,C,R,E> -> Args -> Sys.Outcome<W.World<S,C,R,E>,Error,Out>,owner:Owner<S,Sys.Registry<S,C,R,E,Args,Error,Out,runner>,kind>) -> Owner<S,Sys.Registry<S,C,R,E,Args,Error,Out,runner>,kind> & List<&2,Query.Clause<S>>:
92  match owner:
93    case Owner{Sys.Registry{namespace,id,name,+access,cursor},slot}:
94      (Owner{Sys.Registry{namespace,id,name,access,cursor},slot},descriptions(~S,kind,access))
95
96def returned_observed(~S:Data,~C:Type,~R:Type,~E:Data,~Error:Data,~Out:Type,output:Out,result:T.Returned<W.World<S,C,R,E>,Error> & TraceFacts.State) -> Sys.Outcome<W.World<S,C,R,E>,Error,Out> & TraceFacts.State:
97  match result:
98    case (value,trace):(returned(~S,~C,~R,~E,~Error,~Out,output,value),trace)
99# Same user body and grants, with detached transaction facts returned beside it.
100# Advanced runner finish adapter retaining detached transaction facts separately
101# from World outcome. Same commit/rollback and failure-Out disposal as runner;
102# attempted facts are not evidence that failed transaction writes committed.
103def finished_observed(~S:Data,~C:Type,~R:Type,~E:Data,~Error:Data,~Out:Type,result:T.Tx<W.World<S,C,R,E>,E> & (T.Outcome<Error> & Out)) -> Sys.Outcome<W.World<S,C,R,E>,Error,Out> & TraceFacts.State:
104  match result:
105    case (tx,(outcome,output)):returned_observed(~S,~C,~R,~E,~Error,~Out,output,T.finish_observed(~W.World<S,C,R,E>,~E,~Error,~Cmd.enqueue(~S,~C,~R,~E),~Cmd.publish(~S,~C,~R,~E),tx,outcome))