1mod parse;
18
19pub use parse::{
20 parse_model, resolve_mount_target, EdgeDecl, Model, Mount, NodeDecl, RefDecl, RelDecl,
21};
22
23use quarb::{AstAdapter, NodeId, QueryResult, Value};
24use std::cell::OnceCell;
25use std::collections::HashMap;
26
27const MODEL_TAG: u64 = 1 << 63;
32const CIDX_SHIFT: u64 = 44;
33const VAL_MASK: u64 = (1 << CIDX_SHIFT) - 1;
34
35enum Members {
39 Values(Vec<Value>),
42 Nodes(Vec<NodeId>),
47}
48
49impl Members {
50 fn len(&self) -> usize {
51 match self {
52 Members::Values(v) => v.len(),
53 Members::Nodes(n) => n.len(),
54 }
55 }
56}
57
58struct Container {
60 name: String,
61 role: String,
64 trait_name: String,
66 members: Members,
70 by_str: HashMap<String, usize>,
72}
73
74enum Member {
76 Value(Value),
77 Node(NodeId),
78}
79
80impl Container {
81 fn member(&self, v: usize) -> Option<Member> {
83 if v == 0 {
84 return None;
85 }
86 match &self.members {
87 Members::Values(vs) => vs.get(v - 1).cloned().map(Member::Value),
88 Members::Nodes(ns) => ns.get(v - 1).copied().map(Member::Node),
89 }
90 }
91}
92
93struct Fabric {
96 alias: HashMap<NodeId, (NodeId, String)>,
101 resolve: HashMap<(NodeId, String), NodeId>,
103 ref_back: HashMap<NodeId, Vec<(String, NodeId)>>,
106 ref_fwd: HashMap<NodeId, Vec<(String, NodeId)>>,
108 rel_fwd: HashMap<NodeId, Vec<(String, NodeId)>>,
112 rel_back: HashMap<NodeId, Vec<(String, NodeId)>>,
113 edges: HashMap<NodeId, Vec<(String, NodeId)>>,
117}
118
119pub struct ModelAdapter<A: AstAdapter> {
121 base: A,
122 model: Model,
123 containers: OnceCell<Vec<Container>>,
124 fabric: OnceCell<Fabric>,
125}
126
127impl<A: AstAdapter> ModelAdapter<A> {
128 pub fn new(base: A, model: Model) -> Self {
129 ModelAdapter {
130 base,
131 model,
132 containers: OnceCell::new(),
133 fabric: OnceCell::new(),
134 }
135 }
136
137 pub fn base(&self) -> &A {
138 &self.base
139 }
140
141 pub fn locator(&self, node: NodeId, base_locator: impl Fn(NodeId) -> String) -> String {
144 match self.decode(node) {
145 None => base_locator(node),
146 Some((c, 0)) => format!("/{}", self.containers()[c].name),
147 Some((c, v)) => {
148 let cont = &self.containers()[c];
151 format!("/{}/{}[{}]", cont.name, cont.role, v)
152 }
153 }
154 }
155
156 fn seeded_defs(&self) -> quarb::Defs {
157 quarb::parse_defs(&self.model.defs_text).unwrap_or_default()
158 }
159
160 fn containers(&self) -> &[Container] {
165 self.containers.get_or_init(|| {
166 let defs = self.seeded_defs();
167 let mut built: Vec<Container> = Vec::new();
168 for decl in &self.model.nodes {
169 let members = self.members(&decl.query, &defs, &built);
170 let by_str = match &members {
171 Members::Values(vs) => vs
172 .iter()
173 .enumerate()
174 .map(|(i, v)| (v.to_string(), i))
175 .collect(),
176 Members::Nodes(ns) => ns
180 .iter()
181 .enumerate()
182 .filter_map(|(i, n)| self.base_key(*n).map(|k| (k, i)))
183 .collect(),
184 };
185 built.push(Container {
186 name: decl.name.clone(),
187 role: decl.role.clone(),
188 trait_name: decl.trait_name.clone(),
189 members,
190 by_str,
191 });
192 }
193 built
194 })
195 }
196
197 fn members(&self, query: &str, defs: &quarb::Defs, prior: &[Container]) -> Members {
204 let result = if prior.is_empty() {
208 quarb::run_with_defs(query, defs, &self.base)
209 } else {
210 let scratch = PriorView {
211 base: &self.base,
212 prior,
213 };
214 quarb::run_with_defs(query, defs, &scratch)
215 };
216 match result {
217 Ok(QueryResult::Values(vs)) => {
218 let mut seen = std::collections::HashSet::new();
219 Members::Values(vs.into_iter().filter(|v| seen.insert(v.to_string())).collect())
220 }
221 Ok(QueryResult::Nodes(ns)) => {
222 let mut seen = std::collections::HashSet::new();
223 Members::Nodes(ns.into_iter().filter(|n| seen.insert(*n)).collect())
224 }
225 Err(_) => Members::Values(Vec::new()),
226 }
227 }
228
229 fn base_key(&self, node: NodeId) -> Option<String> {
232 self.base
233 .default_value(node)
234 .map(|v| v.to_string())
235 .or_else(|| self.base.name(node))
236 }
237
238 fn aliased(&self, node: NodeId) -> Option<NodeId> {
240 match self.decode(node) {
241 Some((c, v)) if v > 0 => match &self.containers()[c].members {
242 Members::Nodes(ns) => ns.get(v - 1).copied(),
243 Members::Values(_) => None,
244 },
245 _ => None,
246 }
247 }
248
249 fn elevated(&self, node: NodeId) -> Option<Value> {
251 match self.decode(node) {
252 Some((c, v)) if v > 0 => match &self.containers()[c].members {
253 Members::Values(vs) => vs.get(v - 1).cloned(),
254 Members::Nodes(_) => None,
255 },
256 _ => None,
257 }
258 }
259
260 fn container_node(c: usize) -> NodeId {
261 NodeId(MODEL_TAG | (c as u64) << CIDX_SHIFT)
262 }
263
264 fn value_node(c: usize, v: usize) -> NodeId {
265 NodeId(MODEL_TAG | (c as u64) << CIDX_SHIFT | (v as u64 + 1))
266 }
267
268 fn decode(&self, node: NodeId) -> Option<(usize, usize)> {
272 if node.0 & MODEL_TAG == 0 {
273 return None;
274 }
275 let c = ((node.0 & !MODEL_TAG) >> CIDX_SHIFT) as usize;
276 let v = (node.0 & VAL_MASK) as usize;
277 (c < self.containers().len()).then_some((c, v))
278 }
279
280 fn container_by_name(&self, name: &str) -> Option<usize> {
281 self.containers().iter().position(|c| c.name == name)
282 }
283
284 fn find_value(&self, container: usize, value: &Value) -> Option<NodeId> {
286 let idx = *self.containers()[container].by_str.get(&value.to_string())?;
287 Some(Self::value_node(container, idx))
288 }
289
290 fn fabric(&self) -> &Fabric {
292 self.fabric.get_or_init(|| {
293 let defs = self.seeded_defs();
294 let mut f = Fabric {
295 alias: HashMap::new(),
296 resolve: HashMap::new(),
297 ref_back: HashMap::new(),
298 ref_fwd: HashMap::new(),
299 rel_fwd: HashMap::new(),
300 rel_back: HashMap::new(),
301 edges: HashMap::new(),
302 };
303 for (c, cont) in self.containers().iter().enumerate() {
304 if let Members::Nodes(ns) = &cont.members {
305 for (i, n) in ns.iter().enumerate() {
306 f.alias
307 .entry(*n)
308 .or_insert((Self::value_node(c, i), cont.role.clone()));
309 }
310 }
311 }
312 for decl in &self.model.refs {
315 let Some(container) = self.container_by_name(&decl.container) else {
316 continue;
317 };
318 let by_key: Option<HashMap<String, NodeId>> =
322 decl.key_field.as_deref().map(|f| {
323 (1..=self.containers()[container].members.len())
324 .filter_map(|v| {
325 let n = Self::value_node(container, v - 1);
326 self.property(n, f).map(|k| (k.to_string(), n))
327 })
328 .collect()
329 });
330 for node in self.scope_nodes(&decl.scope, &defs) {
331 let Some(value) = self.base.property(node, &decl.field) else {
332 continue;
333 };
334 if matches!(value, Value::Null) {
335 continue;
336 }
337 let target = match &by_key {
338 Some(idx) => idx.get(&value.to_string()).copied(),
339 None => self.find_value(container, &value),
340 };
341 let Some(target) = target else {
342 continue;
343 };
344 let fwd = self.containers()[container].role.clone();
352 let (back_node, back) = match f.alias.get(&node) {
356 Some((alias, role)) => (*alias, role.clone()),
357 None => (node, scope_role(&decl.scope)),
358 };
359 f.resolve.insert((node, decl.field.clone()), target);
360 f.ref_fwd.entry(node).or_default().push((fwd, target));
361 f.ref_back.entry(target).or_default().push((back, back_node));
362 }
363 }
364 for decl in &self.model.rels {
371 let fwd = scope_role(&decl.target);
372 let back = scope_role(&decl.source);
373 for source in self.view_nodes(&decl.source, &defs) {
374 let cond = self.bind_driver(&decl.cond, source);
375 let query = format!("{}{}", decl.target, cond);
376 for target in self.view_nodes(&query, &defs) {
377 if target == source {
378 continue;
379 }
380 f.rel_fwd
381 .entry(source)
382 .or_default()
383 .push((fwd.clone(), target));
384 f.rel_back
385 .entry(target)
386 .or_default()
387 .push((back.clone(), source));
388 }
389 }
390 }
391 for decl in &self.model.edges {
395 let ca = self.field_container(&decl.field_a);
396 let cb = self.field_container(&decl.field_b);
397 let (Some((ca, la)), Some((cb, lb))) = (ca, cb) else {
398 continue;
399 };
400 let mut seen = std::collections::HashSet::new();
401 for node in self.scope_nodes(&decl.scope, &defs) {
402 let (Some(va), Some(vb)) = (
403 self.base.property(node, &decl.field_a),
404 self.base.property(node, &decl.field_b),
405 ) else {
406 continue;
407 };
408 if matches!(va, Value::Null) || matches!(vb, Value::Null) {
409 continue;
410 }
411 let (Some(na), Some(nb)) =
412 (self.find_value(ca, &va), self.find_value(cb, &vb))
413 else {
414 continue;
415 };
416 if seen.insert((na, nb)) {
417 f.edges.entry(na).or_default().push((lb.clone(), nb));
418 f.edges.entry(nb).or_default().push((la.clone(), na));
419 }
420 }
421 }
422 f
423 })
424 }
425
426 fn field_container(&self, field: &str) -> Option<(usize, String)> {
431 let decl = self.model.refs.iter().find(|r| r.field == field)?;
432 let c = self.container_by_name(&decl.container)?;
433 Some((c, self.containers()[c].role.clone()))
434 }
435
436 fn scope_nodes(&self, scope: &str, defs: &quarb::Defs) -> Vec<NodeId> {
438 match quarb::run_with_defs(scope, defs, &self.base) {
439 Ok(QueryResult::Nodes(ns)) => ns,
440 _ => Vec::new(),
441 }
442 }
443
444 fn view_nodes(&self, path: &str, defs: &quarb::Defs) -> Vec<NodeId> {
449 let view = PriorView {
450 base: &self.base,
451 prior: self.containers(),
452 };
453 match quarb::run_with_defs(path, defs, &view) {
454 Ok(QueryResult::Nodes(ns)) => ns,
455 _ => Vec::new(),
456 }
457 }
458
459 fn bind_driver(&self, cond: &str, source: NodeId) -> String {
464 let view = PriorView {
465 base: &self.base,
466 prior: self.containers(),
467 };
468 let b: Vec<char> = cond.chars().collect();
469 let mut out = String::new();
470 let mut i = 0;
471 while i < b.len() {
472 match b[i] {
473 q @ ('\'' | '"') => {
474 out.push(q);
475 i += 1;
476 while i < b.len() && b[i] != q {
477 if b[i] == '\\' && i + 1 < b.len() {
478 out.push(b[i]);
479 i += 1;
480 }
481 out.push(b[i]);
482 i += 1;
483 }
484 if i < b.len() {
485 out.push(b[i]);
486 i += 1;
487 }
488 }
489 '$' if b.get(i + 1) == Some(&'$') => {
490 i += 2;
491 let value = if b.get(i) == Some(&':') && b.get(i + 1) == Some(&':') {
492 i += 2;
493 let start = i;
494 while i < b.len()
495 && (b[i].is_alphanumeric() || b[i] == '_' || b[i] == '-')
496 {
497 i += 1;
498 }
499 let field: String = b[start..i].iter().collect();
500 view.property(source, &field)
501 } else {
502 view.default_value(source)
503 };
504 out.push_str(&literal(value.unwrap_or(Value::Null)));
505 }
506 c => {
507 out.push(c);
508 i += 1;
509 }
510 }
511 }
512 out
513 }
514}
515
516fn literal(v: Value) -> String {
519 match v {
520 Value::Int(n) => n.to_string(),
521 Value::Float(f) => f.to_string(),
522 Value::Bool(b) => b.to_string(),
523 Value::Null => "''".to_string(),
524 other => format!("'{}'", other.to_string().replace('\\', "\\\\").replace('\'', "\\'")),
525 }
526}
527
528struct PriorView<'a, A: AstAdapter> {
532 base: &'a A,
533 prior: &'a [Container],
534}
535
536impl<A: AstAdapter> AstAdapter for PriorView<'_, A> {
537 fn root(&self) -> NodeId {
538 self.base.root()
539 }
540 fn children(&self, node: NodeId) -> Vec<NodeId> {
541 if node.0 & MODEL_TAG != 0 {
542 let c = ((node.0 & !MODEL_TAG) >> CIDX_SHIFT) as usize;
543 let v = (node.0 & VAL_MASK) as usize;
544 if v == 0 && c < self.prior.len() {
545 return (0..self.prior[c].members.len())
546 .map(|i| NodeId(MODEL_TAG | (c as u64) << CIDX_SHIFT | (i as u64 + 1)))
547 .collect();
548 }
549 return Vec::new();
550 }
551 let mut kids = self.base.children(node);
552 if node == self.base.root() {
553 for c in 0..self.prior.len() {
554 kids.push(NodeId(MODEL_TAG | (c as u64) << CIDX_SHIFT));
555 }
556 }
557 kids
558 }
559 fn name(&self, node: NodeId) -> Option<String> {
560 if node.0 & MODEL_TAG != 0 {
561 let c = ((node.0 & !MODEL_TAG) >> CIDX_SHIFT) as usize;
562 let v = (node.0 & VAL_MASK) as usize;
563 let cont = self.prior.get(c)?;
564 return Some(if v == 0 {
567 cont.name.clone()
568 } else {
569 cont.role.clone()
570 });
571 }
572 self.base.name(node)
573 }
574 fn children_named(&self, node: NodeId, name: &str) -> Vec<NodeId> {
575 if node == self.base.root() {
576 let mut out = self.base.children_named(node, name);
577 if let Some(c) = self.prior.iter().position(|k| k.name == name) {
578 out.push(NodeId(MODEL_TAG | (c as u64) << CIDX_SHIFT));
579 }
580 return out;
581 }
582 if node.0 & MODEL_TAG != 0 {
583 let c = ((node.0 & !MODEL_TAG) >> CIDX_SHIFT) as usize;
584 let v = (node.0 & VAL_MASK) as usize;
585 let Some(cont) = self.prior.get(c) else {
586 return Vec::new();
587 };
588 if v == 0 && name == cont.role {
589 return (0..cont.members.len())
590 .map(|i| NodeId(MODEL_TAG | (c as u64) << CIDX_SHIFT | (i as u64 + 1)))
591 .collect();
592 }
593 return Vec::new();
594 }
595 self.base.children_named(node, name)
596 }
597 fn traits(&self, node: NodeId) -> Vec<String> {
598 if node.0 & MODEL_TAG != 0 {
599 let c = ((node.0 & !MODEL_TAG) >> CIDX_SHIFT) as usize;
600 let v = (node.0 & VAL_MASK) as usize;
601 return match self.prior.get(c) {
602 Some(cont) if v > 0 => vec![cont.trait_name.clone()],
603 _ => Vec::new(),
604 };
605 }
606 self.base.traits(node)
607 }
608 fn parent(&self, node: NodeId) -> Option<NodeId> {
609 if node.0 & MODEL_TAG != 0 {
610 let c = ((node.0 & !MODEL_TAG) >> CIDX_SHIFT) as usize;
611 let v = (node.0 & VAL_MASK) as usize;
612 return Some(if v == 0 {
613 self.base.root()
614 } else {
615 NodeId(MODEL_TAG | (c as u64) << CIDX_SHIFT)
616 });
617 }
618 self.base.parent(node)
619 }
620 fn property(&self, node: NodeId, name: &str) -> Option<Value> {
621 if node.0 & MODEL_TAG != 0 {
622 let c = ((node.0 & !MODEL_TAG) >> CIDX_SHIFT) as usize;
623 let v = (node.0 & VAL_MASK) as usize;
624 return match self.prior.get(c)?.member(v)? {
625 Member::Value(_) => None,
628 Member::Node(n) => self.base.property(n, name),
629 };
630 }
631 self.base.property(node, name)
632 }
633 fn default_value(&self, node: NodeId) -> Option<Value> {
634 if node.0 & MODEL_TAG != 0 {
635 let c = ((node.0 & !MODEL_TAG) >> CIDX_SHIFT) as usize;
636 let v = (node.0 & VAL_MASK) as usize;
637 return match self.prior.get(c)?.member(v)? {
638 Member::Value(val) => Some(val),
639 Member::Node(n) => self.base.default_value(n),
640 };
641 }
642 self.base.default_value(node)
643 }
644}
645
646impl<A: AstAdapter> AstAdapter for ModelAdapter<A> {
647 fn root(&self) -> NodeId {
648 self.base.root()
649 }
650
651 fn children(&self, node: NodeId) -> Vec<NodeId> {
652 match self.decode(node) {
653 Some((c, 0)) => (0..self.containers()[c].members.len())
655 .map(|v| Self::value_node(c, v))
656 .collect(),
657 Some(_) => match self.aliased(node) {
660 Some(base) => self.base.children(base),
661 None => Vec::new(),
662 },
663 None => {
666 let mut kids = self.base.children(node);
667 if node == self.base.root() {
668 for c in 0..self.containers().len() {
669 kids.push(Self::container_node(c));
670 }
671 }
672 kids
673 }
674 }
675 }
676
677 fn children_named(&self, node: NodeId, name: &str) -> Vec<NodeId> {
678 if node == self.base.root() {
680 let mut out = self.base.children_named(node, name);
681 if let Some(c) = self.container_by_name(name) {
682 out.push(Self::container_node(c));
683 }
684 return out;
685 }
686 match self.decode(node) {
687 Some((c, 0)) => {
690 let cont = &self.containers()[c];
691 if name == cont.role {
692 (0..cont.members.len()).map(|v| Self::value_node(c, v)).collect()
693 } else {
694 Vec::new()
695 }
696 }
697 Some(_) => match self.aliased(node) {
698 Some(base) => self.base.children_named(base, name),
699 None => Vec::new(),
700 },
701 None => self.base.children_named(node, name),
702 }
703 }
704
705 fn name(&self, node: NodeId) -> Option<String> {
706 match self.decode(node) {
707 Some((c, 0)) => Some(self.containers()[c].name.clone()),
708 Some((c, _)) => Some(self.containers()[c].role.clone()),
712 None => self.base.name(node),
713 }
714 }
715
716 fn parent(&self, node: NodeId) -> Option<NodeId> {
717 match self.decode(node) {
718 Some((_, 0)) => Some(self.base.root()),
719 Some((c, _)) => Some(Self::container_node(c)),
720 None => self.base.parent(node),
721 }
722 }
723
724 fn traits(&self, node: NodeId) -> Vec<String> {
725 match self.decode(node) {
726 Some((c, v)) if v > 0 => {
729 let mut out = vec![self.containers()[c].trait_name.clone()];
730 if let Some(base) = self.aliased(node) {
733 out.extend(self.base.traits(base));
734 }
735 out
736 }
737 Some(_) => Vec::new(),
738 None => self.base.traits(node),
739 }
740 }
741
742 fn property(&self, node: NodeId, name: &str) -> Option<Value> {
743 match self.decode(node) {
744 Some((_, v)) if v > 0 => match self.aliased(node) {
750 Some(base) => self.base.property(base, name),
751 None => None,
752 },
753 Some(_) => None,
754 None => self.base.property(node, name),
755 }
756 }
757
758 fn default_value(&self, node: NodeId) -> Option<Value> {
759 match self.decode(node) {
760 Some((_, v)) if v > 0 => match self.aliased(node) {
761 Some(base) => self.base.default_value(base),
762 None => self.elevated(node),
763 },
764 Some(_) => None,
765 None => self.base.default_value(node),
766 }
767 }
768
769 fn metadata(&self, node: NodeId, key: &str) -> Option<Value> {
770 match self.decode(node) {
771 Some((c, 0)) if key == "n-rows" => {
772 Some(Value::Int(self.containers()[c].members.len() as i64))
773 }
774 Some(_) => None,
775 None => self.base.metadata(node, key),
776 }
777 }
778
779 fn resolve(&self, node: NodeId, property: &str, hint: Option<&str>) -> Option<NodeId> {
780 let under = self.aliased(node).unwrap_or(node);
782 if self.decode(under).is_none() {
783 if let Some(&target) = self.fabric().resolve.get(&(under, property.to_string())) {
784 return Some(target);
785 }
786 }
787 self.base.resolve(under, property, hint)
788 }
789
790 fn links(&self, node: NodeId) -> Vec<(String, NodeId)> {
791 let f = self.fabric();
792 match self.decode(node) {
793 Some((_, v)) if v > 0 => {
796 let mut out = f.edges.get(&node).cloned().unwrap_or_default();
797 if let Some(rels) = f.rel_fwd.get(&node) {
798 out.extend(rels.iter().cloned());
799 }
800 if let Some(base) = self.aliased(node) {
801 out.extend(self.base.links(base));
802 if let Some(refs) = f.ref_fwd.get(&base) {
803 out.extend(refs.iter().cloned());
804 }
805 }
806 out
807 }
808 Some(_) => Vec::new(),
809 None => {
812 let mut out = self.base.links(node);
813 if let Some(refs) = f.ref_fwd.get(&node) {
814 out.extend(refs.iter().cloned());
815 }
816 if let Some(rels) = f.rel_fwd.get(&node) {
817 out.extend(rels.iter().cloned());
818 }
819 out
820 }
821 }
822 }
823
824 fn backlinks(&self, node: NodeId) -> Vec<(String, NodeId)> {
825 let f = self.fabric();
826 match self.decode(node) {
827 Some((_, v)) if v > 0 => {
831 let mut out = f.ref_back.get(&node).cloned().unwrap_or_default();
832 if let Some(e) = f.edges.get(&node) {
833 out.extend(e.iter().cloned());
834 }
835 if let Some(rels) = f.rel_back.get(&node) {
836 out.extend(rels.iter().cloned());
837 }
838 out
839 }
840 Some(_) => Vec::new(),
841 None => {
842 let mut out = self.base.backlinks(node);
843 if let Some(rels) = f.rel_back.get(&node) {
844 out.extend(rels.iter().cloned());
845 }
846 out
847 }
848 }
849 }
850
851 fn quantifier_bound(&self) -> usize {
852 self.base.quantifier_bound()
853 }
854 fn allow_shell(&self) -> bool {
855 self.base.allow_shell()
856 }
857 fn invocation_instant(&self) -> Option<(i64, u32)> {
858 self.base.invocation_instant()
859 }
860 fn unit_scale(&self, expr: &str) -> Option<(f64, String)> {
861 self.base.unit_scale(expr)
862 }
863}
864
865fn scope_role(scope: &str) -> String {
871 scope
872 .split('/')
873 .filter(|seg| {
874 !seg.is_empty()
875 && !seg.starts_with('*')
876 && !seg.starts_with('[')
877 && !seg.chars().next().is_some_and(|c| c.is_ascii_digit())
878 })
879 .next_back()
880 .unwrap_or("")
881 .split(['[', ':'])
882 .next()
883 .unwrap_or("")
884 .to_string()
885}
886
887pub struct Borrowed<'a>(pub &'a dyn AstAdapter);
893
894impl AstAdapter for Borrowed<'_> {
895 fn root(&self) -> NodeId {
896 self.0.root()
897 }
898 fn children(&self, n: NodeId) -> Vec<NodeId> {
899 self.0.children(n)
900 }
901 fn name(&self, n: NodeId) -> Option<String> {
902 self.0.name(n)
903 }
904 fn parent(&self, n: NodeId) -> Option<NodeId> {
905 self.0.parent(n)
906 }
907 fn traits(&self, n: NodeId) -> Vec<String> {
908 self.0.traits(n)
909 }
910 fn children_named(&self, n: NodeId, name: &str) -> Vec<NodeId> {
911 self.0.children_named(n, name)
912 }
913 fn property(&self, n: NodeId, name: &str) -> Option<Value> {
914 self.0.property(n, name)
915 }
916 fn default_value(&self, n: NodeId) -> Option<Value> {
917 self.0.default_value(n)
918 }
919 fn metadata(&self, n: NodeId, key: &str) -> Option<Value> {
920 self.0.metadata(n, key)
921 }
922 fn links(&self, n: NodeId) -> Vec<(String, NodeId)> {
923 self.0.links(n)
924 }
925 fn backlinks(&self, n: NodeId) -> Vec<(String, NodeId)> {
926 self.0.backlinks(n)
927 }
928 fn resolve(&self, n: NodeId, p: &str, h: Option<&str>) -> Option<NodeId> {
929 self.0.resolve(n, p, h)
930 }
931 fn link_property(&self, s: NodeId, l: &str, t: NodeId, name: &str) -> Option<Value> {
932 self.0.link_property(s, l, t, name)
933 }
934 fn quantifier_bound(&self) -> usize {
935 self.0.quantifier_bound()
936 }
937 fn allow_shell(&self) -> bool {
938 self.0.allow_shell()
939 }
940 fn invocation_instant(&self) -> Option<(i64, u32)> {
941 self.0.invocation_instant()
942 }
943 fn unit_scale(&self, expr: &str) -> Option<(f64, String)> {
944 self.0.unit_scale(expr)
945 }
946}