1mod parse;
18
19pub use parse::{parse_model, resolve_mount_target, EdgeDecl, Model, Mount, NodeDecl, RefDecl};
20
21use quarb::{AstAdapter, NodeId, QueryResult, Value};
22use std::cell::OnceCell;
23use std::collections::HashMap;
24
25const MODEL_TAG: u64 = 1 << 63;
30const CIDX_SHIFT: u64 = 44;
31const VAL_MASK: u64 = (1 << CIDX_SHIFT) - 1;
32
33struct Container {
35 name: String,
36 values: Vec<Value>,
40 by_str: HashMap<String, usize>,
42}
43
44struct Fabric {
47 resolve: HashMap<(NodeId, String), NodeId>,
49 ref_back: HashMap<NodeId, Vec<(String, NodeId)>>,
52 ref_fwd: HashMap<NodeId, Vec<(String, NodeId)>>,
54 edges: HashMap<NodeId, Vec<(String, NodeId)>>,
58}
59
60pub struct ModelAdapter<A: AstAdapter> {
62 base: A,
63 model: Model,
64 containers: OnceCell<Vec<Container>>,
65 fabric: OnceCell<Fabric>,
66}
67
68impl<A: AstAdapter> ModelAdapter<A> {
69 pub fn new(base: A, model: Model) -> Self {
70 ModelAdapter {
71 base,
72 model,
73 containers: OnceCell::new(),
74 fabric: OnceCell::new(),
75 }
76 }
77
78 pub fn base(&self) -> &A {
79 &self.base
80 }
81
82 pub fn locator(&self, node: NodeId, base_locator: impl Fn(NodeId) -> String) -> String {
85 match self.decode(node) {
86 None => base_locator(node),
87 Some((c, 0)) => format!("/{}", self.containers()[c].name),
88 Some((c, v)) => {
89 let cont = &self.containers()[c];
90 format!("/{}/{}", cont.name, cont.values[v - 1])
91 }
92 }
93 }
94
95 fn seeded_defs(&self) -> quarb::Defs {
96 quarb::parse_defs(&self.model.defs_text).unwrap_or_default()
97 }
98
99 fn containers(&self) -> &[Container] {
104 self.containers.get_or_init(|| {
105 let defs = self.seeded_defs();
106 let mut built: Vec<Container> = Vec::new();
107 for decl in &self.model.nodes {
108 let values = self.distinct_values(&decl.query, &defs, &built);
109 let by_str = values
110 .iter()
111 .enumerate()
112 .map(|(i, v)| (v.to_string(), i))
113 .collect();
114 built.push(Container {
115 name: decl.name.clone(),
116 values,
117 by_str,
118 });
119 }
120 built
121 })
122 }
123
124 fn distinct_values(
130 &self,
131 query: &str,
132 defs: &quarb::Defs,
133 prior: &[Container],
134 ) -> Vec<Value> {
135 let mut seen = std::collections::HashSet::new();
136 let mut out = Vec::new();
137 let mut push = |vs: Vec<Value>| {
138 for v in vs {
139 if seen.insert(v.to_string()) {
140 out.push(v);
141 }
142 }
143 };
144 let result = if prior.is_empty() {
148 quarb::run_with_defs(query, defs, &self.base)
149 } else {
150 let scratch = PriorView {
151 base: &self.base,
152 prior,
153 };
154 quarb::run_with_defs(query, defs, &scratch)
155 };
156 match result {
157 Ok(QueryResult::Values(vs)) => push(vs),
158 Ok(QueryResult::Nodes(ns)) => {
159 let named = ns
162 .into_iter()
163 .filter_map(|n| self.base.name(n).map(Value::Str))
164 .collect();
165 push(named)
166 }
167 Err(_) => {}
168 }
169 out
170 }
171
172 fn container_node(c: usize) -> NodeId {
173 NodeId(MODEL_TAG | (c as u64) << CIDX_SHIFT)
174 }
175
176 fn value_node(c: usize, v: usize) -> NodeId {
177 NodeId(MODEL_TAG | (c as u64) << CIDX_SHIFT | (v as u64 + 1))
178 }
179
180 fn decode(&self, node: NodeId) -> Option<(usize, usize)> {
184 if node.0 & MODEL_TAG == 0 {
185 return None;
186 }
187 let c = ((node.0 & !MODEL_TAG) >> CIDX_SHIFT) as usize;
188 let v = (node.0 & VAL_MASK) as usize;
189 (c < self.containers().len()).then_some((c, v))
190 }
191
192 fn container_by_name(&self, name: &str) -> Option<usize> {
193 self.containers().iter().position(|c| c.name == name)
194 }
195
196 fn find_value(&self, container: usize, value: &Value) -> Option<NodeId> {
198 let idx = *self.containers()[container].by_str.get(&value.to_string())?;
199 Some(Self::value_node(container, idx))
200 }
201
202 fn fabric(&self) -> &Fabric {
204 self.fabric.get_or_init(|| {
205 let defs = self.seeded_defs();
206 let mut f = Fabric {
207 resolve: HashMap::new(),
208 ref_back: HashMap::new(),
209 ref_fwd: HashMap::new(),
210 edges: HashMap::new(),
211 };
212 for decl in &self.model.refs {
215 let Some(container) = self.container_by_name(&decl.container) else {
216 continue;
217 };
218 for node in self.scope_nodes(&decl.scope, &defs) {
219 let Some(value) = self.base.property(node, &decl.field) else {
220 continue;
221 };
222 if matches!(value, Value::Null) {
223 continue;
224 }
225 let Some(target) = self.find_value(container, &value) else {
226 continue;
227 };
228 f.resolve.insert((node, decl.field.clone()), target);
229 f.ref_fwd
230 .entry(node)
231 .or_default()
232 .push((decl.field.clone(), target));
233 f.ref_back
234 .entry(target)
235 .or_default()
236 .push((decl.field.clone(), node));
237 }
238 }
239 for decl in &self.model.edges {
243 let ca = self.field_container(&decl.field_a);
244 let cb = self.field_container(&decl.field_b);
245 let (Some((ca, la)), Some((cb, lb))) = (ca, cb) else {
246 continue;
247 };
248 let mut seen = std::collections::HashSet::new();
249 for node in self.scope_nodes(&decl.scope, &defs) {
250 let (Some(va), Some(vb)) = (
251 self.base.property(node, &decl.field_a),
252 self.base.property(node, &decl.field_b),
253 ) else {
254 continue;
255 };
256 if matches!(va, Value::Null) || matches!(vb, Value::Null) {
257 continue;
258 }
259 let (Some(na), Some(nb)) =
260 (self.find_value(ca, &va), self.find_value(cb, &vb))
261 else {
262 continue;
263 };
264 if seen.insert((na, nb)) {
265 f.edges.entry(na).or_default().push((lb.clone(), nb));
266 f.edges.entry(nb).or_default().push((la.clone(), na));
267 }
268 }
269 }
270 f
271 })
272 }
273
274 fn field_container(&self, field: &str) -> Option<(usize, String)> {
277 let decl = self.model.refs.iter().find(|r| r.field == field)?;
278 let c = self.container_by_name(&decl.container)?;
279 Some((c, decl.container.clone()))
280 }
281
282 fn scope_nodes(&self, scope: &str, defs: &quarb::Defs) -> Vec<NodeId> {
284 match quarb::run_with_defs(scope, defs, &self.base) {
285 Ok(QueryResult::Nodes(ns)) => ns,
286 _ => Vec::new(),
287 }
288 }
289}
290
291struct PriorView<'a, A: AstAdapter> {
295 base: &'a A,
296 prior: &'a [Container],
297}
298
299impl<A: AstAdapter> AstAdapter for PriorView<'_, A> {
300 fn root(&self) -> NodeId {
301 self.base.root()
302 }
303 fn children(&self, node: NodeId) -> Vec<NodeId> {
304 if node.0 & MODEL_TAG != 0 {
305 let c = ((node.0 & !MODEL_TAG) >> CIDX_SHIFT) as usize;
306 let v = (node.0 & VAL_MASK) as usize;
307 if v == 0 && c < self.prior.len() {
308 return (0..self.prior[c].values.len())
309 .map(|i| NodeId(MODEL_TAG | (c as u64) << CIDX_SHIFT | (i as u64 + 1)))
310 .collect();
311 }
312 return Vec::new();
313 }
314 let mut kids = self.base.children(node);
315 if node == self.base.root() {
316 for c in 0..self.prior.len() {
317 kids.push(NodeId(MODEL_TAG | (c as u64) << CIDX_SHIFT));
318 }
319 }
320 kids
321 }
322 fn name(&self, node: NodeId) -> Option<String> {
323 if node.0 & MODEL_TAG != 0 {
324 let c = ((node.0 & !MODEL_TAG) >> CIDX_SHIFT) as usize;
325 let v = (node.0 & VAL_MASK) as usize;
326 let cont = self.prior.get(c)?;
327 return Some(if v == 0 {
328 cont.name.clone()
329 } else {
330 cont.values[v - 1].to_string()
331 });
332 }
333 self.base.name(node)
334 }
335 fn property(&self, node: NodeId, name: &str) -> Option<Value> {
336 if node.0 & MODEL_TAG != 0 {
337 return None;
338 }
339 self.base.property(node, name)
340 }
341 fn default_value(&self, node: NodeId) -> Option<Value> {
342 if node.0 & MODEL_TAG != 0 {
343 let c = ((node.0 & !MODEL_TAG) >> CIDX_SHIFT) as usize;
344 let v = (node.0 & VAL_MASK) as usize;
345 return (v > 0).then(|| self.prior.get(c).map(|k| k.values[v - 1].clone()))?;
346 }
347 self.base.default_value(node)
348 }
349}
350
351impl<A: AstAdapter> AstAdapter for ModelAdapter<A> {
352 fn root(&self) -> NodeId {
353 self.base.root()
354 }
355
356 fn children(&self, node: NodeId) -> Vec<NodeId> {
357 match self.decode(node) {
358 Some((c, 0)) => (0..self.containers()[c].values.len())
360 .map(|v| Self::value_node(c, v))
361 .collect(),
362 Some(_) => Vec::new(),
364 None => {
367 let mut kids = self.base.children(node);
368 if node == self.base.root() {
369 for c in 0..self.containers().len() {
370 kids.push(Self::container_node(c));
371 }
372 }
373 kids
374 }
375 }
376 }
377
378 fn children_named(&self, node: NodeId, name: &str) -> Vec<NodeId> {
379 if node == self.base.root() {
381 let mut out = self.base.children_named(node, name);
382 if let Some(c) = self.container_by_name(name) {
383 out.push(Self::container_node(c));
384 }
385 return out;
386 }
387 match self.decode(node) {
388 Some((c, 0)) => {
389 let cont = &self.containers()[c];
390 cont.by_str
391 .get(name)
392 .map(|&v| vec![Self::value_node(c, v)])
393 .unwrap_or_default()
394 }
395 Some(_) => Vec::new(),
396 None => self.base.children_named(node, name),
397 }
398 }
399
400 fn name(&self, node: NodeId) -> Option<String> {
401 match self.decode(node) {
402 Some((c, 0)) => Some(self.containers()[c].name.clone()),
403 Some((c, v)) => Some(self.containers()[c].values[v - 1].to_string()),
404 None => self.base.name(node),
405 }
406 }
407
408 fn parent(&self, node: NodeId) -> Option<NodeId> {
409 match self.decode(node) {
410 Some((_, 0)) => Some(self.base.root()),
411 Some((c, _)) => Some(Self::container_node(c)),
412 None => self.base.parent(node),
413 }
414 }
415
416 fn traits(&self, node: NodeId) -> Vec<String> {
417 match self.decode(node) {
418 Some((c, v)) if v > 0 => vec![singular(&self.containers()[c].name)],
421 Some(_) => Vec::new(),
422 None => self.base.traits(node),
423 }
424 }
425
426 fn property(&self, node: NodeId, name: &str) -> Option<Value> {
427 match self.decode(node) {
428 Some((c, v)) if v > 0 => Some(self.containers()[c].values[v - 1].clone()),
432 Some(_) => None,
433 None => self.base.property(node, name),
434 }
435 }
436
437 fn default_value(&self, node: NodeId) -> Option<Value> {
438 match self.decode(node) {
439 Some((c, v)) if v > 0 => Some(self.containers()[c].values[v - 1].clone()),
440 Some(_) => None,
441 None => self.base.default_value(node),
442 }
443 }
444
445 fn metadata(&self, node: NodeId, key: &str) -> Option<Value> {
446 match self.decode(node) {
447 Some((c, 0)) if key == "n-rows" => {
448 Some(Value::Int(self.containers()[c].values.len() as i64))
449 }
450 Some(_) => None,
451 None => self.base.metadata(node, key),
452 }
453 }
454
455 fn resolve(&self, node: NodeId, property: &str, hint: Option<&str>) -> Option<NodeId> {
456 if self.decode(node).is_none() {
457 if let Some(&target) = self.fabric().resolve.get(&(node, property.to_string())) {
458 return Some(target);
459 }
460 }
461 self.base.resolve(node, property, hint)
462 }
463
464 fn links(&self, node: NodeId) -> Vec<(String, NodeId)> {
465 match self.decode(node) {
466 Some((_, v)) if v > 0 => {
468 self.fabric().edges.get(&node).cloned().unwrap_or_default()
469 }
470 Some(_) => Vec::new(),
471 None => {
473 let mut out = self.base.links(node);
474 if let Some(refs) = self.fabric().ref_fwd.get(&node) {
475 out.extend(refs.iter().cloned());
476 }
477 out
478 }
479 }
480 }
481
482 fn backlinks(&self, node: NodeId) -> Vec<(String, NodeId)> {
483 match self.decode(node) {
484 Some((_, v)) if v > 0 => {
487 let mut out = self.fabric().ref_back.get(&node).cloned().unwrap_or_default();
488 if let Some(e) = self.fabric().edges.get(&node) {
489 out.extend(e.iter().cloned());
490 }
491 out
492 }
493 Some(_) => Vec::new(),
494 None => self.base.backlinks(node),
495 }
496 }
497
498 fn quantifier_bound(&self) -> usize {
499 self.base.quantifier_bound()
500 }
501 fn allow_shell(&self) -> bool {
502 self.base.allow_shell()
503 }
504 fn invocation_instant(&self) -> Option<(i64, u32)> {
505 self.base.invocation_instant()
506 }
507 fn unit_scale(&self, expr: &str) -> Option<(f64, String)> {
508 self.base.unit_scale(expr)
509 }
510}
511
512fn singular(name: &str) -> String {
515 name.strip_suffix('s').unwrap_or(name).to_string()
516}
517
518pub struct Borrowed<'a>(pub &'a dyn AstAdapter);
524
525impl AstAdapter for Borrowed<'_> {
526 fn root(&self) -> NodeId {
527 self.0.root()
528 }
529 fn children(&self, n: NodeId) -> Vec<NodeId> {
530 self.0.children(n)
531 }
532 fn name(&self, n: NodeId) -> Option<String> {
533 self.0.name(n)
534 }
535 fn parent(&self, n: NodeId) -> Option<NodeId> {
536 self.0.parent(n)
537 }
538 fn traits(&self, n: NodeId) -> Vec<String> {
539 self.0.traits(n)
540 }
541 fn children_named(&self, n: NodeId, name: &str) -> Vec<NodeId> {
542 self.0.children_named(n, name)
543 }
544 fn property(&self, n: NodeId, name: &str) -> Option<Value> {
545 self.0.property(n, name)
546 }
547 fn default_value(&self, n: NodeId) -> Option<Value> {
548 self.0.default_value(n)
549 }
550 fn metadata(&self, n: NodeId, key: &str) -> Option<Value> {
551 self.0.metadata(n, key)
552 }
553 fn links(&self, n: NodeId) -> Vec<(String, NodeId)> {
554 self.0.links(n)
555 }
556 fn backlinks(&self, n: NodeId) -> Vec<(String, NodeId)> {
557 self.0.backlinks(n)
558 }
559 fn resolve(&self, n: NodeId, p: &str, h: Option<&str>) -> Option<NodeId> {
560 self.0.resolve(n, p, h)
561 }
562 fn link_property(&self, s: NodeId, l: &str, t: NodeId, name: &str) -> Option<Value> {
563 self.0.link_property(s, l, t, name)
564 }
565 fn quantifier_bound(&self) -> usize {
566 self.0.quantifier_bound()
567 }
568 fn allow_shell(&self) -> bool {
569 self.0.allow_shell()
570 }
571 fn invocation_instant(&self) -> Option<(i64, u32)> {
572 self.0.invocation_instant()
573 }
574 fn unit_scale(&self, expr: &str) -> Option<(f64, String)> {
575 self.0.unit_scale(expr)
576 }
577}