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 "xml" | "svg" | "xhtml" => {
92 return quarb_xml::XmlAdapter::parse(content).ok().map(Inner::Xml);
93 }
94 "html" | "htm" => return Some(Inner::Html(quarb_html::HtmlAdapter::parse(content))),
95 "yaml" | "yml" => return quarb_yaml::parse(content).ok().map(Inner::Json),
96 "toml" => return quarb_toml::parse(content).ok().map(Inner::Json),
97 "md" | "markdown" => return Some(Inner::Html(quarb_markdown::parse(content))),
98 "csv" => return quarb_csv::CsvAdapter::parse(content).ok().map(Inner::Csv),
99 "tsv" => {
100 return quarb_csv::CsvAdapter::parse_with_delimiter(content, b'\t')
101 .ok()
102 .map(Inner::Csv);
103 }
104 ext if quarb_code::supported(ext) => {
105 return quarb_code::CodeAdapter::parse(content, ext)
106 .ok()
107 .map(Inner::Code);
108 }
109 _ => {}
110 }
111 let t = content.trim_start();
113 if t.starts_with('{') || t.starts_with('[') {
114 return quarb_json::JsonAdapter::parse(content)
115 .ok()
116 .map(Inner::Json);
117 }
118 if t.starts_with("<?xml") {
119 return quarb_xml::XmlAdapter::parse(content).ok().map(Inner::Xml);
120 }
121 None
122}
123
124struct Graft {
126 outer: NodeId,
127 inner: Inner,
128}
129
130const GRAFT_BIT: u64 = 1 << 55;
139
140pub struct ComposeAdapter<A: AstAdapter> {
142 outer: A,
143 grafts: RefCell<Vec<Graft>>,
144 probed: RefCell<HashMap<NodeId, Option<usize>>>,
147 interned: RefCell<HashMap<(usize, NodeId), NodeId>>,
149 reverse: RefCell<Vec<(usize, NodeId)>>,
150 source_path: Option<fn(&A, NodeId) -> Option<PathBuf>>,
154}
155
156impl<A: AstAdapter> ComposeAdapter<A> {
157 pub fn new(outer: A) -> Self {
158 ComposeAdapter {
159 outer,
160 grafts: RefCell::new(Vec::new()),
161 probed: RefCell::new(HashMap::new()),
162 interned: RefCell::new(HashMap::new()),
163 reverse: RefCell::new(Vec::new()),
164 source_path: None,
165 }
166 }
167
168 pub fn with_source_paths(outer: A, source_path: fn(&A, NodeId) -> Option<PathBuf>) -> Self {
174 ComposeAdapter {
175 source_path: Some(source_path),
176 ..Self::new(outer)
177 }
178 }
179
180 pub fn outer(&self) -> &A {
182 &self.outer
183 }
184
185 pub fn locator(&self, node: NodeId, outer_locator: impl Fn(NodeId) -> String) -> String {
188 match self.split(node) {
189 None => outer_locator(node),
190 Some((g, inner)) => {
191 let grafts = self.grafts.borrow();
192 let graft = &grafts[g];
193 format!(
194 "{}!{}",
195 outer_locator(graft.outer),
196 graft.inner.locator(inner)
197 )
198 }
199 }
200 }
201
202 fn split(&self, node: NodeId) -> Option<(usize, NodeId)> {
204 if node.0 & GRAFT_BIT == 0 {
205 return None;
206 }
207 self.reverse
208 .borrow()
209 .get((node.0 & !GRAFT_BIT) as usize)
210 .copied()
211 }
212
213 fn intern(&self, graft: usize, inner: NodeId) -> NodeId {
214 if let Some(&id) = self.interned.borrow().get(&(graft, inner)) {
215 return id;
216 }
217 let mut rev = self.reverse.borrow_mut();
218 let id = NodeId(GRAFT_BIT | rev.len() as u64);
219 rev.push((graft, inner));
220 self.interned.borrow_mut().insert((graft, inner), id);
221 id
222 }
223
224 fn graft_at(&self, node: NodeId) -> Option<usize> {
228 if let Some(&g) = self.probed.borrow().get(&node) {
229 return g;
230 }
231 let g = (|| {
232 if !self.outer.children(node).is_empty() {
233 return None;
234 }
235 let name = self.outer.name(node)?;
236 if archive_name(&name)
237 && let Some(path_of) = self.source_path
238 && let Some(path) = path_of(&self.outer, node)
239 && let Ok(a) = quarb_archive::ArchiveAdapter::open(&path)
240 {
241 let inner = Inner::Archive(Box::new(ComposeAdapter::new(a)));
242 let mut grafts = self.grafts.borrow_mut();
243 grafts.push(Graft { outer: node, inner });
244 return Some(grafts.len() - 1);
245 }
246 let content = match self.outer.default_value(node)? {
247 Value::Str(s) => s,
248 _ => return None,
249 };
250 let inner = parse_inner(&name, &content)?;
251 let mut grafts = self.grafts.borrow_mut();
252 grafts.push(Graft { outer: node, inner });
253 Some(grafts.len() - 1)
254 })();
255 self.probed.borrow_mut().insert(node, g);
256 g
257 }
258
259 fn wrap(&self, graft: usize, inner: NodeId) -> NodeId {
262 let grafts = self.grafts.borrow();
263 if inner == grafts[graft].inner.adapter().root() {
264 grafts[graft].outer
265 } else {
266 drop(grafts);
267 self.intern(graft, inner)
268 }
269 }
270}
271
272impl<A: AstAdapter> AstAdapter for ComposeAdapter<A> {
273 fn root(&self) -> NodeId {
274 self.outer.root()
275 }
276
277 fn children(&self, node: NodeId) -> Vec<NodeId> {
278 match self.split(node) {
279 Some((g, inner)) => {
280 let ids: Vec<NodeId> = {
281 let grafts = self.grafts.borrow();
282 grafts[g].inner.adapter().children(inner)
283 };
284 ids.into_iter().map(|c| self.wrap(g, c)).collect()
285 }
286 None => {
287 let outer = self.outer.children(node);
288 if !outer.is_empty() {
289 return outer;
290 }
291 match self.graft_at(node) {
292 Some(g) => {
293 let ids: Vec<NodeId> = {
294 let grafts = self.grafts.borrow();
295 let a = grafts[g].inner.adapter();
296 a.children(a.root())
297 };
298 ids.into_iter().map(|c| self.wrap(g, c)).collect()
299 }
300 None => Vec::new(),
301 }
302 }
303 }
304 }
305
306 fn name(&self, node: NodeId) -> Option<String> {
307 match self.split(node) {
308 Some((g, inner)) => self.grafts.borrow()[g].inner.adapter().name(inner),
309 None => self.outer.name(node),
310 }
311 }
312
313 fn parent(&self, node: NodeId) -> Option<NodeId> {
314 match self.split(node) {
315 Some((g, inner)) => {
316 let p = self.grafts.borrow()[g].inner.adapter().parent(inner)?;
317 Some(self.wrap(g, p))
318 }
319 None => self.outer.parent(node),
320 }
321 }
322
323 fn traits(&self, node: NodeId) -> Vec<String> {
324 match self.split(node) {
325 Some((g, inner)) => self.grafts.borrow()[g].inner.adapter().traits(inner),
326 None => self.outer.traits(node),
327 }
328 }
329
330 fn property(&self, node: NodeId, name: &str) -> Option<Value> {
331 match self.split(node) {
332 Some((g, inner)) => self.grafts.borrow()[g]
333 .inner
334 .adapter()
335 .property(inner, name),
336 None => self.outer.property(node, name),
337 }
338 }
339
340 fn default_value(&self, node: NodeId) -> Option<Value> {
341 match self.split(node) {
342 Some((g, inner)) => self.grafts.borrow()[g].inner.adapter().default_value(inner),
343 None => self.outer.default_value(node),
344 }
345 }
346
347 fn metadata(&self, node: NodeId, key: &str) -> Option<Value> {
348 match self.split(node) {
349 Some((g, inner)) => self.grafts.borrow()[g].inner.adapter().metadata(inner, key),
350 None => self.outer.metadata(node, key),
351 }
352 }
353
354 fn resolve(&self, node: NodeId, property: &str, hint: Option<&str>) -> Option<NodeId> {
355 match self.split(node) {
356 Some((g, inner)) => {
357 let t = self.grafts.borrow()[g]
358 .inner
359 .adapter()
360 .resolve(inner, property, hint)?;
361 Some(self.wrap(g, t))
362 }
363 None => self.outer.resolve(node, property, hint),
364 }
365 }
366
367 fn links(&self, node: NodeId) -> Vec<(String, NodeId)> {
368 match self.split(node) {
369 Some((g, inner)) => {
370 let ls: Vec<(String, NodeId)> = {
371 let grafts = self.grafts.borrow();
372 grafts[g].inner.adapter().links(inner)
373 };
374 ls.into_iter().map(|(l, n)| (l, self.wrap(g, n))).collect()
375 }
376 None => self.outer.links(node),
377 }
378 }
379
380 fn backlinks(&self, node: NodeId) -> Vec<(String, NodeId)> {
381 match self.split(node) {
382 Some((g, inner)) => {
383 let ls: Vec<(String, NodeId)> = {
384 let grafts = self.grafts.borrow();
385 grafts[g].inner.adapter().backlinks(inner)
386 };
387 ls.into_iter().map(|(l, n)| (l, self.wrap(g, n))).collect()
388 }
389 None => self.outer.backlinks(node),
390 }
391 }
392
393 fn link_property(
394 &self,
395 source: NodeId,
396 label: &str,
397 target: NodeId,
398 name: &str,
399 ) -> Option<Value> {
400 match (self.split(source), self.split(target)) {
403 (Some((g, src)), Some((gt, tgt))) if g == gt => self.grafts.borrow()[g]
404 .inner
405 .adapter()
406 .link_property(src, label, tgt, name),
407 (None, None) => self.outer.link_property(source, label, target, name),
408 _ => None,
409 }
410 }
411}