1 import Base 2 import ./entity_allocator.bend as A 3 import ./entity_key.bend as K 4 import ./world.bend as W 5 import ./relation_types.bend as T 6 import ./relation_graph.bend as Graph 7 import ./relation_reorder_core.bend as Reorder 8 import ./execution_relation_operation.bend as O 9 10 # Trusted barrier seam. Namespace and allocator must come from the same actual 11 # Administration owner; this module does not grant gameplay graph authority. 12 def live_namespace(~S:Data,same:Bool,allocator:A.Allocator,handle:W.Handle) -> A.Allocator & Bool: 13 match same: 14 case False{}:(allocator,False{}) 15 case True{}:A.checked(allocator,W.handle_key(~S,handle),1) 16 def live(~S:Data,+namespace:U32,allocator:A.Allocator,+handle:W.Handle) -> A.Allocator & Bool: 17 match handle: 18 case W.Handle{ns,key}:live_namespace(~S,U32.is_eq(namespace,ns),allocator,W.Handle{ns,key}) 19 def result(~S:Data,operation:O.Operation,checked:T.CoreResult) -> O.Outcome: 20 match checked: 21 case T.CoreResult{graph,None{}}:O.Applied{graph,operation} 22 case T.CoreResult{graph,Some{error}}:O.Refused{graph,operation,O.RelationError{error}} 23 def relate_target(~S:Data,graph:T.Graph,descriptor:T.Descriptor,+source:W.Handle,+target:W.Handle,sourceLive:Bool,checked:A.Allocator & Bool) -> A.Allocator & O.Outcome: 24 match checked: 25 case (allocator,targetLive):(allocator,result(~S,O.Relate{source,target},Graph.relate(~S,graph,descriptor,W.handle_key(~S,source),W.handle_key(~S,target),sourceLive,targetLive))) 26 def relate_source(~S:Data,+namespace:U32,graph:T.Graph,descriptor:T.Descriptor,source:W.Handle,+target:W.Handle,checked:A.Allocator & Bool) -> A.Allocator & O.Outcome: 27 match checked: 28 case (allocator,sourceLive):relate_target(~S,graph,descriptor,source,target,sourceLive,live(~S,namespace,allocator,target)) 29 def unrelate_checked(~S:Data,graph:T.Graph,descriptor:T.Descriptor,+source:W.Handle,checked:A.Allocator & Bool) -> A.Allocator & O.Outcome: 30 match checked: 31 case (allocator,False{}):(allocator,O.Refused{graph,O.Unrelate{source},O.RelationError{T.MissingEntity{W.handle_key(~S,source)}}}) 32 case (allocator,True{}):(allocator,O.Applied{Graph.unrelate(~S,graph,descriptor,W.handle_key(~S,source)),O.Unrelate{source}}) 33 def child_next(key:K.Key,reversed:List<&2,T.ChildStatus>,next:A.Allocator -> List<&2,T.ChildStatus> -> A.Allocator & List<&2,T.ChildStatus>,checked:A.Allocator & Bool) -> A.Allocator & List<&2,T.ChildStatus>: 34 match checked: 35 case (allocator,isLive):next(allocator,T.ChildStatus{key,isLive} <> reversed) 36 def children_checked(~S:Data,+namespace:U32,children:List<&2,W.Handle>,allocator:A.Allocator,reversed:List<&2,T.ChildStatus>) -> A.Allocator & List<&2,T.ChildStatus>: 37 match children: 38 case []:(allocator,List.reverse(&2,T.ChildStatus,reversed)) 39 case +child <> rest:child_next(W.handle_key(~S,child),reversed,allocator => reversed => children_checked(~S,namespace,rest,allocator,reversed),live(~S,namespace,allocator,child)) 40 def reorder_children(~S:Data,graph:T.Graph,descriptor:T.Descriptor,+parent:W.Handle,+children:List<&2,W.Handle>,parentLive:Bool,checked:A.Allocator & List<&2,T.ChildStatus>) -> A.Allocator & O.Outcome: 41 match checked: 42 case (allocator,statuses):(allocator,result(~S,O.Reorder{parent,children},Reorder.reorder(~S,graph,descriptor,W.handle_key(~S,parent),statuses,parentLive))) 43 def reorder_parent(~S:Data,namespace:U32,graph:T.Graph,descriptor:T.Descriptor,parent:W.Handle,+children:List<&2,W.Handle>,checked:A.Allocator & Bool) -> A.Allocator & O.Outcome: 44 match checked: 45 case (allocator,parentLive):reorder_children(~S,graph,descriptor,parent,children,parentLive,children_checked(~S,namespace,children,allocator,[])) 46 def reorder(~S:Data,+namespace:U32,allocator:A.Allocator,graph:T.Graph,descriptor:T.Descriptor,+parent:W.Handle,children:List<&2,W.Handle>) -> A.Allocator & O.Outcome: 47 match descriptor: 48 case T.Descriptor{key,name,inverse,T.Ordinary{}}:(allocator,O.Refused{graph,O.Reorder{parent,children},O.HierarchyRequired{}}) 49 case T.Descriptor{key,name,inverse,T.Hierarchy{}}:reorder_parent(~S,namespace,graph,T.Descriptor{key,name,inverse,T.Hierarchy{}},parent,children,live(~S,namespace,allocator,parent)) 50 # Bevy ad678262, relationship/mod.rs:28-36 makes the source relationship 51 # authoritative and maintains its target collection. Existing Bend graph/reorder 52 # algorithms implement that invariant; dispatch never accepts an inverse writer. 53 def apply(~S:Data,~descriptor:T.Descriptor,+namespace:U32,allocator:A.Allocator,graph:T.Graph,operation:O.Operation) -> A.Allocator & O.Outcome: 54 match operation: 55 case O.Relate{+source,target}:relate_source(~S,namespace,graph,descriptor,source,target,live(~S,namespace,allocator,source)) 56 case O.Unrelate{+source}:unrelate_checked(~S,graph,descriptor,source,live(~S,namespace,allocator,source)) 57 case O.Reorder{parent,children}:reorder(~S,namespace,allocator,graph,descriptor,parent,children)