1use quarb::{AstAdapter, NodeId, Value};
34use std::cell::RefCell;
35use std::collections::HashMap;
36use std::path::PathBuf;
37
38enum Inner {
40 Json(quarb_json::JsonAdapter),
41 Xml(quarb_xml::XmlAdapter),
42 Html(quarb_html::HtmlAdapter),
43 Csv(quarb_csv::CsvAdapter),
44 Code(quarb_code::CodeAdapter),
45 Archive(Box<ComposeAdapter<quarb_archive::ArchiveAdapter>>),
48}
49
50impl Inner {
51 fn adapter(&self) -> &dyn AstAdapter {
52 match self {
53 Inner::Json(a) => a,
54 Inner::Xml(a) => a,
55 Inner::Html(a) => a,
56 Inner::Csv(a) => a,
57 Inner::Code(a) => a,
58 Inner::Archive(a) => &**a,
59 }
60 }
61
62 fn locator(&self, node: NodeId) -> String {
63 match self {
64 Inner::Json(a) => a.pointer(node),
65 Inner::Xml(a) => a.locator(node),
66 Inner::Html(a) => a.locator(node),
67 Inner::Csv(a) => a.locator(node),
68 Inner::Code(a) => a.locator(node),
69 Inner::Archive(a) => a.locator(node, |o| a.outer().locator(o)),
70 }
71 }
72}
73
74fn archive_name(name: &str) -> bool {
78 let ext = name.rsplit('.').next().unwrap_or("").to_ascii_lowercase();
79 matches!(ext.as_str(), "zip" | "tar" | "tgz" | "gz")
80}
81
82fn parse_inner(name: &str, content: &str) -> Option<Inner> {
84 let ext = name.rsplit('.').next().unwrap_or("").to_ascii_lowercase();
85 match ext.as_str() {
86 "json" => {
87 return quarb_json::JsonAdapter::parse(content)
88 .ok()
89 .map(Inner::Json);
90 }
91 "jsonl" | "ndjson" => {
92 return quarb_json::JsonAdapter::parse_lines(content)
93 .ok()
94 .map(Inner::Json);
95 }
96 "xml" | "svg" | "xhtml" => {
97 return quarb_xml::XmlAdapter::parse(content).ok().map(Inner::Xml);
98 }
99 "html" | "htm" => return Some(Inner::Html(quarb_html::HtmlAdapter::parse(content))),
100 "yaml" | "yml" => return quarb_yaml::parse(content).ok().map(Inner::Json),
101 "toml" => return quarb_toml::parse(content).ok().map(Inner::Json),
102 "md" | "markdown" => return Some(Inner::Html(quarb_markdown::parse(content))),
103 "csv" => return quarb_csv::CsvAdapter::parse(content).ok().map(Inner::Csv),
104 "tsv" => {
105 return quarb_csv::CsvAdapter::parse_with_delimiter(content, b'\t')
106 .ok()
107 .map(Inner::Csv);
108 }
109 ext if quarb_code::supported(ext) => {
110 return quarb_code::CodeAdapter::parse(content, ext)
111 .ok()
112 .map(Inner::Code);
113 }
114 _ => {}
115 }
116 let t = content.trim_start();
118 if t.starts_with('{') || t.starts_with('[') {
119 return quarb_json::JsonAdapter::parse(content)
120 .ok()
121 .map(Inner::Json);
122 }
123 if t.starts_with("<?xml") {
124 return quarb_xml::XmlAdapter::parse(content).ok().map(Inner::Xml);
125 }
126 None
127}
128
129struct Graft {
131 outer: NodeId,
132 inner: Inner,
133}
134
135const GRAFT_BIT: u64 = 1 << 55;
144
145pub struct ComposeAdapter<A: AstAdapter> {
147 outer: A,
148 grafts: RefCell<Vec<Graft>>,
149 probed: RefCell<HashMap<NodeId, Option<usize>>>,
152 interned: RefCell<HashMap<(usize, NodeId), NodeId>>,
154 reverse: RefCell<Vec<(usize, NodeId)>>,
155 source_path: Option<fn(&A, NodeId) -> Option<PathBuf>>,
159}
160
161impl<A: AstAdapter> ComposeAdapter<A> {
162 pub fn new(outer: A) -> Self {
163 ComposeAdapter {
164 outer,
165 grafts: RefCell::new(Vec::new()),
166 probed: RefCell::new(HashMap::new()),
167 interned: RefCell::new(HashMap::new()),
168 reverse: RefCell::new(Vec::new()),
169 source_path: None,
170 }
171 }
172
173 pub fn with_source_paths(outer: A, source_path: fn(&A, NodeId) -> Option<PathBuf>) -> Self {
179 ComposeAdapter {
180 source_path: Some(source_path),
181 ..Self::new(outer)
182 }
183 }
184
185 pub fn outer(&self) -> &A {
187 &self.outer
188 }
189
190 pub fn locator(&self, node: NodeId, outer_locator: impl Fn(NodeId) -> String) -> String {
193 match self.split(node) {
194 None => outer_locator(node),
195 Some((g, inner)) => {
196 let grafts = self.grafts.borrow();
197 let graft = &grafts[g];
198 format!(
199 "{}!{}",
200 outer_locator(graft.outer),
201 graft.inner.locator(inner)
202 )
203 }
204 }
205 }
206
207 fn split(&self, node: NodeId) -> Option<(usize, NodeId)> {
209 if node.0 & GRAFT_BIT == 0 {
210 return None;
211 }
212 self.reverse
213 .borrow()
214 .get((node.0 & !GRAFT_BIT) as usize)
215 .copied()
216 }
217
218 fn intern(&self, graft: usize, inner: NodeId) -> NodeId {
219 if let Some(&id) = self.interned.borrow().get(&(graft, inner)) {
220 return id;
221 }
222 let mut rev = self.reverse.borrow_mut();
223 let id = NodeId(GRAFT_BIT | rev.len() as u64);
224 rev.push((graft, inner));
225 self.interned.borrow_mut().insert((graft, inner), id);
226 id
227 }
228
229 fn graft_at(&self, node: NodeId) -> Option<usize> {
233 if let Some(&g) = self.probed.borrow().get(&node) {
234 return g;
235 }
236 let g = (|| {
237 if !self.outer.children(node).is_empty() {
238 return None;
239 }
240 let name = self.outer.name(node)?;
241 if archive_name(&name)
242 && let Some(path_of) = self.source_path
243 && let Some(path) = path_of(&self.outer, node)
244 && let Ok(a) = quarb_archive::ArchiveAdapter::open(&path)
245 {
246 let inner = Inner::Archive(Box::new(ComposeAdapter::new(a)));
247 let mut grafts = self.grafts.borrow_mut();
248 grafts.push(Graft { outer: node, inner });
249 return Some(grafts.len() - 1);
250 }
251 let content = match self.outer.default_value(node)? {
252 Value::Str(s) => s,
253 _ => return None,
254 };
255 let inner = parse_inner(&name, &content)?;
256 let mut grafts = self.grafts.borrow_mut();
257 grafts.push(Graft { outer: node, inner });
258 Some(grafts.len() - 1)
259 })();
260 self.probed.borrow_mut().insert(node, g);
261 g
262 }
263
264 fn wrap(&self, graft: usize, inner: NodeId) -> NodeId {
267 let grafts = self.grafts.borrow();
268 if inner == grafts[graft].inner.adapter().root() {
269 grafts[graft].outer
270 } else {
271 drop(grafts);
272 self.intern(graft, inner)
273 }
274 }
275}
276
277impl<A: AstAdapter> AstAdapter for ComposeAdapter<A> {
278 fn root(&self) -> NodeId {
279 self.outer.root()
280 }
281
282 fn children(&self, node: NodeId) -> Vec<NodeId> {
283 match self.split(node) {
284 Some((g, inner)) => {
285 let ids: Vec<NodeId> = {
286 let grafts = self.grafts.borrow();
287 grafts[g].inner.adapter().children(inner)
288 };
289 ids.into_iter().map(|c| self.wrap(g, c)).collect()
290 }
291 None => {
292 let outer = self.outer.children(node);
293 if !outer.is_empty() {
294 return outer;
295 }
296 match self.graft_at(node) {
297 Some(g) => {
298 let ids: Vec<NodeId> = {
299 let grafts = self.grafts.borrow();
300 let a = grafts[g].inner.adapter();
301 a.children(a.root())
302 };
303 ids.into_iter().map(|c| self.wrap(g, c)).collect()
304 }
305 None => Vec::new(),
306 }
307 }
308 }
309 }
310
311 fn name(&self, node: NodeId) -> Option<String> {
312 match self.split(node) {
313 Some((g, inner)) => self.grafts.borrow()[g].inner.adapter().name(inner),
314 None => self.outer.name(node),
315 }
316 }
317
318 fn parent(&self, node: NodeId) -> Option<NodeId> {
319 match self.split(node) {
320 Some((g, inner)) => {
321 let p = self.grafts.borrow()[g].inner.adapter().parent(inner)?;
322 Some(self.wrap(g, p))
323 }
324 None => self.outer.parent(node),
325 }
326 }
327
328 fn traits(&self, node: NodeId) -> Vec<String> {
329 match self.split(node) {
330 Some((g, inner)) => self.grafts.borrow()[g].inner.adapter().traits(inner),
331 None => self.outer.traits(node),
332 }
333 }
334
335 fn property(&self, node: NodeId, name: &str) -> Option<Value> {
336 match self.split(node) {
337 Some((g, inner)) => self.grafts.borrow()[g]
338 .inner
339 .adapter()
340 .property(inner, name),
341 None => self.outer.property(node, name),
342 }
343 }
344
345 fn default_value(&self, node: NodeId) -> Option<Value> {
346 match self.split(node) {
347 Some((g, inner)) => self.grafts.borrow()[g].inner.adapter().default_value(inner),
348 None => self.outer.default_value(node),
349 }
350 }
351
352 fn metadata(&self, node: NodeId, key: &str) -> Option<Value> {
353 match self.split(node) {
354 Some((g, inner)) => self.grafts.borrow()[g].inner.adapter().metadata(inner, key),
355 None => self.outer.metadata(node, key),
356 }
357 }
358
359 fn resolve(&self, node: NodeId, property: &str, hint: Option<&str>) -> Option<NodeId> {
360 match self.split(node) {
361 Some((g, inner)) => {
362 let t = self.grafts.borrow()[g]
363 .inner
364 .adapter()
365 .resolve(inner, property, hint)?;
366 Some(self.wrap(g, t))
367 }
368 None => self.outer.resolve(node, property, hint),
369 }
370 }
371
372 fn links(&self, node: NodeId) -> Vec<(String, NodeId)> {
373 match self.split(node) {
374 Some((g, inner)) => {
375 let ls: Vec<(String, NodeId)> = {
376 let grafts = self.grafts.borrow();
377 grafts[g].inner.adapter().links(inner)
378 };
379 ls.into_iter().map(|(l, n)| (l, self.wrap(g, n))).collect()
380 }
381 None => self.outer.links(node),
382 }
383 }
384
385 fn backlinks(&self, node: NodeId) -> Vec<(String, NodeId)> {
386 match self.split(node) {
387 Some((g, inner)) => {
388 let ls: Vec<(String, NodeId)> = {
389 let grafts = self.grafts.borrow();
390 grafts[g].inner.adapter().backlinks(inner)
391 };
392 ls.into_iter().map(|(l, n)| (l, self.wrap(g, n))).collect()
393 }
394 None => self.outer.backlinks(node),
395 }
396 }
397
398 fn link_property(
399 &self,
400 source: NodeId,
401 label: &str,
402 target: NodeId,
403 name: &str,
404 ) -> Option<Value> {
405 match (self.split(source), self.split(target)) {
408 (Some((g, src)), Some((gt, tgt))) if g == gt => self.grafts.borrow()[g]
409 .inner
410 .adapter()
411 .link_property(src, label, tgt, name),
412 (None, None) => self.outer.link_property(source, label, target, name),
413 _ => None,
414 }
415 }
416}