relation_graph.bend

bendvy-ecs-core@0.1.0.3 · 183 lines · 60 definitions

1import Base
2import entity_key.bend as K
3import relation_types.bend as T
4
5# Experimental maintained inverse implementation. Does not call graph-spec.
6def key_erased(-S: Data,descriptor: T.Descriptor<S>) -> U32:
7  match descriptor:
8    case T.Descriptor{key,_,_,_}: key
9def name_erased(-S: Data,descriptor: T.Descriptor<S>) -> String:
10  match descriptor:
11    case T.Descriptor{_,name,_,_}: name
12def contains(xs: List<&2,K.Key>,+id: K.Key) -> Bool:
13  match xs:
14    case []: False{}
15    case x <> rest: Bool.or(K.equal(x,id),contains(rest,id))
16def removed_id(remove: Bool,id: K.Key,rest: List<&2,K.Key>) -> List<&2,K.Key>:
17  match remove:
18    case True{}: rest
19    case False{}: id <> rest
20def remove_id(xs: List<&2,K.Key>,+id: K.Key) -> List<&2,K.Key>:
21  match xs:
22    case []: []
23    case +x <> rest: removed_id(K.equal(x,id),x,remove_id(rest,id))
24def chosen_target(found: Bool,target: K.Key,next: Unit -> Maybe<&2,K.Key>) -> Maybe<&2,K.Key>:
25  match found:
26    case True{}: Some{target}
27    case False{}: next(Unit{})
28def target_edges_erased(-S: Data,edges: List<&2,T.Edge<S>>,+descriptor: T.Descriptor<S>,+source: K.Key) -> Maybe<&2,K.Key>:
29  match edges:
30    case []: None{}
31    case T.Edge{other,id,target} <> rest: chosen_target(Bool.and(U32.is_eq(key_erased(S,other),key_erased(S,descriptor)),K.equal(id,source)),target,_ => target_edges_erased(S,rest,descriptor,source))
32def target_erased(-S: Data,graph: T.Graph<S>,descriptor: T.Descriptor<S>,source: K.Key) -> Maybe<&2,K.Key>:
33  match graph:
34    case T.Graph{edges,_}: target_edges_erased(S,edges,descriptor,source)
35def chosen_inverse(found: Bool,sources: List<&2,K.Key>,next: Unit -> List<&2,K.Key>) -> List<&2,K.Key>:
36  match found:
37    case True{}: sources
38    case False{}: next(Unit{})
39def inverse_entries_erased(-S: Data,entries: List<&2,T.Inverse<S>>,+descriptor: T.Descriptor<S>,+target: K.Key) -> List<&2,K.Key>:
40  match entries:
41    case []: []
42    case T.Inverse{other,id,sources} <> rest: chosen_inverse(Bool.and(U32.is_eq(key_erased(S,other),key_erased(S,descriptor)),K.equal(id,target)),sources,_ => inverse_entries_erased(S,rest,descriptor,target))
43def inverse_erased(-S: Data,graph: T.Graph<S>,descriptor: T.Descriptor<S>,target: K.Key) -> List<&2,K.Key>:
44  match graph:
45    case T.Graph{_,entries}: inverse_entries_erased(S,entries,descriptor,target)
46def edge_removed_erased(-S: Data,remove: Bool,edge: T.Edge<S>,rest: List<&2,T.Edge<S>>) -> List<&2,T.Edge<S>>:
47  match remove:
48    case True{}: rest
49    case False{}: edge <> rest
50def remove_edge_fields_erased(-S: Data,edge: T.Edge<S>,+descriptor: T.Descriptor<S>,source: K.Key,next: Unit -> List<&2,T.Edge<S>>) -> List<&2,T.Edge<S>>:
51  match edge:
52    case T.Edge{+other,+id,+target}: edge_removed_erased(S,Bool.and(U32.is_eq(key_erased(S,other),key_erased(S,descriptor)),K.equal(id,source)),T.Edge{other,id,target},next(Unit{}))
53def remove_edge_keep_erased(-S:Data,edge:T.Edge<S>,+descriptor:T.Descriptor<S>,source:K.Key,acc:List<&2,T.Edge<S>>) -> List<&2,T.Edge<S>>:
54  match edge:
55    case T.Edge{+other,+id,+target}: edge_removed_erased(S,Bool.and(U32.is_eq(key_erased(S,other),key_erased(S,descriptor)),K.equal(id,source)),T.Edge{other,id,target},acc)
56def remove_edge_acc_erased(-S:Data,edges:List<&2,T.Edge<S>>,+descriptor:T.Descriptor<S>,+source:K.Key,acc:List<&2,T.Edge<S>>) -> List<&2,T.Edge<S>>:
57  match edges:
58    case []: List.reverse(&2,T.Edge<S>,acc)
59    case +edge <> rest: remove_edge_acc_erased(S,rest,descriptor,source,remove_edge_keep_erased(S,edge,descriptor,source,acc))
60def remove_edge_erased(-S: Data,edges: List<&2,T.Edge<S>>,descriptor: T.Descriptor<S>,source: K.Key) -> List<&2,T.Edge<S>>:
61  remove_edge_acc_erased(S,edges,descriptor,source,[])
62def nonempty_inverse_erased(-S: Data,descriptor: T.Descriptor<S>,target: K.Key,sources: List<&2,K.Key>,rest: List<&2,T.Inverse<S>>) -> List<&2,T.Inverse<S>>:
63  match sources:
64    case []: rest
65    case head <> tail: T.Inverse{descriptor,target,head <> tail} <> rest
66def inverse_remove_one_erased(-S: Data,matched: Bool,descriptor: T.Descriptor<S>,target: K.Key,sources: List<&2,K.Key>,source: K.Key,rest: List<&2,T.Inverse<S>>) -> List<&2,T.Inverse<S>>:
67  match matched:
68    case True{}: nonempty_inverse_erased(S,descriptor,target,remove_id(sources,source),rest)
69    case False{}: T.Inverse{descriptor,target,sources} <> rest
70def inverse_remove_acc_erased(-S:Data,entries:List<&2,T.Inverse<S>>,+descriptor:T.Descriptor<S>,+target:K.Key,+source:K.Key,acc:List<&2,T.Inverse<S>>) -> List<&2,T.Inverse<S>>:
71  match entries:
72    case []: List.reverse(&2,T.Inverse<S>,acc)
73    case T.Inverse{+other,+id,sources} <> rest: inverse_remove_acc_erased(S,rest,descriptor,target,source,inverse_remove_one_erased(S,Bool.and(U32.is_eq(key_erased(S,other),key_erased(S,descriptor)),K.equal(id,target)),other,id,sources,source,acc))
74def inverse_remove_erased(-S: Data,entries: List<&2,T.Inverse<S>>,descriptor: T.Descriptor<S>,target: K.Key,source: K.Key) -> List<&2,T.Inverse<S>>:
75  inverse_remove_acc_erased(S,entries,descriptor,target,source,[])
76def remove_previous_erased(-S: Data,previous: Maybe<&2,K.Key>,entries: List<&2,T.Inverse<S>>,descriptor: T.Descriptor<S>,source: K.Key) -> List<&2,T.Inverse<S>>:
77  match previous:
78    case None{}: entries
79    case Some{target}: inverse_remove_erased(S,entries,descriptor,target,source)
80def appended_source(present: Bool,sources: List<&2,K.Key>,source: K.Key) -> List<&2,K.Key>:
81  match present:
82    case True{}: sources
83    case False{}: List.append(&2,K.Key,sources,[source])
84def inverse_add_found_erased(-S: Data,found: Bool,other: T.Descriptor<S>,id: K.Key,+sources: List<&2,K.Key>,+descriptor: T.Descriptor<S>,target: K.Key,+source: K.Key,rest: List<&2,T.Inverse<S>>,next: Unit -> List<&2,T.Inverse<S>>) -> List<&2,T.Inverse<S>>:
85  match found:
86    case True{}: T.Inverse{other,id,appended_source(contains(sources,source),sources,source)} <> rest
87    case False{}: T.Inverse{other,id,sources} <> next(Unit{})
88def inverse_add_erased(-S: Data,entries: List<&2,T.Inverse<S>>,+descriptor: T.Descriptor<S>,+target: K.Key,+source: K.Key) -> List<&2,T.Inverse<S>>:
89  match entries:
90    case []: [T.Inverse{descriptor,target,[source]}]
91    case T.Inverse{+other,+id,+sources} <> +rest: inverse_add_found_erased(S,Bool.and(U32.is_eq(key_erased(S,other),key_erased(S,descriptor)),K.equal(id,target)),other,id,sources,descriptor,target,source,rest,_ => inverse_add_erased(S,rest,descriptor,target,source))
92def unrelate_erased(-S: Data,graph: T.Graph<S>,+descriptor: T.Descriptor<S>,+source: K.Key) -> T.Graph<S>:
93  match graph:
94    case T.Graph{+edges,inverses}: T.Graph{remove_edge_erased(S,edges,descriptor,source),remove_previous_erased(S,target_edges_erased(S,edges,descriptor,source),inverses,descriptor,source)}
95def next_cycle_erased(-S: Data,current: Maybe<&2,K.Key>,next: K.Key -> Bool) -> Bool:
96  match current:
97    case None{}: False{}
98    case Some{id}: next(id)
99def cycle_loop_erased(-S: Data,fuel: Nat,+graph: T.Graph<S>,+descriptor: T.Descriptor<S>,+source: K.Key,+current: K.Key) -> Bool:
100  match fuel:
101    case 0n: K.equal(source,current)
102    case 1n+rest: Bool.or(K.equal(source,current),next_cycle_erased(S,target_erased(S,graph,descriptor,current),id => cycle_loop_erased(S,rest,graph,descriptor,source,id)))
103def cycle_erased(-S: Data,+graph: T.Graph<S>,descriptor: T.Descriptor<S>,source: K.Key,target: K.Key) -> Bool:
104  match graph descriptor:
105    case T.Graph{edges,inverses} T.Descriptor{k,n,inv,T.Ordinary{}}: False{}
106    case T.Graph{+edges,+inverses} T.Descriptor{+k,+n,+inv,T.Hierarchy{}}: cycle_loop_erased(S,List.length(&2,T.Edge<S>,edges),T.Graph{edges,inverses},T.Descriptor{k,n,inv,T.Hierarchy{}},source,target)
107def validation(sourceLive: Bool,targetLive: Bool,self: Bool,cyclic: Bool,source: K.Key,target: K.Key,name: String) -> Maybe<&2,T.Error>:
108  match sourceLive targetLive self cyclic:
109    case False{} _ _ _: Some{T.MissingEntity{source}}
110    case True{} False{} _ _: Some{T.MissingTargetEntity{source,target,name}}
111    case True{} True{} True{} _: Some{T.SelfRelationNotAllowed{source,name}}
112    case True{} True{} False{} True{}: Some{T.HierarchyCycle{source,target,name}}
113    case True{} True{} False{} False{}: None{}
114def already(previous: Maybe<&2,K.Key>,target: K.Key) -> Bool:
115  match previous:
116    case None{}: False{}
117    case Some{id}: K.equal(id,target)
118def updated_erased(-S: Data,same: Bool,+edges: List<&2,T.Edge<S>>,inverses: List<&2,T.Inverse<S>>,+descriptor: T.Descriptor<S>,+source: K.Key,+target: K.Key) -> T.Graph<S>:
119  match same:
120    case True{}: T.Graph{edges,inverses}
121    case False{}: T.Graph{List.append(&2,T.Edge<S>,remove_edge_erased(S,edges,descriptor,source),[T.Edge{descriptor,source,target}]),inverse_add_erased(S,remove_previous_erased(S,target_edges_erased(S,edges,descriptor,source),inverses,descriptor,source),descriptor,target,source)}
122def checked_erased(-S: Data,error: Maybe<&2,T.Error>,graph: T.Graph<S>,+descriptor: T.Descriptor<S>,+source: K.Key,+target: K.Key) -> T.CoreResult<S>:
123  match error graph:
124    case Some{error} graph: T.CoreResult{graph,Some{error}}
125    case None{} T.Graph{+edges,inverses}: T.CoreResult{updated_erased(S,already(target_edges_erased(S,edges,descriptor,source),target),edges,inverses,descriptor,source,target),None{}}
126def relate_erased(-S: Data,+graph: T.Graph<S>,+descriptor: T.Descriptor<S>,+source: K.Key,+target: K.Key,sourceLive: Bool,targetLive: Bool) -> T.CoreResult<S>:
127  checked_erased(S,validation(sourceLive,targetLive,K.equal(source,target),cycle_erased(S,graph,descriptor,source,target),source,target,name_erased(S,descriptor)),graph,descriptor,source,target)
128def project_erased(-S: Data,graph: T.Graph<S>) -> T.SpecGraph<S>:
129  match graph:
130    case T.Graph{edges,_}: T.SpecGraph{edges}
131# Public schema-specialized entry points delegate to the same erased algorithms.
132def key(~S: Data,descriptor: T.Descriptor<S>) -> U32:
133  key_erased(S,descriptor)
134def name(~S: Data,descriptor: T.Descriptor<S>) -> String:
135  name_erased(S,descriptor)
136def target_edges(~S: Data,edges: List<&2,T.Edge<S>>,+descriptor: T.Descriptor<S>,+source: K.Key) -> Maybe<&2,K.Key>:
137  target_edges_erased(S,edges,descriptor,source)
138def target(~S: Data,graph: T.Graph<S>,descriptor: T.Descriptor<S>,source: K.Key) -> Maybe<&2,K.Key>:
139  target_erased(S,graph,descriptor,source)
140def inverse_entries(~S: Data,entries: List<&2,T.Inverse<S>>,+descriptor: T.Descriptor<S>,+target: K.Key) -> List<&2,K.Key>:
141  inverse_entries_erased(S,entries,descriptor,target)
142def inverse(~S: Data,graph: T.Graph<S>,descriptor: T.Descriptor<S>,target: K.Key) -> List<&2,K.Key>:
143  inverse_erased(S,graph,descriptor,target)
144def edge_removed(~S: Data,remove: Bool,edge: T.Edge<S>,rest: List<&2,T.Edge<S>>) -> List<&2,T.Edge<S>>:
145  edge_removed_erased(S,remove,edge,rest)
146def remove_edge_fields(~S: Data,edge: T.Edge<S>,+descriptor: T.Descriptor<S>,source: K.Key,next: Unit -> List<&2,T.Edge<S>>) -> List<&2,T.Edge<S>>:
147  remove_edge_fields_erased(S,edge,descriptor,source,next)
148def remove_edge_keep(~S:Data,edge:T.Edge<S>,+descriptor:T.Descriptor<S>,source:K.Key,acc:List<&2,T.Edge<S>>) -> List<&2,T.Edge<S>>:
149  remove_edge_keep_erased(S,edge,descriptor,source,acc)
150def remove_edge_acc(~S:Data,edges:List<&2,T.Edge<S>>,+descriptor:T.Descriptor<S>,+source:K.Key,acc:List<&2,T.Edge<S>>) -> List<&2,T.Edge<S>>:
151  remove_edge_acc_erased(S,edges,descriptor,source,acc)
152def remove_edge(~S: Data,edges: List<&2,T.Edge<S>>,descriptor: T.Descriptor<S>,source: K.Key) -> List<&2,T.Edge<S>>:
153  remove_edge_erased(S,edges,descriptor,source)
154def nonempty_inverse(~S: Data,descriptor: T.Descriptor<S>,target: K.Key,sources: List<&2,K.Key>,rest: List<&2,T.Inverse<S>>) -> List<&2,T.Inverse<S>>:
155  nonempty_inverse_erased(S,descriptor,target,sources,rest)
156def inverse_remove_one(~S: Data,matched: Bool,descriptor: T.Descriptor<S>,target: K.Key,sources: List<&2,K.Key>,source: K.Key,rest: List<&2,T.Inverse<S>>) -> List<&2,T.Inverse<S>>:
157  inverse_remove_one_erased(S,matched,descriptor,target,sources,source,rest)
158def inverse_remove_acc(~S:Data,entries:List<&2,T.Inverse<S>>,+descriptor:T.Descriptor<S>,+target:K.Key,+source:K.Key,acc:List<&2,T.Inverse<S>>) -> List<&2,T.Inverse<S>>:
159  inverse_remove_acc_erased(S,entries,descriptor,target,source,acc)
160def inverse_remove(~S: Data,entries: List<&2,T.Inverse<S>>,descriptor: T.Descriptor<S>,target: K.Key,source: K.Key) -> List<&2,T.Inverse<S>>:
161  inverse_remove_erased(S,entries,descriptor,target,source)
162def remove_previous(~S: Data,previous: Maybe<&2,K.Key>,entries: List<&2,T.Inverse<S>>,descriptor: T.Descriptor<S>,source: K.Key) -> List<&2,T.Inverse<S>>:
163  remove_previous_erased(S,previous,entries,descriptor,source)
164def inverse_add_found(~S: Data,found: Bool,other: T.Descriptor<S>,id: K.Key,+sources: List<&2,K.Key>,+descriptor: T.Descriptor<S>,target: K.Key,+source: K.Key,rest: List<&2,T.Inverse<S>>,next: Unit -> List<&2,T.Inverse<S>>) -> List<&2,T.Inverse<S>>:
165  inverse_add_found_erased(S,found,other,id,sources,descriptor,target,source,rest,next)
166def inverse_add(~S: Data,entries: List<&2,T.Inverse<S>>,+descriptor: T.Descriptor<S>,+target: K.Key,+source: K.Key) -> List<&2,T.Inverse<S>>:
167  inverse_add_erased(S,entries,descriptor,target,source)
168def unrelate(~S: Data,graph: T.Graph<S>,+descriptor: T.Descriptor<S>,+source: K.Key) -> T.Graph<S>:
169  unrelate_erased(S,graph,descriptor,source)
170def next_cycle(~S: Data,current: Maybe<&2,K.Key>,next: K.Key -> Bool) -> Bool:
171  next_cycle_erased(S,current,next)
172def cycle_loop(~S: Data,fuel: Nat,+graph: T.Graph<S>,+descriptor: T.Descriptor<S>,+source: K.Key,+current: K.Key) -> Bool:
173  cycle_loop_erased(S,fuel,graph,descriptor,source,current)
174def cycle(~S: Data,+graph: T.Graph<S>,descriptor: T.Descriptor<S>,source: K.Key,target: K.Key) -> Bool:
175  cycle_erased(S,graph,descriptor,source,target)
176def updated(~S: Data,same: Bool,+edges: List<&2,T.Edge<S>>,inverses: List<&2,T.Inverse<S>>,+descriptor: T.Descriptor<S>,+source: K.Key,+target: K.Key) -> T.Graph<S>:
177  updated_erased(S,same,edges,inverses,descriptor,source,target)
178def checked(~S: Data,error: Maybe<&2,T.Error>,graph: T.Graph<S>,+descriptor: T.Descriptor<S>,+source: K.Key,+target: K.Key) -> T.CoreResult<S>:
179  checked_erased(S,error,graph,descriptor,source,target)
180def relate(~S: Data,+graph: T.Graph<S>,+descriptor: T.Descriptor<S>,+source: K.Key,+target: K.Key,sourceLive: Bool,targetLive: Bool) -> T.CoreResult<S>:
181  relate_erased(S,graph,descriptor,source,target,sourceLive,targetLive)
182def project(~S: Data,graph: T.Graph<S>) -> T.SpecGraph<S>:
183  project_erased(S,graph)