1use quarb::source::SourceDecoding;
34use quarb::{AstAdapter, NodeId, Value};
35use std::cell::RefCell;
36use std::collections::HashMap;
37use std::path::PathBuf;
38
39enum Inner {
41 Json(quarb_json::JsonAdapter),
42 Xml(quarb_xml::XmlAdapter),
43 Html(quarb_html::HtmlAdapter),
44 Text(quarb_text::TextModel),
45 Csv(quarb_csv::CsvAdapter),
46 #[cfg(feature = "source")]
47 Syntax(quarb_tree_sitter::TreeSitterAdapter),
48 #[cfg(feature = "source")]
49 Code(quarb_code::CodeModel),
50 Archive(Box<ComposeAdapter<quarb_archive::ArchiveAdapter>>),
53}
54
55impl Inner {
56 fn adapter(&self) -> &dyn AstAdapter {
57 match self {
58 Inner::Json(a) => a,
59 Inner::Xml(a) => a,
60 Inner::Html(a) => a,
61 Inner::Text(a) => a,
62 Inner::Csv(a) => a,
63 #[cfg(feature = "source")]
64 Inner::Syntax(a) => a,
65 #[cfg(feature = "source")]
66 Inner::Code(a) => a,
67 Inner::Archive(a) => &**a,
68 }
69 }
70
71 fn locator(&self, node: NodeId) -> String {
72 match self {
73 Inner::Json(a) => a.pointer(node),
74 Inner::Xml(a) => a.locator(node),
75 Inner::Html(a) => a.locator(node),
76 Inner::Text(a) => a.locator(node),
77 Inner::Csv(a) => a.locator(node),
78 #[cfg(feature = "source")]
79 Inner::Syntax(a) => a.locator(node),
80 #[cfg(feature = "source")]
81 Inner::Code(a) => a.locator(node),
82 Inner::Archive(a) => a.locator(node, |o| a.outer().locator(o)),
83 }
84 }
85}
86
87#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
94pub enum SourceGraft {
95 #[default]
96 Syntax,
97 Code,
98}
99
100#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
106pub enum DocumentGraft {
107 #[default]
108 Dom,
109 Text,
110}
111
112pub fn declared_encoding(name: &str, bytes: &[u8]) -> Option<String> {
118 let ext = name.rsplit('.').next().unwrap_or("").to_ascii_lowercase();
119 match ext.as_str() {
120 "xml" | "svg" | "xhtml" | "fb2" | "tei" | "rss" | "atom" | "opml" | "xsd" | "xsl" => {
121 quarb_xml::declared_encoding(bytes)
122 }
123 "html" | "htm" => quarb_html::declared_encoding(bytes),
124 "rtf" => quarb_text_rtf::declared_encoding(bytes),
126 _ => quarb_xml::declared_encoding(bytes).or_else(|| quarb_html::declared_encoding(bytes)),
127 }
128}
129
130pub fn source_decoding(
133 explicit: Option<&str>,
134) -> Result<SourceDecoding, quarb::source::SourceError> {
135 SourceDecoding::default()
136 .with_declared(declared_encoding)
137 .with_option(explicit)
138}
139
140pub fn read_source(
144 path: &std::path::Path,
145 explicit: Option<&str>,
146) -> std::io::Result<Result<quarb::source::Decoded, quarb::source::SourceError>> {
147 let bytes = std::fs::read(path)?;
148 let name = path.file_name().and_then(|n| n.to_str()).unwrap_or("");
149 Ok(source_decoding(explicit).and_then(|d| d.decode(name, &bytes)))
150}
151
152fn archive_name(name: &str) -> bool {
155 quarb_archive::archive_extension(name.rsplit('.').next().unwrap_or(""))
156}
157
158fn parse_inner(
160 name: &str,
161 content: &str,
162 graft: SourceGraft,
163 doc: DocumentGraft,
164 csv: quarb_csv::CsvOptions,
165) -> Option<Inner> {
166 #[cfg(not(feature = "source"))]
167 let _ = graft;
168 let ext = name.rsplit('.').next().unwrap_or("").to_ascii_lowercase();
169 match ext.as_str() {
170 "json" => {
171 return quarb_json::JsonAdapter::parse(content)
172 .ok()
173 .map(Inner::Json);
174 }
175 "jsonl" | "ndjson" => {
176 return quarb_json::JsonAdapter::parse_lines(content)
177 .ok()
178 .map(Inner::Json);
179 }
180 "xml" | "svg" | "xhtml" => {
181 #[cfg(feature = "koine")]
185 if doc == DocumentGraft::Text
186 && quarb_text_koine::detect_xml_kind(content) == Some("fb2")
187 && let Ok(m) = quarb_text_koine::parse_xml_as(content, "fb2")
188 {
189 return Some(Inner::Text(m));
190 }
191 return quarb_xml::XmlAdapter::parse(content).ok().map(Inner::Xml);
192 }
193 "fb2" => {
194 #[cfg(feature = "koine")]
195 if doc == DocumentGraft::Text
196 && let Ok(m) = quarb_text_koine::parse_xml_as(content, "fb2")
197 {
198 return Some(Inner::Text(m));
199 }
200 return quarb_xml::XmlAdapter::parse(content).ok().map(Inner::Xml);
201 }
202 "html" | "htm" => {
203 return Some(match doc {
204 DocumentGraft::Dom => Inner::Html(quarb_html::HtmlAdapter::parse(content)),
205 DocumentGraft::Text => Inner::Text(quarb_text_html::parse(content)),
206 });
207 }
208 "yaml" | "yml" => return quarb_yaml::parse(content).ok().map(Inner::Json),
209 "toml" => return quarb_toml::parse(content).ok().map(Inner::Json),
210 "md" | "markdown" => {
211 return Some(match doc {
212 DocumentGraft::Dom => Inner::Html(quarb_markdown::parse(content)),
213 DocumentGraft::Text => Inner::Text(quarb_text_markdown::parse(content)),
214 });
215 }
216 "txt" => return Some(Inner::Text(quarb_text::TextModel::parse_plain(content))),
219 "csv" => {
220 return quarb_csv::CsvAdapter::parse_declared(content, b',', csv)
221 .ok()
222 .map(Inner::Csv);
223 }
224 "tsv" => {
225 return quarb_csv::CsvAdapter::parse_declared(content, b'\t', csv)
226 .ok()
227 .map(Inner::Csv);
228 }
229 #[cfg(feature = "source")]
230 ext if quarb_tree_sitter::supported(ext) => {
231 return match graft {
232 SourceGraft::Syntax => quarb_tree_sitter::TreeSitterAdapter::parse(content, ext)
233 .ok()
234 .map(Inner::Syntax),
235 SourceGraft::Code => quarb_code::CodeModel::parse(content, ext)
236 .ok()
237 .map(Inner::Code),
238 };
239 }
240 _ => {}
241 }
242 let t = content.trim_start();
244 if t.starts_with('{') || t.starts_with('[') {
245 return quarb_json::JsonAdapter::parse(content)
246 .ok()
247 .map(Inner::Json);
248 }
249 if t.starts_with("<?xml") {
250 return quarb_xml::XmlAdapter::parse(content).ok().map(Inner::Xml);
251 }
252 None
253}
254
255fn grafts_by_name(name: &str) -> bool {
260 let Some((_, ext)) = name.rsplit_once('.') else {
261 return true;
262 };
263 let ext = ext.to_ascii_lowercase();
264 if matches!(
265 ext.as_str(),
266 "json"
267 | "jsonl"
268 | "ndjson"
269 | "xml"
270 | "svg"
271 | "xhtml"
272 | "fb2"
273 | "html"
274 | "htm"
275 | "yaml"
276 | "yml"
277 | "toml"
278 | "md"
279 | "markdown"
280 | "txt"
281 | "csv"
282 | "tsv"
283 ) {
284 return true;
285 }
286 #[cfg(feature = "source")]
287 if quarb_tree_sitter::supported(&ext) {
288 return true;
289 }
290 false
291}
292
293struct Graft {
295 outer: NodeId,
296 inner: Inner,
297}
298
299const GRAFT_BIT: u64 = 1 << 55;
308
309pub type DocumentReader = std::rc::Rc<dyn Fn(&std::path::Path) -> Option<quarb_text::TextModel>>;
313
314pub struct ComposeAdapter<A: AstAdapter> {
315 outer: A,
316 grafts: RefCell<Vec<Graft>>,
317 probed: RefCell<HashMap<NodeId, Option<usize>>>,
320 interned: RefCell<HashMap<(usize, NodeId), NodeId>>,
322 reverse: RefCell<Vec<(usize, NodeId)>>,
323 source_path: Option<fn(&A, NodeId) -> Option<PathBuf>>,
327 source_graft: SourceGraft,
329 document_graft: DocumentGraft,
331 document_url: Option<fn(&A, NodeId) -> Option<String>>,
335 urls: RefCell<Option<HashMap<String, NodeId>>>,
337 document_reader: Option<DocumentReader>,
342 decoding: SourceDecoding,
348 decoded: RefCell<HashMap<usize, (String, usize)>>,
351 csv: quarb_csv::CsvOptions,
354}
355
356impl<A: AstAdapter> ComposeAdapter<A> {
357 pub fn new(outer: A) -> Self {
358 ComposeAdapter {
359 outer,
360 grafts: RefCell::new(Vec::new()),
361 probed: RefCell::new(HashMap::new()),
362 interned: RefCell::new(HashMap::new()),
363 reverse: RefCell::new(Vec::new()),
364 source_path: None,
365 source_graft: SourceGraft::default(),
366 document_graft: DocumentGraft::default(),
367 document_url: None,
368 urls: RefCell::new(None),
369 document_reader: None,
370 decoding: SourceDecoding::default(),
371 decoded: RefCell::new(HashMap::new()),
372 csv: quarb_csv::CsvOptions::default(),
373 }
374 }
375
376 pub fn with_csv_options(mut self, csv: quarb_csv::CsvOptions) -> Self {
378 self.csv = csv;
379 self
380 }
381
382 pub fn with_decoding(mut self, decoding: SourceDecoding) -> Self {
386 self.decoding = decoding;
387 self
388 }
389
390 pub fn with_document_reader(mut self, reader: DocumentReader) -> Self {
394 self.document_reader = Some(reader);
395 self
396 }
397
398 pub fn with_document_urls(mut self, document_url: fn(&A, NodeId) -> Option<String>) -> Self {
404 self.document_url = Some(document_url);
405 self
406 }
407
408 fn leaf_by_url(&self, url: &str) -> Option<NodeId> {
411 let f = self.document_url?;
412 if self.urls.borrow().is_none() {
413 let mut map = HashMap::new();
414 let mut stack = vec![self.outer.root()];
415 while let Some(n) = stack.pop() {
416 let kids = self.outer.children(n);
417 if kids.is_empty() {
418 if let Some(u) = f(&self.outer, n) {
419 map.entry(u.split('#').next().unwrap_or(&u).to_string())
420 .or_insert(n);
421 }
422 } else {
423 stack.extend(kids);
424 }
425 }
426 *self.urls.borrow_mut() = Some(map);
427 }
428 self.urls.borrow().as_ref()?.get(url).copied()
429 }
430
431 pub fn with_source_graft(mut self, graft: SourceGraft) -> Self {
434 self.source_graft = graft;
435 self
436 }
437
438 pub fn with_document_graft(mut self, graft: DocumentGraft) -> Self {
441 self.document_graft = graft;
442 self
443 }
444
445 pub fn with_source_paths(outer: A, source_path: fn(&A, NodeId) -> Option<PathBuf>) -> Self {
451 ComposeAdapter {
452 source_path: Some(source_path),
453 ..Self::new(outer)
454 }
455 }
456
457 pub fn outer(&self) -> &A {
459 &self.outer
460 }
461
462 pub fn locator(&self, node: NodeId, outer_locator: impl Fn(NodeId) -> String) -> String {
465 match self.split(node) {
466 None => outer_locator(node),
467 Some((g, inner)) => {
468 let grafts = self.grafts.borrow();
469 let graft = &grafts[g];
470 format!(
471 "{}!{}",
472 outer_locator(graft.outer),
473 graft.inner.locator(inner)
474 )
475 }
476 }
477 }
478
479 fn graft_fill(&self, outer_leaf: NodeId, inner_path: String) -> quarb::Provenance {
485 let mut fill = self.outer.provenance(outer_leaf).as_source_rung();
486 fill.path = Some(inner_path);
487 fill
488 }
489
490 fn split(&self, node: NodeId) -> Option<(usize, NodeId)> {
491 if node.0 & GRAFT_BIT == 0 {
492 return None;
493 }
494 self.reverse
495 .borrow()
496 .get((node.0 & !GRAFT_BIT) as usize)
497 .copied()
498 }
499
500 fn intern(&self, graft: usize, inner: NodeId) -> NodeId {
501 if let Some(&id) = self.interned.borrow().get(&(graft, inner)) {
502 return id;
503 }
504 let mut rev = self.reverse.borrow_mut();
505 let id = NodeId(GRAFT_BIT | rev.len() as u64);
506 rev.push((graft, inner));
507 self.interned.borrow_mut().insert((graft, inner), id);
508 id
509 }
510
511 fn graft_at(&self, node: NodeId) -> Option<usize> {
515 if let Some(&g) = self.probed.borrow().get(&node) {
516 return g;
517 }
518 let g = (|| {
519 if !self.outer.children(node).is_empty() {
520 return None;
521 }
522 let name = self.outer.name(node)?;
523 if archive_name(&name)
524 && let Some(path_of) = self.source_path
525 && let Some(path) = path_of(&self.outer, node)
526 && let Ok(a) =
527 quarb_archive::ArchiveAdapter::open_with_decoding(&path, self.decoding.clone())
528 {
529 let inner = Inner::Archive(Box::new(
530 ComposeAdapter::new(a)
531 .with_source_graft(self.source_graft)
532 .with_document_graft(self.document_graft)
533 .with_decoding(self.decoding.clone())
534 .with_csv_options(self.csv),
535 ));
536 let mut grafts = self.grafts.borrow_mut();
537 grafts.push(Graft { outer: node, inner });
538 return Some(grafts.len() - 1);
539 }
540 if let Some(read) = &self.document_reader
541 && let Some(path_of) = self.source_path
542 && let Some(path) = path_of(&self.outer, node)
543 && let Some(model) = read(&path)
544 {
545 let mut grafts = self.grafts.borrow_mut();
546 grafts.push(Graft {
547 outer: node,
548 inner: Inner::Text(model),
549 });
550 return Some(grafts.len() - 1);
551 }
552 if !grafts_by_name(&name) {
557 return None;
558 }
559 let mut record = None;
564 let content = match self
565 .source_path
566 .and_then(|path_of| path_of(&self.outer, node))
567 .and_then(|p| std::fs::read(p).ok())
568 {
569 Some(bytes) => {
570 let d = self.decoding.decode(&name, &bytes).ok()?;
571 record = Some((d.encoding, d.replaced));
572 d.text
573 }
574 None => match self.outer.default_value(node)? {
575 Value::Str(s) => s,
576 _ => return None,
577 },
578 };
579 let mut inner = parse_inner(
580 &name,
581 &content,
582 self.source_graft,
583 self.document_graft,
584 self.csv,
585 )?;
586 if let (Inner::Text(model), Some(f)) = (&mut inner, self.document_url)
587 && let Some(u) = f(&self.outer, node)
588 {
589 model.set_document_url(&u);
590 }
591 let mut grafts = self.grafts.borrow_mut();
592 grafts.push(Graft { outer: node, inner });
593 if let Some(r) = record {
594 self.decoded.borrow_mut().insert(grafts.len() - 1, r);
595 }
596 Some(grafts.len() - 1)
597 })();
598 self.probed.borrow_mut().insert(node, g);
599 g
600 }
601
602 fn wrap(&self, graft: usize, inner: NodeId) -> NodeId {
605 let grafts = self.grafts.borrow();
606 if inner == grafts[graft].inner.adapter().root() {
607 grafts[graft].outer
608 } else {
609 drop(grafts);
610 self.intern(graft, inner)
611 }
612 }
613}
614
615impl<A: AstAdapter> AstAdapter for ComposeAdapter<A> {
616 fn root(&self) -> NodeId {
617 self.outer.root()
618 }
619
620 fn children(&self, node: NodeId) -> Vec<NodeId> {
621 match self.split(node) {
622 Some((g, inner)) => {
623 let ids: Vec<NodeId> = {
624 let grafts = self.grafts.borrow();
625 grafts[g].inner.adapter().children(inner)
626 };
627 ids.into_iter().map(|c| self.wrap(g, c)).collect()
628 }
629 None => {
630 let outer = self.outer.children(node);
631 if !outer.is_empty() {
632 return outer;
633 }
634 match self.graft_at(node) {
635 Some(g) => {
636 let ids: Vec<NodeId> = {
637 let grafts = self.grafts.borrow();
638 let a = grafts[g].inner.adapter();
639 a.children(a.root())
640 };
641 ids.into_iter().map(|c| self.wrap(g, c)).collect()
642 }
643 None => Vec::new(),
644 }
645 }
646 }
647 }
648
649 fn children_named(&self, node: NodeId, name: &str) -> Vec<NodeId> {
655 match self.split(node) {
656 Some((g, inner)) => {
657 let ids: Vec<NodeId> = {
658 let grafts = self.grafts.borrow();
659 grafts[g].inner.adapter().children_named(inner, name)
660 };
661 ids.into_iter().map(|c| self.wrap(g, c)).collect()
662 }
663 None => {
664 let named = self.outer.children_named(node, name);
665 if !named.is_empty() {
666 return named;
667 }
668 if self.source_path.is_none()
669 && !matches!(self.outer.default_value(node), Some(Value::Str(_)))
670 {
671 return Vec::new();
672 }
673 self.children(node)
674 .into_iter()
675 .filter(|&c| self.answers_to(c, name))
676 .collect()
677 }
678 }
679 }
680
681 fn name(&self, node: NodeId) -> Option<String> {
682 match self.split(node) {
683 Some((g, inner)) => self.grafts.borrow()[g].inner.adapter().name(inner),
684 None => self.outer.name(node),
685 }
686 }
687
688 fn parent(&self, node: NodeId) -> Option<NodeId> {
689 match self.split(node) {
690 Some((g, inner)) => {
691 let p = self.grafts.borrow()[g].inner.adapter().parent(inner)?;
692 Some(self.wrap(g, p))
693 }
694 None => self.outer.parent(node),
695 }
696 }
697
698 fn child_host(&self, node: NodeId) -> NodeId {
699 match self.split(node) {
700 Some((g, inner)) => {
701 let h = self.grafts.borrow()[g].inner.adapter().child_host(inner);
702 self.wrap(g, h)
703 }
704 None => self.outer.child_host(node),
705 }
706 }
707
708 fn properties(&self, node: NodeId) -> Vec<(String, Value)> {
709 match self.split(node) {
710 Some((g, inner)) => self.grafts.borrow()[g].inner.adapter().properties(inner),
711 None => self.outer.properties(node),
712 }
713 }
714
715 fn walks_for_references(&self) -> bool {
718 self.outer.walks_for_references()
719 }
720 fn can_refer_to(&self, source: NodeId, target: NodeId) -> Option<bool> {
723 match (self.split(source), self.split(target)) {
724 (None, None) => self.outer.can_refer_to(source, target),
725 (Some((g, s)), Some((h, t))) if g == h => {
726 self.grafts.borrow()[g].inner.adapter().can_refer_to(s, t)
727 }
728 _ => self.ref_property(source).map(|_| true),
729 }
730 }
731 fn reference_properties(&self, source: NodeId, target: NodeId) -> Vec<String> {
732 match (self.split(source), self.split(target)) {
733 (None, None) => self.outer.reference_properties(source, target),
734 (Some((g, s)), Some((h, t))) if g == h => self.grafts.borrow()[g]
735 .inner
736 .adapter()
737 .reference_properties(s, t),
738 _ => self.ref_property(source).into_iter().collect(),
739 }
740 }
741 fn index_referrers(
744 &self,
745 scope: &str,
746 property: &str,
747 label: Option<&str>,
748 target: NodeId,
749 ) -> Option<Vec<NodeId>> {
750 match self.split(target) {
751 None => self.outer.index_referrers(scope, property, label, target),
752 Some(_) => None,
753 }
754 }
755 fn tree_identities(&self) -> Vec<(String, NodeId)> {
756 self.outer.tree_identities()
757 }
758 fn reverse_label(&self, target: NodeId) -> Option<String> {
759 match self.split(target) {
760 Some((g, inner)) => self.grafts.borrow()[g].inner.adapter().reverse_label(inner),
761 None => self.outer.reverse_label(target),
762 }
763 }
764 fn resolve_needs_label(&self, node: NodeId, property: &str) -> bool {
765 match self.split(node) {
766 Some((g, inner)) => self.grafts.borrow()[g]
767 .inner
768 .adapter()
769 .resolve_needs_label(inner, property),
770 None => self.outer.resolve_needs_label(node, property),
771 }
772 }
773 fn property_names(&self, node: NodeId) -> Vec<String> {
774 match self.split(node) {
775 Some((g, inner)) => self.grafts.borrow()[g]
776 .inner
777 .adapter()
778 .property_names(inner),
779 None => self.outer.property_names(node),
780 }
781 }
782 fn resolves_references(&self) -> bool {
784 self.outer.resolves_references()
785 || self
786 .grafts
787 .borrow()
788 .iter()
789 .any(|g| g.inner.adapter().resolves_references())
790 }
791
792 fn non_tree_nodes(&self) -> Vec<NodeId> {
795 let mut out = self.outer.non_tree_nodes();
796 let grafts = self.grafts.borrow();
797 for (g, graft) in grafts.iter().enumerate() {
798 out.extend(
799 graft
800 .inner
801 .adapter()
802 .non_tree_nodes()
803 .into_iter()
804 .map(|n| self.wrap(g, n)),
805 );
806 }
807 out
808 }
809
810 fn answers_to(&self, node: NodeId, name: &str) -> bool {
813 match self.split(node) {
814 Some((g, inner)) => self.grafts.borrow()[g]
815 .inner
816 .adapter()
817 .answers_to(inner, name),
818 None => self.outer.answers_to(node, name),
819 }
820 }
821
822 fn traits(&self, node: NodeId) -> Vec<String> {
826 match self.split(node) {
827 Some((g, inner)) => self.grafts.borrow()[g].inner.adapter().traits(inner),
828 None => {
829 let mut out = self.outer.traits(node);
830 if let Some(g) = self.graft_at(node) {
831 let grafts = self.grafts.borrow();
832 let a = grafts[g].inner.adapter();
833 for t in a.traits(a.root()) {
834 if !out.contains(&t) {
835 out.push(t);
836 }
837 }
838 }
839 out
840 }
841 }
842 }
843
844 fn property(&self, node: NodeId, name: &str) -> Option<Value> {
845 match self.split(node) {
846 Some((g, inner)) => self.grafts.borrow()[g]
847 .inner
848 .adapter()
849 .property(inner, name),
850 None => self.outer.property(node, name).or_else(|| {
855 let g = self.graft_at(node)?;
856 let grafts = self.grafts.borrow();
857 let a = grafts[g].inner.adapter();
858 a.property(a.root(), name)
859 }),
860 }
861 }
862
863 fn default_value(&self, node: NodeId) -> Option<Value> {
864 match self.split(node) {
865 Some((g, inner)) => self.grafts.borrow()[g].inner.adapter().default_value(inner),
866 None => {
872 if self.decoding.explicit.is_some()
873 && self.outer.children(node).is_empty()
874 && let Some(path_of) = self.source_path
875 && let Some(p) = path_of(&self.outer, node)
876 && p.is_file()
877 && let Ok(bytes) = std::fs::read(&p)
878 {
879 let name = self.outer.name(node).unwrap_or_default();
880 return self
881 .decoding
882 .decode(&name, &bytes)
883 .ok()
884 .map(|d| Value::Str(d.text));
885 }
886 self.outer.default_value(node)
887 }
888 }
889 }
890
891 fn metadata(&self, node: NodeId, key: &str) -> Option<Value> {
892 match self.split(node) {
893 Some((g, inner)) => self.grafts.borrow()[g].inner.adapter().metadata(inner, key),
894 None => self.outer.metadata(node, key).or_else(|| {
898 let g = self.graft_at(node)?;
899 if matches!(key, "encoding" | "replaced") {
900 if !self.decoded.borrow().contains_key(&g)
904 && let Some(path_of) = self.source_path
905 && let Some(p) = path_of(&self.outer, node)
906 && let Ok(bytes) = std::fs::read(&p)
907 {
908 let name = self.outer.name(node).unwrap_or_default();
909 if let Ok(d) = self.decoding.decode(&name, &bytes) {
910 self.decoded
911 .borrow_mut()
912 .insert(g, (d.encoding, d.replaced));
913 }
914 }
915 if let Some((enc, replaced)) = self.decoded.borrow().get(&g) {
916 return Some(match key {
917 "encoding" => Value::Str(enc.clone()),
918 _ => Value::Int(*replaced as i64),
919 });
920 }
921 }
922 let grafts = self.grafts.borrow();
923 let a = grafts[g].inner.adapter();
924 a.metadata(a.root(), key)
925 }),
926 }
927 }
928
929 fn aliased_metadata(&self, node: NodeId) -> &'static [&'static str] {
933 match self.split(node) {
934 Some((g, inner)) => self.grafts.borrow()[g]
935 .inner
936 .adapter()
937 .aliased_metadata(inner),
938 None => self.outer.aliased_metadata(node),
939 }
940 }
941
942 fn provenance(&self, node: NodeId) -> quarb::Provenance {
949 match self.split(node) {
950 Some((g, inner)) => {
951 let (inner_prov, outer_leaf, inner_path) = {
955 let grafts = self.grafts.borrow();
956 let a = grafts[g].inner.adapter();
957 (
958 a.provenance(inner),
959 grafts[g].outer,
960 quarb::name_path(a, inner),
961 )
962 };
963 inner_prov.or(self.graft_fill(outer_leaf, inner_path))
964 }
965 None => self.outer.provenance(node),
966 }
967 }
968 fn provenance_list(&self, node: NodeId) -> quarb::ProvenanceList {
970 match self.split(node) {
971 Some((g, inner)) => {
972 let (inner_list, outer_leaf, inner_path) = {
973 let grafts = self.grafts.borrow();
974 let a = grafts[g].inner.adapter();
975 (
976 a.provenance_list(inner),
977 grafts[g].outer,
978 quarb::name_path(a, inner),
979 )
980 };
981 inner_list.or(self.graft_fill(outer_leaf, inner_path))
982 }
983 None => self.outer.provenance_list(node),
984 }
985 }
986
987 fn resolve(&self, node: NodeId, property: &str, hint: Option<&str>) -> Option<NodeId> {
988 match self.split(node) {
989 Some((g, inner)) => {
990 let t = self.grafts.borrow()[g]
991 .inner
992 .adapter()
993 .resolve(inner, property, hint)?;
994 Some(self.wrap(g, t))
995 }
996 None => self.outer.resolve(node, property, hint),
997 }
998 }
999
1000 fn has_trait(&self, node: NodeId, name: &str) -> bool {
1003 match self.split(node) {
1004 Some((g, inner)) => self.grafts.borrow()[g]
1005 .inner
1006 .adapter()
1007 .has_trait(inner, name),
1008 None => {
1009 self.outer.has_trait(node, name)
1010 || self.graft_at(node).is_some_and(|g| {
1011 let grafts = self.grafts.borrow();
1012 let a = grafts[g].inner.adapter();
1013 a.has_trait(a.root(), name)
1014 })
1015 }
1016 }
1017 }
1018
1019 fn ref_property(&self, node: NodeId) -> Option<String> {
1020 match self.split(node) {
1021 Some((g, inner)) => self.grafts.borrow()[g].inner.adapter().ref_property(inner),
1022 None => self.outer.ref_property(node),
1023 }
1024 }
1025
1026 fn external_ref(
1029 &self,
1030 node: NodeId,
1031 property: &str,
1032 hint: Option<&str>,
1033 ) -> Option<quarb::ExternalRef> {
1034 match self.split(node) {
1035 Some((g, inner)) => self.grafts.borrow()[g]
1036 .inner
1037 .adapter()
1038 .external_ref(inner, property, hint),
1039 None => self.outer.external_ref(node, property, hint),
1040 }
1041 }
1042
1043 fn ref_label(&self, node: NodeId, property: &str) -> Option<String> {
1044 match self.split(node) {
1045 Some((g, inner)) => self.grafts.borrow()[g]
1046 .inner
1047 .adapter()
1048 .ref_label(inner, property),
1049 None => self.outer.ref_label(node, property),
1050 }
1051 }
1052
1053 fn resolve_fragment(&self, node: NodeId, fragment: &str) -> Option<NodeId> {
1056 match self.split(node) {
1057 Some((g, inner)) => {
1058 let t = self.grafts.borrow()[g]
1059 .inner
1060 .adapter()
1061 .resolve_fragment(inner, fragment)?;
1062 Some(self.wrap(g, t))
1063 }
1064 None => match self.graft_at(node) {
1065 Some(g) => {
1066 let t = {
1067 let grafts = self.grafts.borrow();
1068 let a = grafts[g].inner.adapter();
1069 a.resolve_fragment(a.root(), fragment)?
1070 };
1071 Some(self.wrap(g, t))
1072 }
1073 None => self.outer.resolve_fragment(node, fragment),
1074 },
1075 }
1076 }
1077
1078 fn document_by_ref(&self, id: &str) -> Option<NodeId> {
1081 if let Some(leaf) = self.leaf_by_url(id) {
1082 let _ = self.graft_at(leaf);
1084 return Some(leaf);
1085 }
1086 self.outer.document_by_ref(id)
1087 }
1088
1089 fn reverse_resolve(
1094 &self,
1095 node: NodeId,
1096 property: Option<&str>,
1097 hint: Option<&str>,
1098 ) -> Option<Vec<NodeId>> {
1099 match self.split(node) {
1100 Some((g, inner)) => {
1101 let v = self.grafts.borrow()[g]
1102 .inner
1103 .adapter()
1104 .reverse_resolve(inner, property, hint)?;
1105 Some(v.into_iter().map(|t| self.wrap(g, t)).collect())
1106 }
1107 None => self.outer.reverse_resolve(node, property, hint),
1108 }
1109 }
1110
1111 fn descendants_named(&self, node: NodeId, name: &str) -> Option<Vec<(NodeId, usize)>> {
1114 let (g, inner) = self.split(node)?;
1115 let v = self.grafts.borrow()[g]
1116 .inner
1117 .adapter()
1118 .descendants_named(inner, name)?;
1119 Some(v.into_iter().map(|(t, d)| (self.wrap(g, t), d)).collect())
1120 }
1121
1122 fn descendants_where(
1123 &self,
1124 node: NodeId,
1125 name: &str,
1126 property: &str,
1127 value: &Value,
1128 ) -> Option<Vec<(NodeId, usize)>> {
1129 let (g, inner) = self.split(node)?;
1130 let v = self.grafts.borrow()[g]
1131 .inner
1132 .adapter()
1133 .descendants_where(inner, name, property, value)?;
1134 Some(v.into_iter().map(|(t, d)| (self.wrap(g, t), d)).collect())
1135 }
1136
1137 fn select(&self, from: NodeId, plan: &quarb::StepPlan<'_>) -> Option<quarb::Selection> {
1138 match self.split(from) {
1139 Some((g, inner)) => {
1141 let sel = self.grafts.borrow()[g]
1142 .inner
1143 .adapter()
1144 .select(inner, plan)?;
1145 Some(quarb::Selection {
1146 nodes: sel
1147 .nodes
1148 .into_iter()
1149 .map(|(t, d)| (self.wrap(g, t), d))
1150 .collect(),
1151 applied: sel.applied,
1152 })
1153 }
1154 None => match plan.axis {
1158 quarb::PlanAxis::Child => quarb::adapter::select_by_hooks(self, from, plan),
1159 quarb::PlanAxis::Descendant => None,
1160 },
1161 }
1162 }
1163
1164 fn index_lookup(&self, scope: &str, property: &str, value: &Value) -> Option<Vec<NodeId>> {
1165 self.outer.index_lookup(scope, property, value)
1166 }
1167
1168 fn select_plan(&self, scope: &[&str], plan: &quarb::StepPlan<'_>) -> Option<Vec<bool>> {
1169 self.outer.select_plan(scope, plan)
1170 }
1171
1172 fn estimate(&self, scope: &[&str], plan: &quarb::StepPlan<'_>) -> Option<quarb::Estimate> {
1173 self.outer.estimate(scope, plan)
1174 }
1175
1176 fn has_node(&self, node: NodeId) -> bool {
1177 match self.split(node) {
1178 Some((g, inner)) => self.grafts.borrow()[g].inner.adapter().has_node(inner),
1179 None => self.outer.has_node(node),
1180 }
1181 }
1182
1183 fn unit_scale(&self, expr: &str) -> Option<(f64, String)> {
1184 self.outer.unit_scale(expr)
1185 }
1186
1187 fn quantifier_bound(&self) -> usize {
1188 self.outer.quantifier_bound()
1189 }
1190
1191 fn prefetch_links(&self, nodes: &[NodeId], dir: quarb::LinkDir) {
1192 let outer: Vec<NodeId> = nodes
1193 .iter()
1194 .copied()
1195 .filter(|n| self.split(*n).is_none())
1196 .collect();
1197 if !outer.is_empty() {
1198 self.outer.prefetch_links(&outer, dir);
1199 }
1200 }
1201
1202 fn links(&self, node: NodeId) -> Vec<(String, NodeId)> {
1203 match self.split(node) {
1204 Some((g, inner)) => {
1205 let ls: Vec<(String, NodeId)> = {
1206 let grafts = self.grafts.borrow();
1207 grafts[g].inner.adapter().links(inner)
1208 };
1209 ls.into_iter().map(|(l, n)| (l, self.wrap(g, n))).collect()
1210 }
1211 None => self.outer.links(node),
1212 }
1213 }
1214
1215 fn backlinks(&self, node: NodeId) -> Vec<(String, NodeId)> {
1216 match self.split(node) {
1217 Some((g, inner)) => {
1218 let ls: Vec<(String, NodeId)> = {
1219 let grafts = self.grafts.borrow();
1220 grafts[g].inner.adapter().backlinks(inner)
1221 };
1222 ls.into_iter().map(|(l, n)| (l, self.wrap(g, n))).collect()
1223 }
1224 None => self.outer.backlinks(node),
1225 }
1226 }
1227
1228 fn link_property(
1229 &self,
1230 source: NodeId,
1231 label: &str,
1232 target: NodeId,
1233 name: &str,
1234 ) -> Option<Value> {
1235 match (self.split(source), self.split(target)) {
1238 (Some((g, src)), Some((gt, tgt))) if g == gt => self.grafts.borrow()[g]
1239 .inner
1240 .adapter()
1241 .link_property(src, label, tgt, name),
1242 (None, None) => self.outer.link_property(source, label, target, name),
1243 _ => None,
1244 }
1245 }
1246}