1use quarb::{AstAdapter, NodeId, Value};
28use std::cell::RefCell;
29use std::collections::HashMap;
30
31enum Inner {
33 Json(quarb_json::JsonAdapter),
34 Xml(quarb_xml::XmlAdapter),
35 Html(quarb_html::HtmlAdapter),
36 Csv(quarb_csv::CsvAdapter),
37 Code(quarb_code::CodeAdapter),
38}
39
40impl Inner {
41 fn adapter(&self) -> &dyn AstAdapter {
42 match self {
43 Inner::Json(a) => a,
44 Inner::Xml(a) => a,
45 Inner::Html(a) => a,
46 Inner::Csv(a) => a,
47 Inner::Code(a) => a,
48 }
49 }
50
51 fn locator(&self, node: NodeId) -> String {
52 match self {
53 Inner::Json(a) => a.pointer(node),
54 Inner::Xml(a) => a.locator(node),
55 Inner::Html(a) => a.locator(node),
56 Inner::Csv(a) => a.locator(node),
57 Inner::Code(a) => a.locator(node),
58 }
59 }
60}
61
62fn parse_inner(name: &str, content: &str) -> Option<Inner> {
64 let ext = name.rsplit('.').next().unwrap_or("").to_ascii_lowercase();
65 match ext.as_str() {
66 "json" => {
67 return quarb_json::JsonAdapter::parse(content)
68 .ok()
69 .map(Inner::Json);
70 }
71 "xml" | "svg" | "xhtml" => {
72 return quarb_xml::XmlAdapter::parse(content).ok().map(Inner::Xml);
73 }
74 "html" | "htm" => return Some(Inner::Html(quarb_html::HtmlAdapter::parse(content))),
75 "yaml" | "yml" => return quarb_yaml::parse(content).ok().map(Inner::Json),
76 "toml" => return quarb_toml::parse(content).ok().map(Inner::Json),
77 "md" | "markdown" => return Some(Inner::Html(quarb_markdown::parse(content))),
78 "csv" => return quarb_csv::CsvAdapter::parse(content).ok().map(Inner::Csv),
79 "tsv" => {
80 return quarb_csv::CsvAdapter::parse_with_delimiter(content, b'\t')
81 .ok()
82 .map(Inner::Csv);
83 }
84 ext if quarb_code::supported(ext) => {
85 return quarb_code::CodeAdapter::parse(content, ext)
86 .ok()
87 .map(Inner::Code);
88 }
89 _ => {}
90 }
91 let t = content.trim_start();
93 if t.starts_with('{') || t.starts_with('[') {
94 return quarb_json::JsonAdapter::parse(content)
95 .ok()
96 .map(Inner::Json);
97 }
98 if t.starts_with("<?xml") {
99 return quarb_xml::XmlAdapter::parse(content).ok().map(Inner::Xml);
100 }
101 None
102}
103
104struct Graft {
106 outer: NodeId,
107 inner: Inner,
108}
109
110const GRAFT_BIT: u64 = 1 << 55;
119
120pub struct ComposeAdapter<A: AstAdapter> {
122 outer: A,
123 grafts: RefCell<Vec<Graft>>,
124 probed: RefCell<HashMap<NodeId, Option<usize>>>,
127 interned: RefCell<HashMap<(usize, NodeId), NodeId>>,
129 reverse: RefCell<Vec<(usize, NodeId)>>,
130}
131
132impl<A: AstAdapter> ComposeAdapter<A> {
133 pub fn new(outer: A) -> Self {
134 ComposeAdapter {
135 outer,
136 grafts: RefCell::new(Vec::new()),
137 probed: RefCell::new(HashMap::new()),
138 interned: RefCell::new(HashMap::new()),
139 reverse: RefCell::new(Vec::new()),
140 }
141 }
142
143 pub fn outer(&self) -> &A {
145 &self.outer
146 }
147
148 pub fn locator(&self, node: NodeId, outer_locator: impl Fn(NodeId) -> String) -> String {
151 match self.split(node) {
152 None => outer_locator(node),
153 Some((g, inner)) => {
154 let grafts = self.grafts.borrow();
155 let graft = &grafts[g];
156 format!(
157 "{}!{}",
158 outer_locator(graft.outer),
159 graft.inner.locator(inner)
160 )
161 }
162 }
163 }
164
165 fn split(&self, node: NodeId) -> Option<(usize, NodeId)> {
167 if node.0 & GRAFT_BIT == 0 {
168 return None;
169 }
170 self.reverse
171 .borrow()
172 .get((node.0 & !GRAFT_BIT) as usize)
173 .copied()
174 }
175
176 fn intern(&self, graft: usize, inner: NodeId) -> NodeId {
177 if let Some(&id) = self.interned.borrow().get(&(graft, inner)) {
178 return id;
179 }
180 let mut rev = self.reverse.borrow_mut();
181 let id = NodeId(GRAFT_BIT | rev.len() as u64);
182 rev.push((graft, inner));
183 self.interned.borrow_mut().insert((graft, inner), id);
184 id
185 }
186
187 fn graft_at(&self, node: NodeId) -> Option<usize> {
191 if let Some(&g) = self.probed.borrow().get(&node) {
192 return g;
193 }
194 let g = (|| {
195 if !self.outer.children(node).is_empty() {
196 return None;
197 }
198 let name = self.outer.name(node)?;
199 let content = match self.outer.default_value(node)? {
200 Value::Str(s) => s,
201 _ => return None,
202 };
203 let inner = parse_inner(&name, &content)?;
204 let mut grafts = self.grafts.borrow_mut();
205 grafts.push(Graft { outer: node, inner });
206 Some(grafts.len() - 1)
207 })();
208 self.probed.borrow_mut().insert(node, g);
209 g
210 }
211
212 fn wrap(&self, graft: usize, inner: NodeId) -> NodeId {
215 let grafts = self.grafts.borrow();
216 if inner == grafts[graft].inner.adapter().root() {
217 grafts[graft].outer
218 } else {
219 drop(grafts);
220 self.intern(graft, inner)
221 }
222 }
223}
224
225impl<A: AstAdapter> AstAdapter for ComposeAdapter<A> {
226 fn root(&self) -> NodeId {
227 self.outer.root()
228 }
229
230 fn children(&self, node: NodeId) -> Vec<NodeId> {
231 match self.split(node) {
232 Some((g, inner)) => {
233 let ids: Vec<NodeId> = {
234 let grafts = self.grafts.borrow();
235 grafts[g].inner.adapter().children(inner)
236 };
237 ids.into_iter().map(|c| self.wrap(g, c)).collect()
238 }
239 None => {
240 let outer = self.outer.children(node);
241 if !outer.is_empty() {
242 return outer;
243 }
244 match self.graft_at(node) {
245 Some(g) => {
246 let ids: Vec<NodeId> = {
247 let grafts = self.grafts.borrow();
248 let a = grafts[g].inner.adapter();
249 a.children(a.root())
250 };
251 ids.into_iter().map(|c| self.wrap(g, c)).collect()
252 }
253 None => Vec::new(),
254 }
255 }
256 }
257 }
258
259 fn name(&self, node: NodeId) -> Option<String> {
260 match self.split(node) {
261 Some((g, inner)) => self.grafts.borrow()[g].inner.adapter().name(inner),
262 None => self.outer.name(node),
263 }
264 }
265
266 fn parent(&self, node: NodeId) -> Option<NodeId> {
267 match self.split(node) {
268 Some((g, inner)) => {
269 let p = self.grafts.borrow()[g].inner.adapter().parent(inner)?;
270 Some(self.wrap(g, p))
271 }
272 None => self.outer.parent(node),
273 }
274 }
275
276 fn traits(&self, node: NodeId) -> Vec<String> {
277 match self.split(node) {
278 Some((g, inner)) => self.grafts.borrow()[g].inner.adapter().traits(inner),
279 None => self.outer.traits(node),
280 }
281 }
282
283 fn property(&self, node: NodeId, name: &str) -> Option<Value> {
284 match self.split(node) {
285 Some((g, inner)) => self.grafts.borrow()[g]
286 .inner
287 .adapter()
288 .property(inner, name),
289 None => self.outer.property(node, name),
290 }
291 }
292
293 fn default_value(&self, node: NodeId) -> Option<Value> {
294 match self.split(node) {
295 Some((g, inner)) => self.grafts.borrow()[g].inner.adapter().default_value(inner),
296 None => self.outer.default_value(node),
297 }
298 }
299
300 fn metadata(&self, node: NodeId, key: &str) -> Option<Value> {
301 match self.split(node) {
302 Some((g, inner)) => self.grafts.borrow()[g].inner.adapter().metadata(inner, key),
303 None => self.outer.metadata(node, key),
304 }
305 }
306
307 fn resolve(&self, node: NodeId, property: &str, hint: Option<&str>) -> Option<NodeId> {
308 match self.split(node) {
309 Some((g, inner)) => {
310 let t = self.grafts.borrow()[g]
311 .inner
312 .adapter()
313 .resolve(inner, property, hint)?;
314 Some(self.wrap(g, t))
315 }
316 None => self.outer.resolve(node, property, hint),
317 }
318 }
319
320 fn links(&self, node: NodeId) -> Vec<(String, NodeId)> {
321 match self.split(node) {
322 Some((g, inner)) => {
323 let ls: Vec<(String, NodeId)> = {
324 let grafts = self.grafts.borrow();
325 grafts[g].inner.adapter().links(inner)
326 };
327 ls.into_iter().map(|(l, n)| (l, self.wrap(g, n))).collect()
328 }
329 None => self.outer.links(node),
330 }
331 }
332
333 fn backlinks(&self, node: NodeId) -> Vec<(String, NodeId)> {
334 match self.split(node) {
335 Some((g, inner)) => {
336 let ls: Vec<(String, NodeId)> = {
337 let grafts = self.grafts.borrow();
338 grafts[g].inner.adapter().backlinks(inner)
339 };
340 ls.into_iter().map(|(l, n)| (l, self.wrap(g, n))).collect()
341 }
342 None => self.outer.backlinks(node),
343 }
344 }
345
346 fn link_property(
347 &self,
348 source: NodeId,
349 label: &str,
350 target: NodeId,
351 name: &str,
352 ) -> Option<Value> {
353 match (self.split(source), self.split(target)) {
356 (Some((g, src)), Some((gt, tgt))) if g == gt => self.grafts.borrow()[g]
357 .inner
358 .adapter()
359 .link_property(src, label, tgt, name),
360 (None, None) => self.outer.link_property(source, label, target, name),
361 _ => None,
362 }
363 }
364}