1mod parse;
18
19pub use parse::{
20 AliasDecl, AliasKind, AliasRule, EdgeDecl, Model, Mount, NodeDecl, RefDecl, RelDecl,
21 parse_model, parse_model_file, resolve_mount_target,
22};
23
24use quarb::{AstAdapter, NodeId, QueryResult, Value};
25use std::cell::OnceCell;
26use std::collections::HashMap;
27
28const MODEL_TAG: u64 = 1 << 63;
33const CIDX_SHIFT: u64 = 44;
34const VAL_MASK: u64 = (1 << CIDX_SHIFT) - 1;
35
36#[derive(Clone)]
40enum Member {
41 Value(Value),
44 Node(NodeId),
49}
50
51struct Container {
56 name: String,
57 members: Vec<Member>,
62 roles: Vec<(String, String)>,
66 by_str: HashMap<String, usize>,
69 by_role: HashMap<String, HashMap<String, usize>>,
71}
72
73impl Container {
74 fn member(&self, v: usize) -> Option<Member> {
76 if v == 0 {
77 return None;
78 }
79 self.members.get(v - 1).cloned()
80 }
81
82 fn role_of(&self, v: usize) -> &str {
84 &self.roles[v - 1].0
85 }
86
87 fn trait_of(&self, v: usize) -> &str {
89 &self.roles[v - 1].1
90 }
91
92 fn ordinal_in_role(&self, v: usize) -> usize {
95 let role = &self.roles[v - 1].0;
96 self.roles[..v - 1]
97 .iter()
98 .filter(|(r, _)| r == role)
99 .count()
100 + 1
101 }
102
103 fn of_role<'a>(&'a self, role: &'a str) -> impl Iterator<Item = usize> + 'a {
105 self.roles
106 .iter()
107 .enumerate()
108 .filter(move |(_, (r, _))| r == role)
109 .map(|(i, _)| i)
110 }
111}
112
113struct Fabric {
116 alias: HashMap<NodeId, (NodeId, String)>,
121 resolve: HashMap<(NodeId, String), NodeId>,
123 sources: HashMap<(NodeId, String), Vec<NodeId>>,
127 ref_back: HashMap<NodeId, Vec<(String, NodeId)>>,
130 ref_fwd: HashMap<NodeId, Vec<(String, NodeId)>>,
132 rel_fwd: HashMap<NodeId, Vec<(String, NodeId)>>,
136 rel_back: HashMap<NodeId, Vec<(String, NodeId)>>,
137 edges: HashMap<NodeId, Vec<(String, NodeId)>>,
141}
142
143pub struct ModelAdapter<A: AstAdapter> {
145 base: A,
146 model: Model,
147 containers: OnceCell<Vec<Container>>,
148 fabric: OnceCell<Fabric>,
149}
150
151impl<A: AstAdapter> ModelAdapter<A> {
152 pub fn new(base: A, model: Model) -> Self {
153 ModelAdapter {
154 base,
155 model,
156 containers: OnceCell::new(),
157 fabric: OnceCell::new(),
158 }
159 }
160
161 pub fn base(&self) -> &A {
162 &self.base
163 }
164
165 pub fn locator(&self, node: NodeId, base_locator: impl Fn(NodeId) -> String) -> String {
168 match self.decode(node) {
169 None => base_locator(node),
170 Some((c, 0)) => format!("/{}", self.containers()[c].name),
171 Some((c, v)) => {
172 let cont = &self.containers()[c];
175 format!(
176 "/{}/{}[{}]",
177 cont.name,
178 cont.role_of(v),
179 cont.ordinal_in_role(v)
180 )
181 }
182 }
183 }
184
185 fn seeded_defs(&self) -> quarb::Defs {
186 quarb::parse_defs(&self.model.defs_text).unwrap_or_default()
187 }
188
189 fn containers(&self) -> &[Container] {
194 self.containers.get_or_init(|| {
195 let defs = self.seeded_defs();
196 let mut built: Vec<Container> = Vec::new();
197 for decl in &self.model.nodes {
198 let members = self.members(&decl.query, &defs, &built);
199 let idx = match built.iter().position(|c| c.name == decl.name) {
202 Some(i) => i,
203 None => {
204 built.push(Container {
205 name: decl.name.clone(),
206 members: Vec::new(),
207 roles: Vec::new(),
208 by_str: HashMap::new(),
209 by_role: HashMap::new(),
210 });
211 built.len() - 1
212 }
213 };
214 let keyed: Vec<(Member, Option<String>)> = members
219 .into_iter()
220 .map(|m| {
221 let key = match &m {
222 Member::Value(v) => Some(v.to_string()),
223 Member::Node(n) => self.base_key(*n),
224 };
225 (m, key)
226 })
227 .collect();
228 let cont = &mut built[idx];
229 let held_nodes: std::collections::HashSet<NodeId> = cont
234 .members
235 .iter()
236 .zip(&cont.roles)
237 .filter(|(_, (r, _))| *r == decl.role)
238 .filter_map(|(m, _)| match m {
239 Member::Node(n) => Some(*n),
240 Member::Value(_) => None,
241 })
242 .collect();
243 let by_role = cont.by_role.entry(decl.role.clone()).or_default();
244 for (m, key) in keyed {
245 let held = match &m {
246 Member::Node(n) => held_nodes.contains(n),
247 Member::Value(_) => key.as_deref().is_some_and(|k| by_role.contains_key(k)),
248 };
249 if held {
250 continue;
251 }
252 let i = cont.members.len();
253 cont.members.push(m);
254 cont.roles
255 .push((decl.role.clone(), decl.trait_name.clone()));
256 if let Some(k) = key {
257 by_role.entry(k.clone()).or_insert(i);
258 cont.by_str.entry(k).or_insert(i);
259 }
260 }
261 }
262 built
263 })
264 }
265
266 fn members(&self, query: &str, defs: &quarb::Defs, prior: &[Container]) -> Vec<Member> {
273 let result = if prior.is_empty() {
277 quarb::run_with_defs(query, defs, &self.base)
278 } else {
279 let scratch = PriorView {
280 base: &self.base,
281 prior,
282 };
283 quarb::run_with_defs(query, defs, &scratch)
284 };
285 match result {
286 Ok(QueryResult::Values(vs)) => {
287 let mut seen = std::collections::HashSet::new();
288 vs.into_iter()
289 .filter(|v| seen.insert(v.to_string()))
290 .map(Member::Value)
291 .collect()
292 }
293 Ok(QueryResult::Nodes(ns)) => {
294 let mut seen = std::collections::HashSet::new();
295 ns.into_iter()
296 .filter(|n| seen.insert(*n))
297 .map(Member::Node)
298 .collect()
299 }
300 Err(_) => Vec::new(),
301 }
302 }
303
304 fn base_key(&self, node: NodeId) -> Option<String> {
307 self.base
308 .default_value(node)
309 .map(|v| v.to_string())
310 .or_else(|| self.base.name(node))
311 }
312
313 fn aliased(&self, node: NodeId) -> Option<NodeId> {
315 match self.decode(node) {
316 Some((c, v)) if v > 0 => match self.containers()[c].member(v)? {
317 Member::Node(n) => Some(n),
318 Member::Value(_) => None,
319 },
320 _ => None,
321 }
322 }
323
324 fn role_at(&self, node: NodeId) -> Option<String> {
327 match self.decode(node) {
328 Some((c, v)) if v > 0 => Some(self.containers()[c].role_of(v).to_string()),
329 _ => None,
330 }
331 }
332
333 fn elevated(&self, node: NodeId) -> Option<Value> {
335 match self.decode(node) {
336 Some((c, v)) if v > 0 => match self.containers()[c].member(v)? {
337 Member::Value(val) => Some(val),
338 Member::Node(_) => None,
339 },
340 _ => None,
341 }
342 }
343
344 fn container_node(c: usize) -> NodeId {
345 NodeId(MODEL_TAG | (c as u64) << CIDX_SHIFT)
346 }
347
348 fn value_node(c: usize, v: usize) -> NodeId {
349 NodeId(MODEL_TAG | (c as u64) << CIDX_SHIFT | (v as u64 + 1))
350 }
351
352 fn decode(&self, node: NodeId) -> Option<(usize, usize)> {
356 if node.0 & MODEL_TAG == 0 {
357 return None;
358 }
359 let c = ((node.0 & !MODEL_TAG) >> CIDX_SHIFT) as usize;
360 let v = (node.0 & VAL_MASK) as usize;
361 (c < self.containers().len()).then_some((c, v))
362 }
363
364 fn container_by_name(&self, name: &str) -> Option<usize> {
365 self.containers().iter().position(|c| c.name == name)
366 }
367
368 fn fabric(&self) -> &Fabric {
370 self.fabric.get_or_init(|| {
371 let defs = self.seeded_defs();
372 let mut f = Fabric {
373 alias: HashMap::new(),
374 resolve: HashMap::new(),
375 sources: HashMap::new(),
376 ref_back: HashMap::new(),
377 ref_fwd: HashMap::new(),
378 rel_fwd: HashMap::new(),
379 rel_back: HashMap::new(),
380 edges: HashMap::new(),
381 };
382 for (c, cont) in self.containers().iter().enumerate() {
383 for (i, m) in cont.members.iter().enumerate() {
384 if let Member::Node(n) = m {
385 f.alias
386 .entry(*n)
387 .or_insert((Self::value_node(c, i), cont.roles[i].0.clone()));
388 }
389 }
390 }
391 let mut reached: HashMap<(NodeId, String), Vec<(String, NodeId)>> = HashMap::new();
395 for decl in &self.model.refs {
396 let mut index: HashMap<String, NodeId> = HashMap::new();
405 let derived = self.container_by_name(&decl.container);
406 match derived {
407 Some(container) => {
408 let cont = &self.containers()[container];
409 let slots: Vec<usize> = match decl.role.as_deref() {
410 Some(role) => cont.of_role(role).map(|i| i + 1).collect(),
411 None => (1..=cont.members.len()).collect(),
412 };
413 for v in slots {
414 let n = Self::value_node(container, v - 1);
415 let key = match decl.key_field.as_deref() {
416 Some(f) => self.property(n, f).map(|k| k.to_string()),
417 None => match cont.member(v) {
418 Some(Member::Value(val)) => Some(val.to_string()),
419 Some(Member::Node(b)) => self.base_key(b),
420 None => None,
421 },
422 };
423 if let Some(k) = key {
424 index.entry(k).or_insert(n);
425 }
426 }
427 }
428 None => {
429 let view = PriorView {
430 base: &self.base,
431 prior: self.containers(),
432 };
433 for n in self.view_nodes(&decl.path, &defs) {
434 let key = match decl.key_field.as_deref() {
435 Some(f) => view.property(n, f).map(|k| k.to_string()),
436 None => view
437 .default_value(n)
438 .map(|v| v.to_string())
439 .or_else(|| view.name(n)),
440 };
441 if let Some(k) = key {
442 index.entry(k).or_insert(n);
443 }
444 }
445 }
446 }
447 let path_label = scope_role(&decl.path);
451 let mut scoped = self.scope_nodes(&decl.scope, &defs);
455 if scoped.is_empty() {
456 scoped = self
457 .view_nodes(&decl.scope, &defs)
458 .into_iter()
459 .filter_map(|n| self.aliased(n))
460 .collect();
461 }
462 for node in scoped {
463 let Some(value) = self.base.property(node, &decl.field) else {
464 continue;
465 };
466 if matches!(value, Value::Null) {
467 continue;
468 }
469 let elements: Vec<Value> = match value {
474 l @ Value::List(_) => l.into_items().unwrap_or_default(),
475 other => vec![other],
476 };
477 let mut first = true;
478 for value in elements {
479 let Some(target) = index.get(&value.to_string()).copied() else {
480 continue;
481 };
482 let fwd = self.role_at(target).unwrap_or_else(|| path_label.clone());
483 let (back_node, back) = match f.alias.get(&node) {
487 Some((alias, role)) => (*alias, role.clone()),
488 None => (node, scope_role(&decl.scope)),
489 };
490 if first {
491 f.resolve.insert((node, decl.field.clone()), target);
492 first = false;
493 }
494 reached
495 .entry((node, decl.field.clone()))
496 .or_default()
497 .push((fwd.clone(), target));
498 let from = f.sources.entry((target, decl.field.clone())).or_default();
499 if !from.contains(&back_node) {
500 from.push(back_node);
501 }
502 f.ref_fwd.entry(node).or_default().push((fwd, target));
503 f.ref_back
504 .entry(target)
505 .or_default()
506 .push((back, back_node));
507 }
508 }
509 }
510 for decl in &self.model.rels {
517 let fwd = scope_role(&decl.target);
518 let back = scope_role(&decl.source);
519 for source in self.view_nodes(&decl.source, &defs) {
520 let cond = self.bind_driver(&decl.cond, source);
521 let query = format!("{}{}", decl.target, cond);
522 for target in self.view_nodes(&query, &defs) {
523 if target == source {
524 continue;
525 }
526 f.rel_fwd
527 .entry(source)
528 .or_default()
529 .push((fwd.clone(), target));
530 f.rel_back
531 .entry(target)
532 .or_default()
533 .push((back.clone(), source));
534 }
535 }
536 }
537 for decl in &self.model.edges {
545 let mut seen = std::collections::HashSet::new();
546 for node in self.scope_nodes(&decl.scope, &defs) {
547 let (Some(ends_a), Some(ends_b)) = (
548 reached.get(&(node, decl.field_a.clone())),
549 reached.get(&(node, decl.field_b.clone())),
550 ) else {
551 continue;
552 };
553 for (ra, na) in ends_a {
554 for (rb, nb) in ends_b {
555 if na != nb && seen.insert((*na, *nb)) {
556 f.edges.entry(*na).or_default().push((rb.clone(), *nb));
557 f.edges.entry(*nb).or_default().push((ra.clone(), *na));
558 }
559 }
560 }
561 }
562 }
563 f
564 })
565 }
566
567 fn scope_nodes(&self, scope: &str, defs: &quarb::Defs) -> Vec<NodeId> {
569 match quarb::run_with_defs(scope, defs, &self.base) {
570 Ok(QueryResult::Nodes(ns)) => ns,
571 _ => Vec::new(),
572 }
573 }
574
575 fn view_nodes(&self, path: &str, defs: &quarb::Defs) -> Vec<NodeId> {
580 let view = PriorView {
581 base: &self.base,
582 prior: self.containers(),
583 };
584 match quarb::run_with_defs(path, defs, &view) {
585 Ok(QueryResult::Nodes(ns)) => ns,
586 _ => Vec::new(),
587 }
588 }
589
590 fn bind_driver(&self, cond: &str, source: NodeId) -> String {
595 let view = PriorView {
596 base: &self.base,
597 prior: self.containers(),
598 };
599 let b: Vec<char> = cond.chars().collect();
600 let mut out = String::new();
601 let mut i = 0;
602 while i < b.len() {
603 match b[i] {
604 q @ ('\'' | '"') => {
605 out.push(q);
606 i += 1;
607 while i < b.len() && b[i] != q {
608 if b[i] == '\\' && i + 1 < b.len() {
609 out.push(b[i]);
610 i += 1;
611 }
612 out.push(b[i]);
613 i += 1;
614 }
615 if i < b.len() {
616 out.push(b[i]);
617 i += 1;
618 }
619 }
620 c @ ('$' | '_')
623 if (c == '$' && b.get(i + 1) == Some(&'$'))
624 || (c == '_'
625 && !(i > 0
626 && (b[i - 1].is_alphanumeric()
627 || b[i - 1] == '_'
628 || b[i - 1] == '-'))
629 && !b.get(i + 1).is_some_and(|c| {
630 c.is_alphanumeric() || *c == '_' || *c == '-'
631 })) =>
632 {
633 if c == '$' {
634 i += 2;
635 if b.get(i) == Some(&'_')
636 && !b
637 .get(i + 1)
638 .is_some_and(|c| c.is_alphanumeric() || *c == '_' || *c == '-')
639 {
640 i += 1;
641 }
642 } else {
643 i += 1;
644 }
645 let value = if b.get(i) == Some(&':') && b.get(i + 1) == Some(&':') {
646 i += 2;
647 let start = i;
648 while i < b.len() && (b[i].is_alphanumeric() || b[i] == '_' || b[i] == '-')
649 {
650 i += 1;
651 }
652 let field: String = b[start..i].iter().collect();
653 view.property(source, &field)
654 } else {
655 view.default_value(source)
656 };
657 out.push_str(&literal(value.unwrap_or(Value::Null)));
658 }
659 c => {
660 out.push(c);
661 i += 1;
662 }
663 }
664 }
665 out
666 }
667}
668
669fn literal(v: Value) -> String {
672 match v {
673 Value::Int(n) => n.to_string(),
674 Value::Float(f) => f.to_string(),
675 Value::Bool(b) => b.to_string(),
676 Value::Null => "''".to_string(),
677 other => format!(
678 "'{}'",
679 other.to_string().replace('\\', "\\\\").replace('\'', "\\'")
680 ),
681 }
682}
683
684struct PriorView<'a, A: AstAdapter> {
688 base: &'a A,
689 prior: &'a [Container],
690}
691
692impl<A: AstAdapter> AstAdapter for PriorView<'_, A> {
693 fn root(&self) -> NodeId {
694 self.base.root()
695 }
696 fn children(&self, node: NodeId) -> Vec<NodeId> {
697 if node.0 & MODEL_TAG != 0 {
698 let c = ((node.0 & !MODEL_TAG) >> CIDX_SHIFT) as usize;
699 let v = (node.0 & VAL_MASK) as usize;
700 if v == 0 && c < self.prior.len() {
701 return (0..self.prior[c].members.len())
702 .map(|i| NodeId(MODEL_TAG | (c as u64) << CIDX_SHIFT | (i as u64 + 1)))
703 .collect();
704 }
705 return Vec::new();
706 }
707 let mut kids = self.base.children(node);
708 if node == self.base.root() {
709 for c in 0..self.prior.len() {
710 kids.push(NodeId(MODEL_TAG | (c as u64) << CIDX_SHIFT));
711 }
712 }
713 kids
714 }
715 fn name(&self, node: NodeId) -> Option<String> {
716 if node.0 & MODEL_TAG != 0 {
717 let c = ((node.0 & !MODEL_TAG) >> CIDX_SHIFT) as usize;
718 let v = (node.0 & VAL_MASK) as usize;
719 let cont = self.prior.get(c)?;
720 return Some(if v == 0 {
723 cont.name.clone()
724 } else {
725 cont.role_of(v).to_string()
726 });
727 }
728 self.base.name(node)
729 }
730 fn children_named(&self, node: NodeId, name: &str) -> Vec<NodeId> {
731 if node == self.base.root() {
732 let mut out = self.base.children_named(node, name);
733 if let Some(c) = self.prior.iter().position(|k| k.name == name) {
734 out.push(NodeId(MODEL_TAG | (c as u64) << CIDX_SHIFT));
735 }
736 return out;
737 }
738 if node.0 & MODEL_TAG != 0 {
739 let c = ((node.0 & !MODEL_TAG) >> CIDX_SHIFT) as usize;
740 let v = (node.0 & VAL_MASK) as usize;
741 let Some(cont) = self.prior.get(c) else {
742 return Vec::new();
743 };
744 if v == 0 {
745 return cont
746 .of_role(name)
747 .map(|i| NodeId(MODEL_TAG | (c as u64) << CIDX_SHIFT | (i as u64 + 1)))
748 .collect();
749 }
750 return Vec::new();
751 }
752 self.base.children_named(node, name)
753 }
754 fn traits(&self, node: NodeId) -> Vec<String> {
755 if node.0 & MODEL_TAG != 0 {
756 let c = ((node.0 & !MODEL_TAG) >> CIDX_SHIFT) as usize;
757 let v = (node.0 & VAL_MASK) as usize;
758 return match self.prior.get(c) {
759 Some(cont) if v > 0 => vec![cont.trait_of(v).to_string()],
760 _ => Vec::new(),
761 };
762 }
763 self.base.traits(node)
764 }
765 fn parent(&self, node: NodeId) -> Option<NodeId> {
766 if node.0 & MODEL_TAG != 0 {
767 let c = ((node.0 & !MODEL_TAG) >> CIDX_SHIFT) as usize;
768 let v = (node.0 & VAL_MASK) as usize;
769 return Some(if v == 0 {
770 self.base.root()
771 } else {
772 NodeId(MODEL_TAG | (c as u64) << CIDX_SHIFT)
773 });
774 }
775 self.base.parent(node)
776 }
777 fn property(&self, node: NodeId, name: &str) -> Option<Value> {
778 if node.0 & MODEL_TAG != 0 {
779 let c = ((node.0 & !MODEL_TAG) >> CIDX_SHIFT) as usize;
780 let v = (node.0 & VAL_MASK) as usize;
781 return match self.prior.get(c)?.member(v)? {
782 Member::Value(_) => None,
785 Member::Node(n) => self.base.property(n, name),
786 };
787 }
788 self.base.property(node, name)
789 }
790 fn default_value(&self, node: NodeId) -> Option<Value> {
791 if node.0 & MODEL_TAG != 0 {
792 let c = ((node.0 & !MODEL_TAG) >> CIDX_SHIFT) as usize;
793 let v = (node.0 & VAL_MASK) as usize;
794 return match self.prior.get(c)?.member(v)? {
795 Member::Value(val) => Some(val),
796 Member::Node(n) => self.base.default_value(n),
797 };
798 }
799 self.base.default_value(node)
800 }
801 fn document_by_ref(&self, id: &str) -> Option<NodeId> {
805 self.base.document_by_ref(id)
806 }
807 fn descendants_named(&self, node: NodeId, name: &str) -> Option<Vec<(NodeId, usize)>> {
808 if node.0 & MODEL_TAG != 0 || node == self.base.root() {
809 return None;
810 }
811 self.base.descendants_named(node, name)
812 }
813 fn prefetch_links(&self, nodes: &[NodeId], dir: quarb::LinkDir) {
814 let base: Vec<NodeId> = nodes
815 .iter()
816 .copied()
817 .filter(|n| n.0 & MODEL_TAG == 0)
818 .collect();
819 if !base.is_empty() {
820 self.base.prefetch_links(&base, dir);
821 }
822 }
823 fn provenance(&self, node: NodeId) -> quarb::Provenance {
824 if node.0 & MODEL_TAG != 0 {
825 return quarb::Provenance::default();
826 }
827 self.base.provenance(node)
828 }
829 fn provenance_list(&self, node: NodeId) -> quarb::ProvenanceList {
830 if node.0 & MODEL_TAG != 0 {
831 return quarb::ProvenanceList::default();
832 }
833 self.base.provenance_list(node)
834 }
835}
836
837impl<A: AstAdapter> AstAdapter for ModelAdapter<A> {
838 fn root(&self) -> NodeId {
839 self.base.root()
840 }
841
842 fn children(&self, node: NodeId) -> Vec<NodeId> {
843 match self.decode(node) {
844 Some((c, 0)) => (0..self.containers()[c].members.len())
846 .map(|v| Self::value_node(c, v))
847 .collect(),
848 Some(_) => match self.aliased(node) {
851 Some(base) => self.base.children(base),
852 None => Vec::new(),
853 },
854 None => {
857 let mut kids = self.base.children(node);
858 if node == self.base.root() {
859 for c in 0..self.containers().len() {
860 kids.push(Self::container_node(c));
861 }
862 }
863 kids
864 }
865 }
866 }
867
868 fn children_named(&self, node: NodeId, name: &str) -> Vec<NodeId> {
869 if node == self.base.root() {
871 let mut out = self.base.children_named(node, name);
872 if let Some(c) = self.container_by_name(name) {
873 out.push(Self::container_node(c));
874 }
875 return out;
876 }
877 match self.decode(node) {
878 Some((c, 0)) => self.containers()[c]
881 .of_role(name)
882 .map(|i| Self::value_node(c, i))
883 .collect(),
884 Some(_) => match self.aliased(node) {
885 Some(base) => self.base.children_named(base, name),
886 None => Vec::new(),
887 },
888 None => self.base.children_named(node, name),
889 }
890 }
891
892 fn name(&self, node: NodeId) -> Option<String> {
893 match self.decode(node) {
894 Some((c, 0)) => Some(self.containers()[c].name.clone()),
895 Some((c, v)) => Some(self.containers()[c].role_of(v).to_string()),
899 None => self.base.name(node),
900 }
901 }
902
903 fn parent(&self, node: NodeId) -> Option<NodeId> {
904 match self.decode(node) {
905 Some((_, 0)) => Some(self.base.root()),
906 Some((c, _)) => Some(Self::container_node(c)),
907 None => self.base.parent(node),
908 }
909 }
910
911 fn traits(&self, node: NodeId) -> Vec<String> {
912 match self.decode(node) {
913 Some((c, v)) if v > 0 => {
916 let mut out = vec![self.containers()[c].trait_of(v).to_string()];
917 if let Some(base) = self.aliased(node) {
920 out.extend(self.base.traits(base));
921 }
922 out
923 }
924 Some(_) => Vec::new(),
925 None => self.base.traits(node),
926 }
927 }
928
929 fn property(&self, node: NodeId, name: &str) -> Option<Value> {
930 match self.decode(node) {
931 Some((_, v)) if v > 0 => match self.aliased(node) {
937 Some(base) => self.base.property(base, name),
938 None => None,
939 },
940 Some(_) => None,
941 None => self.base.property(node, name),
942 }
943 }
944
945 fn default_value(&self, node: NodeId) -> Option<Value> {
946 match self.decode(node) {
947 Some((_, v)) if v > 0 => match self.aliased(node) {
948 Some(base) => self.base.default_value(base),
949 None => self.elevated(node),
950 },
951 Some(_) => None,
952 None => self.base.default_value(node),
953 }
954 }
955
956 fn metadata(&self, node: NodeId, key: &str) -> Option<Value> {
957 match self.decode(node) {
958 Some((c, 0)) if key == "n-rows" => {
959 Some(Value::Int(self.containers()[c].members.len() as i64))
960 }
961 Some(_) => None,
962 None => self.base.metadata(node, key),
963 }
964 }
965
966 fn aliased_metadata(&self, node: NodeId) -> &'static [&'static str] {
969 self.base.aliased_metadata(node)
970 }
971
972 fn provenance(&self, node: NodeId) -> quarb::Provenance {
979 match self.decode(node) {
980 Some((c, _)) => match self.aliased(node) {
981 Some(base) => self.base.provenance(base),
982 None => quarb::Provenance {
983 source: Some(format!("model:/{}", self.containers()[c].name)),
984 ..Default::default()
985 },
986 },
987 None => self.base.provenance(node),
988 }
989 }
990 fn provenance_list(&self, node: NodeId) -> quarb::ProvenanceList {
991 match self.decode(node) {
992 Some((_, _)) => match self.aliased(node) {
993 Some(base) => self.base.provenance_list(base),
994 None => quarb::ProvenanceList::single(self.provenance(node)),
995 },
996 None => self.base.provenance_list(node),
997 }
998 }
999
1000 fn answers_to(&self, node: NodeId, name: &str) -> bool {
1003 if self.decode(node).is_none() && self.base.answers_to(node, name) {
1004 return true;
1005 }
1006 let Some(canonical) = self.name(node) else {
1007 return canonical_none(name);
1008 };
1009 if canonical == name {
1010 return true;
1011 }
1012 let aliases = self
1013 .model
1014 .aliases
1015 .iter()
1016 .filter(|a| a.kind == AliasKind::Name);
1017 for a in aliases {
1018 if a.admits(name, &canonical) {
1019 return true;
1020 }
1021 if self.decode(node).is_none()
1025 && let AliasRule::Exact { alias, original } = &a.rule
1026 && alias == name
1027 && self.base.answers_to(node, original)
1028 {
1029 return true;
1030 }
1031 }
1032 false
1033 }
1034
1035 fn has_trait(&self, node: NodeId, name: &str) -> bool {
1038 let traits = self.traits(node);
1039 if traits.iter().any(|t| t == name) {
1040 return true;
1041 }
1042 self.model
1043 .aliases
1044 .iter()
1045 .filter(|a| a.kind == AliasKind::Trait)
1046 .any(|a| traits.iter().any(|t| a.admits(name, t)))
1047 }
1048
1049 fn resolve(&self, node: NodeId, property: &str, hint: Option<&str>) -> Option<NodeId> {
1050 let under = self.aliased(node).unwrap_or(node);
1052 if let Some(&target) = self.fabric().resolve.get(&(under, property.to_string())) {
1053 return Some(target);
1054 }
1055 if self.decode(under).is_none() {
1056 return self.base.resolve(under, property, hint);
1057 }
1058 None
1063 }
1064
1065 fn external_ref(&self, node: NodeId, property: &str, hint: Option<&str>) -> Option<String> {
1066 let under = self.aliased(node).unwrap_or(node);
1070 if self.decode(under).is_none() {
1071 return self.base.external_ref(under, property, hint);
1072 }
1073 None
1074 }
1075
1076 fn resolve_fragment(&self, node: NodeId, fragment: &str) -> Option<NodeId> {
1077 let under = self.aliased(node).unwrap_or(node);
1078 if self.decode(under).is_none() {
1079 return self.base.resolve_fragment(under, fragment);
1080 }
1081 None
1082 }
1083
1084 fn ref_property(&self, node: NodeId) -> Option<String> {
1085 let under = self.aliased(node).unwrap_or(node);
1086 if self.decode(under).is_none() {
1087 return self.base.ref_property(under);
1088 }
1089 None
1090 }
1091
1092 fn ref_label(&self, node: NodeId, property: &str) -> Option<String> {
1093 let under = self.aliased(node).unwrap_or(node);
1094 if self.decode(under).is_none() {
1095 return self.base.ref_label(under, property);
1096 }
1097 None
1098 }
1099
1100 fn links(&self, node: NodeId) -> Vec<(String, NodeId)> {
1101 let f = self.fabric();
1102 match self.decode(node) {
1103 Some((_, v)) if v > 0 => {
1106 let mut out = f.edges.get(&node).cloned().unwrap_or_default();
1107 if let Some(rels) = f.rel_fwd.get(&node) {
1108 out.extend(rels.iter().cloned());
1109 }
1110 if let Some(base) = self.aliased(node) {
1111 out.extend(self.base.links(base));
1112 if let Some(refs) = f.ref_fwd.get(&base) {
1113 out.extend(refs.iter().cloned());
1114 }
1115 }
1116 out
1117 }
1118 Some(_) => Vec::new(),
1119 None => {
1122 let mut out = self.base.links(node);
1123 if let Some(refs) = f.ref_fwd.get(&node) {
1124 out.extend(refs.iter().cloned());
1125 }
1126 if let Some(rels) = f.rel_fwd.get(&node) {
1127 out.extend(rels.iter().cloned());
1128 }
1129 out
1130 }
1131 }
1132 }
1133
1134 fn backlinks(&self, node: NodeId) -> Vec<(String, NodeId)> {
1135 let f = self.fabric();
1136 match self.decode(node) {
1137 Some((_, v)) if v > 0 => {
1141 let mut out = f.ref_back.get(&node).cloned().unwrap_or_default();
1142 if let Some(e) = f.edges.get(&node) {
1143 out.extend(e.iter().cloned());
1144 }
1145 if let Some(rels) = f.rel_back.get(&node) {
1146 out.extend(rels.iter().cloned());
1147 }
1148 out
1149 }
1150 Some(_) => Vec::new(),
1151 None => {
1155 let mut out = self.base.backlinks(node);
1156 if let Some(refs) = f.ref_back.get(&node) {
1157 out.extend(refs.iter().cloned());
1158 }
1159 if let Some(rels) = f.rel_back.get(&node) {
1160 out.extend(rels.iter().cloned());
1161 }
1162 out
1163 }
1164 }
1165 }
1166
1167 fn document_by_ref(&self, id: &str) -> Option<NodeId> {
1170 self.base.document_by_ref(id)
1171 }
1172
1173 fn reverse_resolve(
1177 &self,
1178 node: NodeId,
1179 property: Option<&str>,
1180 hint: Option<&str>,
1181 ) -> Option<Vec<NodeId>> {
1182 if let Some(field) = property
1186 && self.model.refs.iter().any(|r| r.field == field)
1187 {
1188 let f = self.fabric();
1189 let target = f.alias.get(&node).map_or(node, |(alias, _)| *alias);
1190 let mut out = f
1191 .sources
1192 .get(&(target, field.to_string()))
1193 .cloned()
1194 .unwrap_or_default();
1195 if target != node
1196 && let Some(more) = f.sources.get(&(node, field.to_string()))
1197 {
1198 for n in more {
1199 if !out.contains(n) {
1200 out.push(*n);
1201 }
1202 }
1203 }
1204 return Some(out);
1205 }
1206 if self.decode(node).is_some()
1207 || !self.model.refs.is_empty()
1208 || !self.model.rels.is_empty()
1209 || !self.model.edges.is_empty()
1210 {
1211 return None;
1212 }
1213 self.base.reverse_resolve(node, property, hint)
1214 }
1215
1216 fn descendants_named(&self, node: NodeId, name: &str) -> Option<Vec<(NodeId, usize)>> {
1220 if self.decode(node).is_some()
1221 || node == self.base.root()
1222 || self.model.aliases.iter().any(|a| a.kind == AliasKind::Name)
1223 {
1224 return None;
1225 }
1226 self.base.descendants_named(node, name)
1227 }
1228
1229 fn prefetch_links(&self, nodes: &[NodeId], dir: quarb::LinkDir) {
1230 let base: Vec<NodeId> = nodes
1231 .iter()
1232 .copied()
1233 .filter(|n| self.decode(*n).is_none())
1234 .collect();
1235 if !base.is_empty() {
1236 self.base.prefetch_links(&base, dir);
1237 }
1238 }
1239
1240 fn quantifier_bound(&self) -> usize {
1241 self.base.quantifier_bound()
1242 }
1243 fn allow_shell(&self) -> bool {
1244 self.base.allow_shell()
1245 }
1246 fn invocation_instant(&self) -> Option<(i64, u32)> {
1247 self.base.invocation_instant()
1248 }
1249 fn unit_scale(&self, expr: &str) -> Option<(f64, String)> {
1250 self.base.unit_scale(expr)
1251 }
1252}
1253
1254fn canonical_none(_name: &str) -> bool {
1256 false
1257}
1258
1259fn scope_role(scope: &str) -> String {
1265 scope
1266 .split('/')
1267 .filter(|seg| {
1268 !seg.is_empty()
1269 && !seg.starts_with('*')
1270 && !seg.starts_with('[')
1271 && !seg.chars().next().is_some_and(|c| c.is_ascii_digit())
1272 })
1273 .next_back()
1274 .unwrap_or("")
1275 .split(['[', ':'])
1276 .next()
1277 .unwrap_or("")
1278 .to_string()
1279}
1280
1281pub struct Borrowed<'a>(pub &'a dyn AstAdapter);
1287
1288impl AstAdapter for Borrowed<'_> {
1289 fn root(&self) -> NodeId {
1290 self.0.root()
1291 }
1292 fn children(&self, n: NodeId) -> Vec<NodeId> {
1293 self.0.children(n)
1294 }
1295 fn name(&self, n: NodeId) -> Option<String> {
1296 self.0.name(n)
1297 }
1298
1299 fn answers_to(&self, n: NodeId, name: &str) -> bool {
1302 self.0.answers_to(n, name)
1303 }
1304
1305 fn has_trait(&self, n: NodeId, name: &str) -> bool {
1306 self.0.has_trait(n, name)
1307 }
1308 fn parent(&self, n: NodeId) -> Option<NodeId> {
1309 self.0.parent(n)
1310 }
1311 fn traits(&self, n: NodeId) -> Vec<String> {
1312 self.0.traits(n)
1313 }
1314 fn children_named(&self, n: NodeId, name: &str) -> Vec<NodeId> {
1315 self.0.children_named(n, name)
1316 }
1317 fn property(&self, n: NodeId, name: &str) -> Option<Value> {
1318 self.0.property(n, name)
1319 }
1320 fn default_value(&self, n: NodeId) -> Option<Value> {
1321 self.0.default_value(n)
1322 }
1323 fn metadata(&self, n: NodeId, key: &str) -> Option<Value> {
1324 self.0.metadata(n, key)
1325 }
1326 fn links(&self, n: NodeId) -> Vec<(String, NodeId)> {
1327 self.0.links(n)
1328 }
1329 fn backlinks(&self, n: NodeId) -> Vec<(String, NodeId)> {
1330 self.0.backlinks(n)
1331 }
1332 fn resolve(&self, n: NodeId, p: &str, h: Option<&str>) -> Option<NodeId> {
1333 self.0.resolve(n, p, h)
1334 }
1335 fn external_ref(&self, n: NodeId, p: &str, h: Option<&str>) -> Option<String> {
1336 self.0.external_ref(n, p, h)
1337 }
1338 fn resolve_fragment(&self, n: NodeId, f: &str) -> Option<NodeId> {
1339 self.0.resolve_fragment(n, f)
1340 }
1341 fn ref_property(&self, n: NodeId) -> Option<String> {
1342 self.0.ref_property(n)
1343 }
1344 fn ref_label(&self, n: NodeId, p: &str) -> Option<String> {
1345 self.0.ref_label(n, p)
1346 }
1347 fn link_property(&self, s: NodeId, l: &str, t: NodeId, name: &str) -> Option<Value> {
1348 self.0.link_property(s, l, t, name)
1349 }
1350 fn document_by_ref(&self, id: &str) -> Option<NodeId> {
1351 self.0.document_by_ref(id)
1352 }
1353 fn reverse_resolve(&self, n: NodeId, p: Option<&str>, h: Option<&str>) -> Option<Vec<NodeId>> {
1354 self.0.reverse_resolve(n, p, h)
1355 }
1356 fn descendants_named(&self, n: NodeId, name: &str) -> Option<Vec<(NodeId, usize)>> {
1357 self.0.descendants_named(n, name)
1358 }
1359 fn prefetch_links(&self, nodes: &[NodeId], dir: quarb::LinkDir) {
1360 self.0.prefetch_links(nodes, dir)
1361 }
1362 fn quantifier_bound(&self) -> usize {
1363 self.0.quantifier_bound()
1364 }
1365 fn allow_shell(&self) -> bool {
1366 self.0.allow_shell()
1367 }
1368 fn invocation_instant(&self) -> Option<(i64, u32)> {
1369 self.0.invocation_instant()
1370 }
1371 fn provenance(&self, n: NodeId) -> quarb::Provenance {
1372 self.0.provenance(n)
1373 }
1374 fn provenance_list(&self, n: NodeId) -> quarb::ProvenanceList {
1375 self.0.provenance_list(n)
1376 }
1377 fn unit_scale(&self, expr: &str) -> Option<(f64, String)> {
1378 self.0.unit_scale(expr)
1379 }
1380}