relation_reorder_core.bend
bendvy-ecs-core@0.1.0.0 · 61 lines · 0 definitions
1import Base
2import entity_key.bend as K
3import relation_types.bend as T
4import relation_graph.bend as C
5
6# Maintained inverse reorder: preserve authoritative targets; replace selected inverse order.
7def child_ids(children: List<&2,T.ChildStatus>) -> List<&2,K.Key>:
8 match children:
9 case []: []
10 case T.ChildStatus{id,_} <> rest: id <> child_ids(rest)
11def parent_match(value: Maybe<&2,K.Key>,parent: K.Key) -> Bool:
12 match value:
13 case None{}: False{}
14 case Some{id}: K.equal(id,parent)
15def same_count(a: List<&2,K.Key>,b: List<&2,K.Key>) -> Bool:
16 match a b:
17 case Nil{} Nil{}: True{}
18 case Con{_,ar} Con{_,br}: same_count(ar,br)
19 case _ _: False{}
20def subset(a: List<&2,K.Key>,+b: List<&2,K.Key>) -> Bool:
21 match a:
22 case []: True{}
23 case x <> rest: Bool.and(C.contains(b,x),subset(rest,b))
24def child_error(live: Bool,duplicate: Bool,related: Bool,parent: K.Key,child: K.Key,+name: String) -> Maybe<&2,T.Error>:
25 match live duplicate related:
26 case False{} _ _: Some{T.MissingChildEntity{parent,child,name}}
27 case True{} True{} _: Some{T.DuplicateChild{parent,child,name}}
28 case True{} False{} False{}: Some{T.ChildNotRelatedToParent{parent,child,name}}
29 case True{} False{} True{}: None{}
30def first_error(current: Maybe<&2,T.Error>,next: Unit -> Maybe<&2,T.Error>) -> Maybe<&2,T.Error>:
31 match current:
32 case Some{e}: Some{e}
33 case None{}: next(Unit{})
34def children_checked(~S: Data,children: List<&2,T.ChildStatus>,+graph: T.Graph<S>,+d: T.Descriptor<S>,+parent: K.Key,+seen: List<&2,K.Key>) -> Maybe<&2,T.Error>:
35 match children:
36 case []: None{}
37 case T.ChildStatus{+id,live} <> rest: first_error(child_error(live,C.contains(seen,id),parent_match(C.target(~S,graph,d,id),parent),parent,id,C.name(~S,d)),_ => children_checked(~S,rest,graph,d,parent,id <> seen))
38def mismatch(same: Bool,error: Maybe<&2,T.Error>,parent: K.Key,name: String) -> Maybe<&2,T.Error>:
39 match same error:
40 case _ Some{e}: Some{e}
41 case True{} None{}: None{}
42 case False{} None{}: Some{T.ChildSetMismatch{parent,name}}
43def validate(~S: Data,parentLive: Bool,+graph: T.Graph<S>,+d: T.Descriptor<S>,+parent: K.Key,+children: List<&2,T.ChildStatus>) -> Maybe<&2,T.Error>:
44 match parentLive:
45 case False{}: Some{T.MissingEntity{parent}}
46 case True{}: mismatch(Bool.and(same_count(C.inverse(~S,graph,d,parent),child_ids(children)),subset(C.inverse(~S,graph,d,parent),child_ids(children))),children_checked(~S,children,graph,d,parent,[]),parent,C.name(~S,d))
47# Maintained inverse reorder changes only the selected inverse entry.
48def replaced(~S: Data,found: Bool,entry: T.Inverse<S>,sources: List<&2,K.Key>,rest: List<&2,T.Inverse<S>>) -> List<&2,T.Inverse<S>>:
49 match found entry:
50 case True{} T.Inverse{d,parent,_}: T.Inverse{d,parent,sources} <> rest
51 case False{} entry: entry <> rest
52def replace_inverse(~S: Data,entries: List<&2,T.Inverse<S>>,+d: T.Descriptor<S>,+parent: K.Key,+sources: List<&2,K.Key>) -> List<&2,T.Inverse<S>>:
53 match entries:
54 case []: []
55 case T.Inverse{+other,+id,old} <> rest: replaced(~S,Bool.and(U32.is_eq(C.key(~S,d),C.key(~S,other)),K.equal(parent,id)),T.Inverse{other,id,old},sources,replace_inverse(~S,rest,d,parent,sources))
56def checked(~S: Data,error: Maybe<&2,T.Error>,graph: T.Graph<S>,d: T.Descriptor<S>,parent: K.Key,children: List<&2,T.ChildStatus>) -> T.CoreResult<S>:
57 match error graph:
58 case Some{e} graph: T.CoreResult{graph,Some{e}}
59 case None{} T.Graph{edges,inverses}: T.CoreResult{T.Graph{edges,replace_inverse(~S,inverses,d,parent,child_ids(children))},None{}}
60def reorder(~S: Data,+graph: T.Graph<S>,+d: T.Descriptor<S>,+parent: K.Key,+children: List<&2,T.ChildStatus>,parentLive: Bool) -> T.CoreResult<S>:
61 checked(~S,validate(~S,parentLive,graph,d,parent,children),graph,d,parent,children)