owned_event_family_storage.bend

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

1import Base
2import bendvy-ecs-core@0.1.0.1/world.bend as W
3import bendvy-ecs-core@0.1.0.1/world_resource_owner.bend as Resource
4import bendvy-ecs-core@0.1.0.1/owner_product.bend as Product
5import bendvy-ecs-core@0.1.0.1/capabilities.bend as Cap
6import bendvy-ecs-core@0.1.0.1/owned_event_log.bend as Log
7
8# Trusted engine helpers. Ordinary product declarations bind the canonical log
9# path and matching key route; gameplay receives only its abstract capability.
10# R is the entire heterogeneous resource tree, E the existing Data publication
11# tree. No Type payload or unrelated resource owner is copied or reconstructed.
12def log_returned(~S:Data,~C:Type,~R:Type,~P:Type,~Rest:Type,~E:Data,~path:Product.Lens<R,Log.Log<P>,Rest>,~Out:Type,worldRest:Resource.Rest<S,C,R,E>,resourceRest:Rest,result:Log.Log<P> & Out) -> W.World<S,C,R,E> & Out:
13  match result:
14    case (log,output):(Resource.put(~S,~C,~R,~E,worldRest,Product.put_field(~R,~Log.Log<P>,~Rest,path)(resourceRest,log)),output)
15def log_taken(~S:Data,~C:Type,~R:Type,~P:Type,~Rest:Type,~E:Data,~path:Product.Lens<R,Log.Log<P>,Rest>,~Out:Type,effect:Log.Log<P> -> Log.Log<P> & Out,worldRest:Resource.Rest<S,C,R,E>,result:Rest & Log.Log<P>) -> W.World<S,C,R,E> & Out:
16  match result:
17    case (resourceRest,log):log_returned(~S,~C,~R,~P,~Rest,~E,~path,~Out,worldRest,resourceRest,effect(log))
18def resource_taken(~S:Data,~C:Type,~R:Type,~P:Type,~Rest:Type,~E:Data,~path:Product.Lens<R,Log.Log<P>,Rest>,~Out:Type,effect:Log.Log<P> -> Log.Log<P> & Out,result:Resource.Rest<S,C,R,E> & R) -> W.World<S,C,R,E> & Out:
19  match result:
20    case (worldRest,resource):log_taken(~S,~C,~R,~P,~Rest,~E,~path,~Out,effect,worldRest,Product.get_field(~R,~Log.Log<P>,~Rest,path)(resource))
21def with_log(~S:Data,~C:Type,~R:Type,~P:Type,~Rest:Type,~E:Data,~path:Product.Lens<R,Log.Log<P>,Rest>,~Out:Type,effect:Log.Log<P> -> Log.Log<P> & Out,world:W.World<S,C,R,E>) -> W.World<S,C,R,E> & Out:
22  resource_taken(~S,~C,~R,~P,~Rest,~E,~path,~Out,effect,Resource.take(~S,~C,~R,~E,world))
23
24def injected(~E:Data,~inject:Nat -> E,ids:List<&2,Nat>) -> List<&2,E>:
25  match ids:
26    case []:[]
27    case id <> rest:inject(id) <> injected(~E,~inject,rest)
28def published(~S:Data,~C:Type,~R:Type,~E:Data,~inject:Nat -> E,result:W.World<S,C,R,E> & List<&2,Nat>) -> W.World<S,C,R,E>:
29  match result:
30    case (world,ids):W.event_publish(~S,~C,~R,~E,world,injected(~E,~inject,ids))
31# The transaction adapter calls this after successful canonical ECS finish. One
32# caller batch retains its FIFO; cross-family action order belongs to that adapter,
33# using the existing publication journal, not a regrouping by payload type/family.
34def commit_owned(~S:Data,~C:Type,~R:Type,~P:Type,~Rest:Type,~E:Data,~path:Product.Lens<R,Log.Log<P>,Rest>,~inject:Nat -> E,world:W.World<S,C,R,E>,values:List<P>) -> W.World<S,C,R,E>:
35  published(~S,~C,~R,~E,~inject,with_log(~S,~C,~R,~P,~Rest,~E,~path,~List<&2,Nat>,log => Log.append_many(~P,log,values),world))
36# The runtime chooses surviving records using its unchanged per-family retention
37# policy, then calls each family's selected path with those records.
38def retain(~S:Data,~C:Type,~R:Type,~P:Type,~Rest:Type,~E:Data,~path:Product.Lens<R,Log.Log<P>,Rest>,~select:List<&2,E> -> List<&2,Nat>,world:W.World<S,C,R,E>,records:List<&2,E>) -> W.World<S,C,R,E> & List<Log.Row<P>>:
39  with_log(~S,~C,~R,~P,~Rest,~E,~path,~List<Log.Row<P>>,log => Log.retain(~P,log,select(records)),world)
40# Drain only this log, preserving its next ID and every publication. The outer
41# shutdown drains ALL family logs and clears their publication tree atomically
42# before any reader runs. Clearing shared records here would lose sibling events.
43def drain(~S:Data,~C:Type,~R:Type,~P:Type,~Rest:Type,~E:Data,~path:Product.Lens<R,Log.Log<P>,Rest>,world:W.World<S,C,R,E>) -> W.World<S,C,R,E> & List<Log.Row<P>>:
44  with_log(~S,~C,~R,~P,~Rest,~E,~path,~List<Log.Row<P>>,Log.drain(~P),world)
45# Read only the log at the declaration's path. IDs are local to that family; the
46# ordinary adapter first projects the reader's IDs through the matching key route.
47# Trusted at preserves its owner; the abstract body cannot extract that owner.
48def read(~S:Data,~C:Type,~R:Type,~P:Type,~Rest:Type,~E:Data,~path:Product.Lens<R,Log.Log<P>,Rest>,~Request:Type,~Projection:Data,~Args:Type,~Observation:Type,~at:P -> Request -> P & Projection,~body:@-H:Type -> @-read:Cap.Request<H,Request,Projection> -> H -> Args -> H & Observation,world:W.World<S,C,R,E>,id:Nat,args:Args) -> W.World<S,C,R,E> & Log.ReadResult<Args,Observation>:
49  with_log(~S,~C,~R,~P,~Rest,~E,~path,~Log.ReadResult<Args,Observation>,log => Log.read(~P,~Request,~Projection,~Args,~Observation,~at,~body,log,id,args),world)