1 import Base 2 import ./change_tick.bend as Tick 3 import ./clock_state.bend as Clock 4 import ./trace_facts.bend as TraceFacts 5 import ./deferred_command.bend as Deferred 6 import string_equality.bend as SE 7 import entity_key.bend as K 8 import entity_allocator.bend as A 9 10 # Framework-owned metadata. Independent factory roots are not globally unique. 11 # Schema-branded detached identity containing World namespace and full entity key 12 # (index plus generation). Extracting its index does not validate it; raw construction 13 # is trusted setup, not evidence that a handle belongs to a live entity. 14 type Handle is Data: 15 Handle{namespace: U32, key: K.Key} 16 # Affine namespace sequence for raw World creation. Keep one actual sequence for 17 # worlds that must distinguish each other; independently reset roots can collide. 18 # Application code normally uses world-io creation rather than fabricating this value. 19 type Factory is Type: 20 Factory{nextNamespace: U32} 21 # Detached registration id/name/ordered access metadata. It is not the registered 22 # runner, its affine Local/capture owner or a capability derived from a string. 23 type RegistrationMeta is Data: 24 RegistrationMeta{id: U32, name: String, access: List<&2,String>} 25 # Explicit low-level refusal reasons for entity, capacity, namespace or system-id 26 # admission. Callers must inspect their operation result rather than infer success. 27 type WorldError is Data: 28 MissingEntity{} 29 CapacityExceeded{} 30 NamespaceExhausted{} 31 SystemIdExhausted{} 32 # Affine engine storage/resource owner with allocator and administrative state. 33 # Raw field construction/destructuring is trusted framework provisioning, not the 34 # opaque gameplay interface. Schema branding alone does not validate forged fields. 35 type World is Type: 36 World{namespace: U32,allocator: A.Allocator,store: Store,resource: Resource,events: List<&2,Event>,pending:List>>,registrations: List<&2,RegistrationMeta>,nextSystemId: U32,clock: Clock.State} 37 # Raw creation returns the advanced Factory and World on success; rejection 38 # returns the actual Factory and incoming resource owner without constructing C. 39 type Creation is Type: 40 Created{factory: Factory,world: World} 41 CreateRejected{factory: Factory,resource: Resource} 42 # Reservation admission result. Reserved provides a full handle but does not 43 # activate it or populate components; rejection includes the allocator refusal. 44 type Reservation is Data: 45 Reserved{handle: Handle} 46 ReservationRejected{error: WorldError} 47 # Low-level operation decision; returned World is separate. Accepted describes 48 # that operation, not success of an entire transaction or deferred command queue. 49 type Status is Data: 50 Accepted{} 51 Rejected{error: WorldError} 52 # Metadata-registration result; id allocation is distinct from owning or running 53 # a system. Exhaustion returns RegistrationRejected without a new registration. 54 type Registration is Data: 55 Registered{id: U32} 56 RegistrationRejected{error: WorldError} 57 58 # Return administrative time without advancing it. Full epoch is required by readers. 59 def clock(~S:Data,~C:Type,~R:Type,~E:Data,world:World) -> World & Tick.Tick: 60 match world: 61 case World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,+clock}:(World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock},Clock.now(clock)) 62 63 # Observe this execution's captured tick without advancing administrative time. 64 def execution_clock(~S:Data,~C:Type,~R:Type,~E:Data,world:World) -> World & Tick.Tick: 65 match world: 66 case World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,+clock}:(World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock},Clock.current(clock)) 67 68 def clock_returned(~S:Data,~C:Type,~R:Type,~E:Data,namespace:U32,allocator:A.Allocator,store:C,resource:R,events:List<&2,E>,pending:List>>,registrations:List<&2,RegistrationMeta>,nextSystemId:U32,changed:Clock.State & Tick.Tick) -> World & Tick.Tick: 69 (clock,tick)=changed 70 (World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock},tick) 71 72 # Explicit direct/deferred time boundary; this is not system admission. 73 def advance_clock(~S:Data,~C:Type,~R:Type,~E:Data,world:World) -> World & Tick.Tick: 74 match world: 75 case World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock}:clock_returned(~S,~C,~R,~E,namespace,allocator,store,resource,events,pending,registrations,nextSystemId,Clock.advance(clock)) 76 77 # Stamp a canonical write with its captured execution tick or a new direct-edit tick. 78 def write_clock(~S:Data,~C:Type,~R:Type,~E:Data,world:World) -> World & Tick.Tick: 79 match world: 80 case World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock}:clock_returned(~S,~C,~R,~E,namespace,allocator,store,resource,events,pending,registrations,nextSystemId,Clock.write(clock)) 81 82 # Enter only after registration admission; capture one tick for all run writes. 83 def enter_run(~S:Data,~C:Type,~R:Type,~E:Data,world:World) -> World & Tick.Tick: 84 match world: 85 case World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock}:clock_returned(~S,~C,~R,~E,namespace,allocator,store,resource,events,pending,registrations,nextSystemId,Clock.enter(clock)) 86 87 # Exit an executed run on success or failure, preserving administrative progress. 88 def leave_run(~S:Data,~C:Type,~R:Type,~E:Data,world:World) -> World: 89 match world: 90 case World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock}:World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,Clock.leave(clock)} 91 92 def ensure_returned(~S:Data,~C:Type,~R:Type,~E:Data,namespace:U32,allocator:A.Allocator,store:C,resource:R,events:List<&2,E>,pending:List>>,registrations:List<&2,RegistrationMeta>,nextSystemId:U32,result:Clock.State & Bool) -> World & Bool: 93 (clock,owned)=result 94 (World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock},owned) 95 # A direct query owns a new scope; a query inside a system reuses that scope. 96 def ensure_run(~S:Data,~C:Type,~R:Type,~E:Data,world:World) -> World & Bool: 97 match world: 98 case World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock}:ensure_returned(~S,~C,~R,~E,namespace,allocator,store,resource,events,pending,registrations,nextSystemId,Clock.ensure(clock)) 99 def finish_run(~S:Data,~C:Type,~R:Type,~E:Data,owned:Bool,world:World) -> World: 100 match world: 101 case World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock}:World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,Clock.finish(owned,clock)} 102 103 # Extract only the slot index for trusted storage adapters. Generation and World 104 # namespace are omitted; this projection must not replace handle validation. 105 def handle_index(~S:Data,handle:Handle) -> U32: 106 match handle: 107 case Handle{_,key}:K.index(key) 108 # Extract the complete index/generation key, without checking namespace or liveness. 109 def handle_key(~S:Data,handle:Handle) -> K.Key: 110 match handle: 111 case Handle{_,key}:key 112 113 # Start a raw namespace sequence at one. This pure constructor is not a global 114 # uniqueness service; ordinary independently created Worlds use world-io.bend. 115 def factory() -> Factory: 116 Factory{1} 117 def create_checked(~S:Data,~C:Type,~R:Type,~E:Data,~empty:Unit -> C,available:Bool,+namespace:U32,resource:R) -> Creation: 118 match available: 119 case False{}:CreateRejected{Factory{namespace},resource} 120 case True{}:Created{Factory{(namespace + 1 : U32)},World{namespace,A.empty(),empty(Unit{}),resource,[],[],[],1,Clock.empty()}} 121 # Consume the raw Factory and resource owner to construct an empty World, advancing 122 # the namespace sequence on success. Namespace exhaustion returns both inputs via 123 # CreateRejected. Trusted empty supplies C; use world-io for application creation. 124 def create(~S:Data,~C:Type,~R:Type,~E:Data,~empty:Unit -> C,factory:Factory,resource:R) -> Creation: 125 match factory: 126 case Factory{+namespace}:create_checked(~S,~C,~R,~E,~empty,U32.is_lt(namespace,4294967295),namespace,resource) 127 def reserve_result(~S:Data,~C:Type,~R:Type,~E:Data,+namespace:U32,store:C,resource:R,+events:List<&2,E>,pending:List>>,+registrations:List<&2,RegistrationMeta>,+nextSystemId:U32,+clock:Clock.State,allocator:A.Allocator,reservation:A.Reservation) -> World & Reservation: 128 match reservation: 129 case A.Exhausted{}:(World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock},ReservationRejected{CapacityExceeded{}}) 130 case A.Reserved{key}:(World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock},Reserved{Handle{namespace,key}}) 131 def reserve_join(~S:Data,~C:Type,~R:Type,~E:Data,+namespace:U32,store:C,resource:R,+events:List<&2,E>,pending:List>>,+registrations:List<&2,RegistrationMeta>,+nextSystemId:U32,+clock:Clock.State,reserved:A.Allocator & A.Reservation) -> World & Reservation: 132 (allocator,reservation) = reserved 133 reserve_result(~S,~C,~R,~E,namespace,store,resource,events,pending,registrations,nextSystemId,clock,allocator,reservation) 134 # Reserve a full allocator key, returning World in both success and refusal. 135 # Reservation consumes allocator progress and is not yet visible as a live entity. 136 def reserve_id(~S:Data,~C:Type,~R:Type,~E:Data,world:World) -> World & Reservation: 137 match world: 138 case World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock}:reserve_join(~S,~C,~R,~E,namespace,store,resource,events,pending,registrations,nextSystemId,clock,A.reserve(allocator)) 139 def checked_join(~S:Data,~C:Type,~R:Type,~E:Data,namespace:U32,store:C,resource:R,events:List<&2,E>,pending:List>>,registrations:List<&2,RegistrationMeta>,nextSystemId:U32,clock:Clock.State,checked:A.Allocator & Bool) -> World & Bool: 140 match checked: 141 case (allocator,valid):(World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock},valid) 142 def checked_namespace(~S:Data,~C:Type,~R:Type,~E:Data,allowed:Bool,mode:U32,world:World,key:K.Key) -> World & Bool: 143 match allowed world: 144 case False{} world:(world,False{}) 145 case True{} World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock}:checked_join(~S,~C,~R,~E,namespace,store,resource,events,pending,registrations,nextSystemId,clock,A.checked(allocator,key,mode)) 146 def checked(~S:Data,~C:Type,~R:Type,~E:Data,mode:U32,world:World,handle:Handle) -> World & Bool: 147 match world handle: 148 case World{+namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock} Handle{ns,key}:checked_namespace(~S,~C,~R,~E,U32.is_eq(namespace,ns),mode,World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock},key) 149 # Trusted structural check of namespace and current allocator key metadata, without 150 # requiring a live entity. Not a gameplay substitute for valid. 151 def metadata_valid(~S:Data,~C:Type,~R:Type,~E:Data,world:World,handle:Handle) -> World & Bool: 152 checked(~S,~C,~R,~E,0,world,handle) 153 # Return World with namespace/full-generation/live validation. Foreign or stale 154 # handles fail before allocator slot access for an unmatched namespace. 155 def valid(~S:Data,~C:Type,~R:Type,~E:Data,world:World,handle:Handle) -> World & Bool: 156 checked(~S,~C,~R,~E,1,world,handle) 157 # Return World with validation of actual Pending authority for this full handle. 158 # An arbitrary reserved key does not by itself establish that pending authority. 159 def pending_valid(~S:Data,~C:Type,~R:Type,~E:Data,world:World,handle:Handle) -> World & Bool: 160 checked(~S,~C,~R,~E,2,world,handle) 161 def phase_checked(~S:Data,~C:Type,~R:Type,~E:Data,phase:A.Phase,key:K.Key,checked:World & Bool) -> World & Status: 162 match checked: 163 case (world,False{}):(world,Rejected{MissingEntity{}}) 164 case (World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock},True{}):(World{namespace,A.write_phase(allocator,key,phase),store,resource,events,pending,registrations,nextSystemId,clock},Accepted{}) 165 # Trusted lifecycle phase change after metadata validation; returns World and 166 # Status. This does not construct components or execute a pending populate closure. 167 def activate(~S:Data,~C:Type,~R:Type,~E:Data,world:World,+handle:Handle) -> World & Status: 168 phase_checked(~S,~C,~R,~E,A.Live{},handle_key(~S,handle),metadata_valid(~S,~C,~R,~E,world,handle)) 169 # Opaque storage is retained; this operation cannot make its slot reusable. 170 # Mark a metadata-valid entity DeadRetained, returning Status and World. Payloads 171 # remain in storage; schema cleanup must precede slot release/reuse. 172 def deactivate(~S:Data,~C:Type,~R:Type,~E:Data,world:World,+handle:Handle) -> World & Status: 173 phase_checked(~S,~C,~R,~E,A.DeadRetained{},handle_key(~S,handle),metadata_valid(~S,~C,~R,~E,world,handle)) 174 def discard_status(~S:Data,~C:Type,~R:Type,~E:Data,observed:World & Status) -> World: 175 match observed: 176 case (world,_):world 177 # Structural bookkeeping for an actually staged spawn. Metadata validation gates 178 # the phase update; this helper alone does not enqueue or populate an entity. 179 def mark_pending(~S:Data,~C:Type,~R:Type,~E:Data,world:World,+handle:Handle) -> World: 180 discard_status(~S,~C,~R,~E,phase_checked(~S,~C,~R,~E,A.Pending{},handle_key(~S,handle),metadata_valid(~S,~C,~R,~E,world,handle))) 181 def owner_change(~S:Data,~C:Type,~R:Type,~E:Data,release:Bool,+key:K.Key,checked:World & Bool) -> World: 182 match release checked: 183 case _, (world,False{}):world 184 case False{}, (World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock},True{}):World{namespace,A.abandon(allocator,key),store,resource,events,pending,registrations,nextSystemId,clock} 185 case True{}, (World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock},True{}):World{namespace,A.release(allocator,key),store,resource,events,pending,registrations,nextSystemId,clock} 186 # Abandon actual pending authority without rewinding reserved allocator progress. 187 # Used by spawn rollback; does not pretend a reserved id was never consumed. 188 def clear_pending(~S:Data,~C:Type,~R:Type,~E:Data,world:World,+handle:Handle) -> World: 189 owner_change(~S,~C,~R,~E,False{},handle_key(~S,handle),pending_valid(~S,~C,~R,~E,world,handle)) 190 # Only schema-owned cleanup calls this after all payloads and stamps are cleared. 191 # Trusted cleanup boundary: release only after schema-owned payload/stamp clearing. 192 # Metadata validation is not proof that arbitrary caller-supplied storage is empty. 193 def release_cleared(~S:Data,~C:Type,~R:Type,~E:Data,world:World,+handle:Handle) -> World: 194 owner_change(~S,~C,~R,~E,True{},handle_key(~S,handle),metadata_valid(~S,~C,~R,~E,world,handle)) 195 def command_live(~S:Data,~C:Type,~R:Type,~E:Data,handle:Handle,checked:World & Bool) -> World & Bool: 196 match checked: 197 case (world,True{}):(world,True{}) 198 case (world,False{}):pending_valid(~S,~C,~R,~E,world,handle) 199 # Allow a live or actual Pending handle, preserving namespace/generation checks. 200 # This permits ordered deferred spawn/despawn workflows without making Pending 201 # entities readable through ordinary live-component access. 202 def command_valid(~S:Data,~C:Type,~R:Type,~E:Data,world:World,+handle:Handle) -> World & Bool: 203 command_live(~S,~C,~R,~E,handle,valid(~S,~C,~R,~E,world,handle)) 204 205 # Transfer one affine command to the reverse pending accumulator. It is not run 206 # until a barrier; arbitrary command bodies are trusted engine adapters. 207 def enqueue_command(~S:Data,~C:Type,~R:Type,~E:Data,world:World,command:Deferred.Command>) -> World: 208 match world: 209 case World{+namespace,allocator,store,resource,+events,pending,+registrations,+nextSystemId,+clock}:World{namespace,allocator,store,resource,events,command <> pending,registrations,nextSystemId,clock} 210 # Wrap a raw World-to-World closure as a deferred command. No immediate effect 211 # or automatic transaction inverse is supplied for the callback. 212 def enqueue(~S:Data,~C:Type,~R:Type,~E:Data,world:World,command:World -> World) -> World: 213 enqueue_command(~S,~C,~R,~E,world,Deferred.Raw{command}) 214 def drain_fifo(~S:Data,~C:Type,~R:Type,~E:Data,commands:List>>,world:World) -> World: 215 match commands: 216 case []:world 217 case command <> rest:Deferred.run_disabled(~World,command,drain_fifo(~S,~C,~R,~E,rest,world)) 218 def drain_apply(~S:Data,~C:Type,~R:Type,~E:Data,command:Deferred.Command>,result:World & TraceFacts.State) -> World & TraceFacts.State: 219 match result: 220 case (world,trace):Deferred.run(~World,command,world,trace) 221 def drain_fifo_traced(~S:Data,~C:Type,~R:Type,~E:Data,commands:List>>,world:World,trace:TraceFacts.State) -> World & TraceFacts.State: 222 match commands: 223 case []:(world,trace) 224 case command <> rest: 225 drain_apply(~S,~C,~R,~E,command,drain_fifo_traced(~S,~C,~R,~E,rest,world,trace)) 226 # Detach the current pending batch, execute it in FIFO enqueue order, and return 227 # World plus operation trace state. Commands enqueued during that drain remain 228 # pending for a later barrier; arbitrary callback effects are not transactional. 229 def barrier_completed(~S:Data,~C:Type,~R:Type,~E:Data,result:World & TraceFacts.State) -> World & TraceFacts.State: 230 (world,trace)=result 231 (leave_run(~S,~C,~R,~E,world),trace) 232 def barrier_entered(~S:Data,~C:Type,~R:Type,~E:Data,trace:TraceFacts.State,entered:World & Tick.Tick) -> World & TraceFacts.State: 233 match entered: 234 case (World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock},_):barrier_completed(~S,~C,~R,~E,drain_fifo_traced(~S,~C,~R,~E,pending,World{namespace,allocator,store,resource,events,[],registrations,nextSystemId,clock},trace)) 235 # Explicit deferred-application boundary; all commands in this batch share its tick. 236 def barrier_traced(~S:Data,~C:Type,~R:Type,~E:Data,world:World,trace:TraceFacts.State) -> World & TraceFacts.State: 237 barrier_entered(~S,~C,~R,~E,trace,enter_run(~S,~C,~R,~E,world)) 238 # Apply the current pending command batch in FIFO order with tracing disabled. 239 # Returns World; it neither invents a transaction rollback nor recursively drains 240 # new work queued by those commands. See commands.bend for lifecycle adapters. 241 def barrier(~S:Data,~C:Type,~R:Type,~E:Data,world:World) -> World: 242 Deferred.world_only(~World,barrier_traced(~S,~C,~R,~E,world,TraceFacts.Off{})) 243 244 # Immediate whole-resource swap returning the displaced actual R owner. This raw 245 # administrative operation supplies neither projection restrictions nor undo. 246 def replace_resource(~S: Data,~C: Type,~R: Type,~E: Data,world: World,replacement: R) -> World & R: 247 match world: 248 case World{+namespace,allocator,store,resource,+events,pending,+registrations,+nextSystemId,+clock}: (World{namespace,allocator,store,replacement,events,pending,registrations,nextSystemId,clock},resource) 249 250 def event_append_loop(~E: Data,reversed: List<&2,E>,+output: List<&2,E>) -> List<&2,E>: 251 match reversed: 252 case []: output 253 case head <> rest: event_append_loop(~E,rest,head <> output) 254 255 def event_append(~E: Data,+left: List<&2,E>,+right: List<&2,E>) -> List<&2,E>: 256 event_append_loop(~E,List.reverse(&2,E,left),right) 257 258 def event_publish_nonempty(~S: Data,~C: Type,~R: Type,~E: Data,world: World,+published: List<&2,E>) -> World: 259 match world: 260 case World{+namespace,allocator,store,resource,+events,pending,+registrations,+nextSystemId,+clock}: World{namespace,allocator,store,resource,event_append(~E,events,published),pending,registrations,nextSystemId,clock} 261 262 # An empty publication changes no field and needs no traversal of retained events. 263 # Append detached Data events in list order and return World. Empty input preserves 264 # World. This does not synchronize typed event Runtime batches/readers or run systems. 265 def event_publish(~S: Data,~C: Type,~R: Type,~E: Data,world: World,+published: List<&2,E>) -> World: 266 match published: 267 case []: world 268 case head <> rest: event_publish_nonempty(~S,~C,~R,~E,world,head <> rest) 269 270 # Return World and its copied Data event list without consuming or acknowledging 271 # reader positions. Affine Type event logs use their separate resource ownership. 272 def events_view(~S: Data,~C: Type,~R: Type,~E: Data,world: World) -> World & List<&2,E>: 273 match world: 274 case World{+namespace,allocator,store,resource,+events,pending,+registrations,+nextSystemId,+clock}: (World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock},events) 275 276 def observe_resource_finish(~S: Data,~C: Type,~R: Type,~E: Data,~V: Type,observed: R & V,+namespace: U32,allocator: A.Allocator,store: C,+events: List<&2,E>,pending:List>>,+registrations: List<&2,RegistrationMeta>,+nextSystemId: U32,+clock: Clock.State) -> World & V: 277 (resource,value) = observed 278 (World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock},value) 279 280 # Trusted resource-owner adapter: project returns the actual R with an Out owner 281 # or value, then World is rebuilt. The signature does not prove projection purity 282 # or allow duplicating affine resource contents. 283 def observe_resource(~S: Data,~C: Type,~R: Type,~E: Data,~V: Type,~project: R -> R & V,world: World) -> World & V: 284 match world: 285 case World{+namespace,allocator,store,resource,+events,pending,+registrations,+nextSystemId,+clock}: observe_resource_finish(~S,~C,~R,~E,~V,project(resource),namespace,allocator,store,events,pending,registrations,nextSystemId,clock) 286 287 def register_checked(~S: Data,~C: Type,~R: Type,~E: Data,available: Bool,world: World,+name: String,+access: List<&2,String>) -> World & Registration: 288 match available world: 289 case False{} world: (world,RegistrationRejected{SystemIdExhausted{}}) 290 case True{} World{+namespace,allocator,store,resource,+events,pending,+registrations,+nextSystemId,+clock}: (World{namespace,allocator,store,resource,events,pending,RegistrationMeta{nextSystemId,name,access} <> registrations,(nextSystemId + 1 : U32),clock},Registered{nextSystemId}) 291 292 # Allocate a system metadata id/name/access entry, returning World and Registration. 293 # System-id exhaustion preserves World. Metadata alone does not install a runner 294 # or validate a gameplay body; ordinary registered-system setup performs that join. 295 def register(~S: Data,~C: Type,~R: Type,~E: Data,world: World,+name: String,+access: List<&2,String>) -> World & Registration: 296 match world: 297 case World{+namespace,allocator,store,resource,+events,pending,+registrations,+nextSystemId,+clock}: register_checked(~S,~C,~R,~E,U32.is_lt(nextSystemId,4294967295),World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock},name,access) 298 299 # Exact ordered declaration comparison; no normalization grants capabilities. 300 def access_equal(xs: List<&2,String>,ys: List<&2,String>) -> Bool: 301 match xs ys: 302 case Nil{} Nil{}: True{} 303 case Nil{} Con{_,_}: False{} 304 case Con{_,_} Nil{}: False{} 305 case Con{x,xs} Con{y,ys}: Bool.and(SE.equal(x,y),access_equal(xs,ys)) 306 307 def matching_access(sameName: Bool,metaAccess: List<&2,String>,wantedAccess: List<&2,String>) -> Bool: 308 match sameName: 309 case False{}: False{} 310 case True{}: access_equal(metaAccess,wantedAccess) 311 312 def matching_id(sameId: Bool,metaName: String,wantedName: String,metaAccess: List<&2,String>,wantedAccess: List<&2,String>) -> Bool: 313 match sameId: 314 case False{}: False{} 315 case True{}: matching_access(SE.equal(metaName,wantedName),metaAccess,wantedAccess) 316 317 def registration_meta_matches(meta: RegistrationMeta,+id: U32,+name: String,+access: List<&2,String>) -> Bool: 318 match meta: 319 case RegistrationMeta{mid,mname,maccess}: matching_id(U32.is_eq(mid,id),mname,name,maccess,access) 320 321 def registration_list_walk(registrations: List<&2,RegistrationMeta>,+id: U32,+name: String,+access: List<&2,String>,found: Bool) -> Bool: 322 match registrations found: 323 case _ True{}: True{} 324 case [] False{}: False{} 325 case meta <> rest False{}: registration_list_walk(rest,id,name,access,registration_meta_matches(meta,id,name,access)) 326 327 def registration_list_matches(registrations: List<&2,RegistrationMeta>,+id: U32,+name: String,+access: List<&2,String>) -> Bool: 328 registration_list_walk(registrations,id,name,access,False{}) 329 330 331 # Return World and its namespace for engine admission checks, not global provenance. 332 def namespace(~S: Data,~C: Type,~R: Type,~E: Data,world: World) -> World & U32: 333 match world: 334 case World{+namespace,allocator,store,resource,+events,pending,+registrations,+nextSystemId,+clock}: (World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock},namespace) 335 336 # Check retained id, name and exact ordered access strings while returning World. 337 # No sorting/normalization creates extra authority or verifies arbitrary callbacks. 338 def registration_matches(~S: Data,~C: Type,~R: Type,~E: Data,world: World,+id: U32,+name: String,+access: List<&2,String>) -> World & Bool: 339 match world: 340 case World{+namespace,allocator,store,resource,+events,pending,+registrations,+nextSystemId,+clock}: (World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock},registration_list_matches(registrations,id,name,access)) 341 342 def with_store_finish(~S: Data,~C: Type,~R: Type,~E: Data,~Out: Type,observed: C & Out,+namespace: U32,allocator: A.Allocator,resource: R,+events: List<&2,E>,pending:List>>,+registrations: List<&2,RegistrationMeta>,+nextSystemId: U32,+clock: Clock.State) -> World & Out: 343 (store,value) = observed 344 (World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock},value) 345 346 # Trusted storage adapter threading actual C and returning Out with World. This is 347 # not a gameplay capability or a universal guarantee that effect preserves storage. 348 def with_store(~S: Data,~C: Type,~R: Type,~E: Data,~Out: Type,effect: C -> C & Out,world: World) -> World & Out: 349 match world: 350 case World{+namespace,allocator,store,resource,+events,pending,+registrations,+nextSystemId,+clock}: with_store_finish(~S,~C,~R,~E,~Out,effect(store),namespace,allocator,resource,events,pending,registrations,nextSystemId,clock) 351 352 def pending_prepend(~S: Data,~C: Type,~R: Type,~E: Data,command: World -> World,counted: List<(World -> World)> & U32) -> List<(World -> World)> & U32: 353 (commands,count) = counted 354 (command <> commands,(count + 1 : U32)) 355 356 def pending_length_acc(~S: Data,~C: Type,~R: Type,~E: Data,commands:List>>,reversed: List>>,count: U32) -> List>> & U32: 357 match commands: 358 case []: (List.reverse(&1,Deferred.Command>,reversed),count) 359 case command <> rest: pending_length_acc(~S,~C,~R,~E,rest,command <> reversed,(count + 1 : U32)) 360 361 def pending_length(~S: Data,~C: Type,~R: Type,~E: Data,commands:List>>) -> List>> & U32: 362 pending_length_acc(~S,~C,~R,~E,commands,[],0) 363 364 def pending_count_join(~S: Data,~C: Type,~R: Type,~E: Data,+namespace: U32,allocator: A.Allocator,store: C,resource: R,+events: List<&2,E>,+registrations: List<&2,RegistrationMeta>,+nextSystemId: U32,+clock: Clock.State,counted: List>> & U32) -> World & U32: 365 (pending,count) = counted 366 (World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock},count) 367 368 # Count pending affine command closures without executing them, returning World 369 # with the original command order and owners retained. 370 def pending_count(~S: Data,~C: Type,~R: Type,~E: Data,world: World) -> World & U32: 371 match world: 372 case World{+namespace,allocator,store,resource,+events,pending,+registrations,+nextSystemId,+clock}: pending_count_join(~S,~C,~R,~E,namespace,allocator,store,resource,events,registrations,nextSystemId,clock,pending_length(~S,~C,~R,~E,pending)) 373 374 # Event runtime retention replaces only its owned event domain. 375 # Administrative replacement of the Data event domain only. It does not execute 376 # pending work, rebuild registrations or reset external event reader owners. 377 def events_replace(~S: Data,~C: Type,~R: Type,~E: Data,world: World,+retained: List<&2,E>) -> World: 378 match world: 379 case World{+namespace,allocator,store,resource,_,pending,+registrations,+nextSystemId,+clock}: World{namespace,allocator,store,resource,retained,pending,registrations,nextSystemId,clock} 380 381 def key_handles(~S:Data,+namespace:U32,keys:List<&2,K.Key>) -> List<&2,Handle>: 382 match keys: 383 case []:[] 384 case key <> rest:Handle{namespace,key} <> key_handles(~S,namespace,rest) 385 def handles_join(~S:Data,~C:Type,~R:Type,~E:Data,+namespace:U32,store:C,resource:R,events:List<&2,E>,pending:List>>,registrations:List<&2,RegistrationMeta>,nextSystemId:U32,clock:Clock.State,observed:A.Allocator & List<&2,K.Key>) -> World & List<&2,Handle>: 386 match observed: 387 case (allocator,keys):(World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock},key_handles(~S,namespace,keys)) 388 # Return World and currently visible live full handles in allocator-visible order. 389 # Reserved/Pending handles are not an ordinary query membership list yet. 390 def handles(~S:Data,~C:Type,~R:Type,~E:Data,world:World) -> World & List<&2,Handle>: 391 match world: 392 case World{namespace,allocator,store,resource,events,pending,registrations,nextSystemId,clock}:handles_join(~S,~C,~R,~E,namespace,store,resource,events,pending,registrations,nextSystemId,clock,A.visible(allocator))