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)