1use anyhow::{bail, Result};
30use bytes::Buf;
31use chrono::{DateTime, NaiveDate, Utc};
32use compact_str::CompactString;
33use futures::future;
34use fxhash::FxHashMap;
35use immutable_chunkmap::set::SetS as Set;
36use log::{error, warn};
37use netidx_core::pack::Pack;
38use netidx_derive::Pack;
39use parser::LeafTbl;
40use serde::{Deserialize, Serialize};
41use sled::IVec;
42use smallvec::SmallVec;
43use std::{
44 any::Any,
45 cmp::{self, Ordering},
46 collections::{BTreeMap, HashMap},
47 fmt::{Debug, Display},
48 io::SeekFrom,
49 marker::PhantomData,
50 path::{Path, PathBuf},
51 sync::Arc,
52 time::UNIX_EPOCH,
53};
54use tokio::{
55 fs::{self, File, OpenOptions},
56 io::{AsyncBufReadExt, AsyncSeekExt, AsyncWriteExt, BufStream},
57 task,
58};
59
60pub mod parser;
61#[cfg(test)]
62mod test;
63
64#[derive(Debug, Clone)]
66pub enum Query {
67 Eq(Arc<dyn IndexableField + Send + Sync>),
68 Gt(Arc<dyn IndexableField + Send + Sync>),
69 Gte(Arc<dyn IndexableField + Send + Sync>),
70 Lt(Arc<dyn IndexableField + Send + Sync>),
71 Lte(Arc<dyn IndexableField + Send + Sync>),
72 And(Vec<Query>),
73 Or(Vec<Query>),
74 Not(Box<Query>),
75}
76
77impl Display for Query {
78 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79 use Query::*;
80 match self {
81 Eq(i) => write!(f, "{} == {}", i.key(), i),
82 Gt(i) => write!(f, "{} > {}", i.key(), i),
83 Gte(i) => write!(f, "{} >= {}", i.key(), i),
84 Lt(i) => write!(f, "{} < {}", i.key(), i),
85 Lte(i) => write!(f, "{} <= {}", i.key(), i),
86 Not(i) => match &**i {
87 Eq(i) => write!(f, "{} != {}", i.key(), i),
88 q => write!(f, "!{}", q),
89 },
90 And(qs) => {
91 let len = qs.len();
92 if len == 0 {
93 Ok(())
94 } else if len == 1 {
95 write!(f, "{}", &qs[0])
96 } else {
97 write!(f, "(")?;
98 for (i, q) in qs.iter().enumerate() {
99 if i < len - 1 {
100 write!(f, "{} && ", q)?
101 } else {
102 write!(f, "{}", q)?
103 }
104 }
105 write!(f, ")")
106 }
107 }
108 Or(qs) => {
109 let len = qs.len();
110 if len == 0 {
111 Ok(())
112 } else if len == 1 {
113 write!(f, "{}", &qs[0])
114 } else {
115 write!(f, "(")?;
116 for (i, q) in qs.iter().enumerate() {
117 if i < len - 1 {
118 write!(f, "{} || ", q)?
119 } else {
120 write!(f, "{}", q)?
121 }
122 }
123 write!(f, ")")
124 }
125 }
126 }
127 }
128}
129
130impl Query {
131 pub fn parse(leaf: &LeafTbl, s: &str) -> Result<Query> {
134 parser::parse_query(leaf, s)
135 }
136
137 pub fn matches<T: Indexable>(&self, t: &T) -> bool {
139 match self {
140 Self::Eq(i) => match t.dyn_partial_cmp(&**i) {
141 Some(Ordering::Equal) => true,
142 None | Some(Ordering::Greater | Ordering::Less) => false,
143 },
144 Self::Gt(i) => match t.dyn_partial_cmp(&**i) {
145 Some(Ordering::Greater) => true,
146 None | Some(Ordering::Equal | Ordering::Less) => false,
147 },
148 Self::Gte(i) => match t.dyn_partial_cmp(&**i) {
149 Some(Ordering::Greater | Ordering::Equal) => true,
150 None | Some(Ordering::Less) => false,
151 },
152 Self::Lt(i) => match t.dyn_partial_cmp(&**i) {
153 Some(Ordering::Less) => true,
154 None | Some(Ordering::Equal | Ordering::Greater) => false,
155 },
156 Self::Lte(i) => match t.dyn_partial_cmp(&**i) {
157 Some(Ordering::Less | Ordering::Equal) => true,
158 None | Some(Ordering::Greater) => false,
159 },
160 Self::And(qs) => qs.iter().all(|q| q.matches(t)),
161 Self::Or(qs) => qs.iter().any(|q| q.matches(t)),
162 Self::Not(q) => !q.matches(t),
163 }
164 }
165}
166
167pub trait IndexableField: Display + Debug + Send + Sync + Any {
171 fn key(&self) -> &'static str;
173
174 fn byte_compareable(&self) -> bool;
179
180 fn encode(&self, buf: &mut SmallVec<[u8; 128]>) -> Result<()>;
183
184 fn decode_cmp(&self, b: &[u8]) -> Result<Ordering> {
188 let mut buf: SmallVec<[u8; 128]> = SmallVec::new();
189 self.encode(&mut buf)?;
190 Ok(b.cmp(&buf[..]))
191 }
192
193 fn as_any(&self) -> &dyn Any;
198}
199
200pub trait Indexable {
202 type Iter: IntoIterator<Item = Box<dyn IndexableField>>;
203
204 fn index(&self) -> Self::Iter;
206
207 fn timestamp(&self) -> DateTime<Utc>;
215
216 fn dyn_partial_cmp(&self, i: &dyn IndexableField) -> Option<Ordering>;
219}
220
221fn min_key_with_prefix(index: &sled::Tree, k: &[u8]) -> Result<Option<IVec>> {
222 let mut iter = index.scan_prefix(k);
223 Ok(iter.next().transpose()?.map(|(k, _)| k))
224}
225
226fn max_key_with_prefix(index: &sled::Tree, k: &[u8]) -> Result<Option<IVec>> {
227 let mut iter = index.scan_prefix(k);
228 Ok(iter.next_back().transpose()?.map(|(k, _)| k))
229}
230
231#[derive(Debug, Clone, Copy, Pack, PartialEq, Eq, PartialOrd, Ord)]
233#[pack(unwrapped)]
234pub struct IndexEntry {
235 pub file: NaiveDate,
237 pub offset: u64,
239}
240
241#[derive(Debug)]
242struct JsonFile<T: Indexable + Serialize + for<'a> Deserialize<'a>> {
243 phantom: PhantomData<T>,
244 last_used: DateTime<Utc>,
245 file: Option<BufStream<File>>,
246 path: PathBuf,
247 name: NaiveDate,
248 len: u64,
249 pos: u64,
250 rbuf: String,
251 wbuf: Vec<u8>,
252}
253
254macro_rules! open_file {
255 ($self:expr) => {
256 if $self.file.is_some() {
257 $self.file.as_mut().unwrap()
258 } else {
259 let f = OpenOptions::new()
260 .read(true)
261 .append(true)
262 .write(true)
263 .create(true)
264 .open(&$self.path)
265 .await?;
266 let mut f = BufStream::new(f);
267 let len = f.seek(SeekFrom::End(0)).await?;
268 $self.len = len;
269 $self.pos = len;
270 $self.file = Some(f);
271 $self.file.as_mut().unwrap()
272 }
273 };
274}
275
276impl<T: Indexable + Serialize + for<'a> Deserialize<'a>> JsonFile<T> {
277 fn new(base: impl AsRef<Path>, name: NaiveDate) -> Self {
278 Self {
279 phantom: PhantomData,
280 last_used: DateTime::<Utc>::MIN_UTC,
281 file: None,
282 path: base.as_ref().join(&format!("{name}")),
283 name,
284 pos: 0,
285 len: 0,
286 rbuf: String::new(),
287 wbuf: Vec::new(),
288 }
289 }
290
291 async fn mtime(&self) -> Result<u128> {
292 Ok(fs::metadata(&self.path)
293 .await?
294 .modified()?
295 .duration_since(UNIX_EPOCH)?
296 .as_nanos())
297 }
298
299 fn close_if_idle(&mut self, now: DateTime<Utc>) {
300 if now - self.last_used > chrono::Duration::minutes(5) {
301 self.file = None
302 }
303 }
304
305 async fn get(&mut self, pos: u64) -> Result<Option<(u64, T)>> {
306 self.last_used = Utc::now();
307 let file = open_file!(self);
308 if pos != self.pos {
309 let new_pos = file.seek(SeekFrom::Start(pos)).await?;
310 if new_pos != pos {
311 bail!("{pos} doesn't exist in {:?}", &self.name)
312 }
313 self.pos = new_pos;
314 }
315 self.rbuf.clear();
316 let read = file.read_line(&mut self.rbuf).await?;
317 if self.rbuf.len() == 0 {
318 Ok(None)
319 } else {
320 self.pos = self.pos + read as u64;
321 Ok(Some((self.pos, serde_json::from_str(&self.rbuf.trim())?)))
322 }
323 }
324
325 async fn flush(&mut self) -> Result<()> {
326 if let Some(file) = &mut self.file {
327 file.flush().await?
328 }
329 Ok(())
330 }
331
332 fn db_name(&self) -> CompactString {
333 use std::fmt::Write;
334 let mut buf = CompactString::new("");
335 write!(buf, "{}", self.name).unwrap();
336 buf
337 }
338
339 async fn update_mtime(&mut self, db: &sled::Tree) -> Result<()> {
340 let mtime = self.mtime().await?;
341 db.insert(self.db_name().as_bytes(), &u128::to_be_bytes(mtime))?;
342 Ok(())
343 }
344
345 async fn append(&mut self, record: &T) -> Result<u64> {
348 self.last_used = Utc::now();
349 let file = open_file!(self);
350 let pos = self.pos;
351 if self.pos != self.len {
352 file.flush().await?;
353 self.pos = file.seek(SeekFrom::End(0)).await?;
354 self.len = self.pos;
355 }
356 self.wbuf.clear();
357 serde_json::to_writer(&mut self.wbuf, record)?;
358 self.wbuf.push(b'\n');
359 file.write_all(&self.wbuf).await?;
360 self.pos += self.wbuf.len() as u64;
361 self.len += self.wbuf.len() as u64;
362 Ok(pos)
363 }
364}
365
366pub struct IndexedJson<T: Indexable + Serialize + for<'a> Deserialize<'a>> {
368 phantom: PhantomData<T>,
369 base: PathBuf,
370 db: sled::Db,
371 index_status: sled::Tree,
372 trees: FxHashMap<CompactString, sled::Tree>,
373 files: BTreeMap<NaiveDate, JsonFile<T>>,
374 gc: DateTime<Utc>,
375 dirty: bool,
376}
377
378impl<T: Debug + Indexable + Serialize + for<'a> Deserialize<'a>> IndexedJson<T> {
379 pub async fn open(base: impl AsRef<Path>) -> Result<Self> {
382 if !base.as_ref().exists() {
383 fs::create_dir_all(&base).await?;
384 }
385 if !fs::metadata(&base).await?.is_dir() {
386 bail!("{:?} is not a directory", base.as_ref())
387 }
388 let db = task::spawn_blocking({
389 let path = base.as_ref().join("db");
390 move || sled::Config::new().flush_every_ms(None).path(path).open()
391 })
392 .await??;
393 let index_status = task::spawn_blocking({
394 let db = db.clone();
395 move || db.open_tree("status")
396 })
397 .await??;
398 let files = BTreeMap::new();
399 let mut t = Self {
400 phantom: PhantomData,
401 base: PathBuf::from(base.as_ref()),
402 db,
403 index_status,
404 trees: HashMap::default(),
405 files,
406 gc: Utc::now(),
407 dirty: false,
408 };
409 t.maybe_reindex().await?;
410 Ok(t)
411 }
412
413 pub fn path(&self) -> &Path {
415 &self.base
416 }
417
418 async fn rescan_files(&mut self) -> Result<()> {
421 self.trees.clear();
422 for name in self.db.tree_names() {
423 if name.starts_with(b"index_") {
424 let tree = self.db.open_tree(&name)?;
425 self.trees
426 .insert(CompactString::from_utf8_lossy(&*name), tree);
427 }
428 }
429 self.files.clear();
430 let mut dir = fs::read_dir(&self.base).await?;
431 loop {
432 match dir.next_entry().await? {
433 None => break,
434 Some(e) => {
435 if e.file_type().await?.is_file() {
436 let name = e.file_name();
437 let name = name.to_string_lossy();
438 if let Ok(d) = name.parse::<NaiveDate>() {
439 self.files.insert(d, JsonFile::new(&self.base, d));
440 }
441 }
442 }
443 }
444 }
445 Ok(())
446 }
447
448 async fn needs_reindex(&mut self) -> Result<bool> {
449 self.rescan_files().await?;
450 for file in self.files.values() {
451 match self.index_status.get(file.db_name().as_bytes())? {
452 None => return Ok(true),
453 Some(dbmtime) => {
454 let dbmtime = {
455 if dbmtime.len() != 16 {
456 return Ok(true);
457 }
458 (&mut &*dbmtime).get_u128()
459 };
460 let fsmtime = file.mtime().await?;
461 if fsmtime != dbmtime {
462 return Ok(true);
463 }
464 }
465 }
466 }
467 for r in self.index_status.iter() {
468 let (file, _) = r?;
469 let file = match String::from_utf8_lossy(&*file).parse::<NaiveDate>() {
470 Err(_) => return Ok(true),
471 Ok(file) => file,
472 };
473 if !self.files.contains_key(&file) {
474 return Ok(true);
475 }
476 }
477 Ok(false)
478 }
479
480 pub async fn maybe_reindex(&mut self) -> Result<()> {
496 if self.needs_reindex().await? {
497 self.reindex().await?
498 }
499 Ok(())
500 }
501
502 pub async fn reindex(&mut self) -> Result<()> {
504 for (_, tree) in self.trees.drain() {
505 tree.clear()?
506 }
507 self.index_status.clear()?;
508 self.rescan_files().await?;
509 for (file, f) in self.files.iter_mut() {
510 let mut pos = 0;
511 loop {
512 match f.get(pos).await {
513 Ok(Some((next_pos, t))) => {
514 let entry = IndexEntry {
515 file: *file,
516 offset: pos,
517 };
518 Self::index_record(&self.db, &mut self.trees, entry, &t)?;
519 pos = next_pos;
520 }
521 Ok(None) => break,
522 Err(e) => {
523 error!("error reindexing file {file} pos {pos} error {:?}", e);
524 break;
525 }
526 }
527 }
528 f.update_mtime(&self.index_status).await?
529 }
530 self.dirty = true;
531 self.flush().await?;
532 Ok(())
533 }
534
535 fn index_record<'a>(
540 db: &sled::Db,
541 trees: &mut FxHashMap<CompactString, sled::Tree>,
542 pos: IndexEntry,
543 record: &'a T,
544 ) -> Result<()> {
545 let mut kbuf: SmallVec<[u8; 128]> = SmallVec::new();
546 let mut vbuf: SmallVec<[u8; 16]> = SmallVec::new();
547 vbuf.resize(pos.encoded_len(), 0u8);
548 pos.encode(&mut &mut *vbuf)?;
549 for field in record.index() {
550 let tree = match trees.get(field.key()) {
551 Some(t) => t,
552 None => {
553 let tree = db.open_tree(format!("index_{}", field.key()))?;
554 trees
555 .entry(CompactString::from(field.key()))
556 .or_insert(tree)
557 }
558 };
559 kbuf.clear();
560 field.encode(&mut kbuf)?;
561 kbuf.push(b'/');
562 let count = match max_key_with_prefix(tree, &kbuf)? {
563 None => 0,
564 Some(k) if k.len() < 8 => 0,
565 Some(k) => (&mut &k[k.len() - 8..]).get_u64() + 1,
566 };
567 kbuf.extend_from_slice(&u64::to_be_bytes(count));
568 tree.insert(&kbuf[..], &vbuf[..])?;
569 }
570 Ok::<_, anyhow::Error>(())
571 }
572
573 fn maybe_gc(&mut self) {
574 let now = Utc::now();
575 if now - self.gc > chrono::Duration::minutes(5) {
576 self.gc = now;
577 for f in self.files.values_mut() {
578 f.close_if_idle(now)
579 }
580 }
581 }
582
583 pub async fn flush(&mut self) -> Result<()> {
587 if self.dirty {
588 future::join_all(self.files.values_mut().map(|f| async {
589 f.flush().await?;
590 f.update_mtime(&self.index_status).await
591 }))
592 .await
593 .into_iter()
594 .collect::<Result<Vec<_>>>()?;
595 task::spawn_blocking({
596 let db = self.db.clone();
597 move || db.flush()
598 })
599 .await??;
600 task::spawn_blocking({
601 let db = self.index_status.clone();
602 move || db.flush()
603 })
604 .await??;
605 for tree in self.trees.values() {
606 task::spawn_blocking({
607 let db = tree.clone();
608 move || db.flush()
609 })
610 .await??;
611 }
612 self.dirty = false;
613 }
614 Ok(())
615 }
616
617 pub async fn append(&mut self, record: &T) -> Result<()> {
620 let name = record.timestamp().date_naive();
621 let file = self
622 .files
623 .entry(name)
624 .or_insert_with(|| JsonFile::new(&self.base, name));
625 let pos = file.append(record).await?;
626 Self::index_record(
627 &self.db,
628 &mut self.trees,
629 IndexEntry {
630 file: name,
631 offset: pos,
632 },
633 record,
634 )?;
635 self.dirty = true;
636 Ok(self.maybe_gc())
637 }
638
639 pub fn first(&self) -> Option<IndexEntry> {
642 self.files.first_key_value().map(|(k, _)| IndexEntry {
643 file: *k,
644 offset: 0,
645 })
646 }
647
648 pub async fn get(&mut self, mut entry: IndexEntry) -> Result<Option<(IndexEntry, T)>> {
655 loop {
656 let file = self
657 .files
658 .entry(entry.file)
659 .or_insert_with(|| JsonFile::new(&self.base, entry.file));
660 match file.get(entry.offset).await? {
661 Some((offset, t)) => break Ok(Some((IndexEntry { offset, ..entry }, t))),
662 None => {
663 let mut r = self.files.range(entry.file..);
664 r.next(); match r.next() {
666 Some((e, _)) => {
667 entry = IndexEntry {
668 file: *e,
669 offset: 0,
670 };
671 }
672 None => break Ok(None),
673 }
674 }
675 }
676 }
677 }
678
679 pub fn query(&self, query: &Query) -> Result<Set<IndexEntry>> {
683 fn field_k(field: &dyn IndexableField) -> Result<SmallVec<[u8; 128]>> {
684 let mut buf = SmallVec::new();
685 field.encode(&mut buf)?;
686 buf.push(b'/');
687 Ok(buf)
688 }
689 fn insert(set: &mut Set<IndexEntry>, k: &[u8], mut v: &[u8]) {
690 match IndexEntry::decode(&mut v) {
691 Ok(ent) => {
692 set.insert_cow(ent);
693 }
694 Err(e) => {
695 warn!("could not decode entry with key {:?}, {:?}", k, e)
696 }
697 }
698 }
699 fn gt_gte(
700 trees: &FxHashMap<CompactString, sled::Tree>,
701 field: &dyn IndexableField,
702 gte: bool,
703 ) -> Result<Set<IndexEntry>> {
704 match trees.get(field.key()) {
705 None => Ok(Set::new()),
706 Some(tree) => {
707 let mut set = Set::new();
708 let key = field_k(field)?;
709 if field.byte_compareable() {
710 let min = match min_key_with_prefix(tree, &key[..])? {
711 Some(k) => k,
712 None => match tree.first()? {
713 Some((k, _)) => k,
714 None => return Ok(set),
715 },
716 };
717 for r in tree.range(&min[..]..) {
718 let (k, v) = r?;
719 let k = &k[0..cmp::min(key.len(), k.len() - 8)];
720 if (gte && k >= &key[..]) || k > &key[..] {
721 insert(&mut set, &*k, &*v)
722 }
723 }
724 } else {
725 for r in tree.iter() {
726 let (k, v) = r?;
727 match field.decode_cmp(&k[..cmp::min(key.len(), k.len() - 8) - 1])? {
728 Ordering::Less => insert(&mut set, &*k, &*v),
729 Ordering::Equal if gte => insert(&mut set, &*k, &*v),
730 Ordering::Equal | Ordering::Greater => (),
731 }
732 }
733 }
734 Ok(set)
735 }
736 }
737 }
738 fn lt_lte(
739 trees: &FxHashMap<CompactString, sled::Tree>,
740 field: &dyn IndexableField,
741 lte: bool,
742 ) -> Result<Set<IndexEntry>> {
743 match trees.get(field.key()) {
744 None => Ok(Set::new()),
745 Some(tree) => {
746 let key = field_k(field)?;
747 let mut set = Set::new();
748 if field.byte_compareable() {
749 let max = match max_key_with_prefix(tree, &key)? {
750 Some(k) => k,
751 None => match tree.last()? {
752 Some((k, _)) => k,
753 None => return Ok(set),
754 },
755 };
756 for r in tree.range(..=&max[..]) {
757 let (k, v) = r?;
758 let k = &k[0..cmp::min(key.len(), k.len() - 8)];
759 if (lte && k <= &key[..]) || k < &key[..] {
760 insert(&mut set, &*k, &*v)
761 }
762 }
763 } else {
764 for r in tree.iter() {
765 let (k, v) = r?;
766 match field.decode_cmp(&k[..cmp::min(key.len(), k.len() - 8) - 1])? {
767 Ordering::Greater => insert(&mut set, &*k, &*v),
768 Ordering::Equal if lte => insert(&mut set, &*k, &*v),
769 Ordering::Equal | Ordering::Less => (),
770 }
771 }
772 }
773 Ok(set)
774 }
775 }
776 }
777 fn eq(
778 trees: &FxHashMap<CompactString, sled::Tree>,
779 field: &dyn IndexableField,
780 ) -> Result<Set<IndexEntry>> {
781 let mut set = Set::new();
782 match trees.get(field.key()) {
783 None => Ok(Set::new()),
784 Some(tree) => {
785 for r in tree.scan_prefix(&field_k(field)?) {
786 let (k, v) = r?;
787 insert(&mut set, &*k, &*v)
788 }
789 Ok(set)
790 }
791 }
792 }
793 fn all_for_key(
794 trees: &FxHashMap<CompactString, sled::Tree>,
795 field: &dyn IndexableField,
796 ) -> Result<Set<IndexEntry>> {
797 match trees.get(field.key()) {
798 None => Ok(Set::new()),
799 Some(tree) => {
800 let mut set = Set::new();
801 for r in tree.iter() {
802 let (k, v) = r?;
803 insert(&mut set, &*k, &*v)
804 }
805 Ok(set)
806 }
807 }
808 }
809 fn all(trees: &FxHashMap<CompactString, sled::Tree>) -> Result<Set<IndexEntry>> {
810 let mut set = Set::new();
811 for tree in trees.values() {
812 for r in tree.iter() {
813 let (k, v) = r?;
814 insert(&mut set, &*k, &*v)
815 }
816 }
817 Ok(set)
818 }
819 match query {
820 Query::Eq(field) => eq(&self.trees, &**field),
821 Query::Gt(field) => gt_gte(&self.trees, &**field, false),
822 Query::Gte(field) => gt_gte(&self.trees, &**field, true),
823 Query::Lt(field) => lt_lte(&self.trees, &**field, false),
824 Query::Lte(field) => lt_lte(&self.trees, &**field, true),
825 Query::And(qs) => Ok(qs
826 .iter()
827 .map(|q| self.query(q))
828 .collect::<Result<Vec<Set<_>>>>()?
829 .into_iter()
830 .fold(None, |acc: Option<Set<_>>, s| match acc {
831 Some(acc) => Some(acc.intersect(&s)),
832 None => Some(s),
833 })
834 .unwrap_or_else(Set::new)),
835 Query::Or(qs) => Ok(qs
836 .iter()
837 .map(|q| self.query(q))
838 .collect::<Result<Vec<_>>>()?
839 .into_iter()
840 .fold(Set::new(), |acc, s| acc.union(&s))),
841 Query::Not(q) => match &**q {
842 Query::Eq(field) => {
843 let matches = eq(&self.trees, &**field)?;
844 let all = all_for_key(&self.trees, &**field)?;
845 Ok(all.diff(&matches))
846 }
847 Query::Gt(field) => lt_lte(&self.trees, &**field, true),
848 Query::Gte(field) => lt_lte(&self.trees, &**field, false),
849 Query::Lt(field) => gt_gte(&self.trees, &**field, true),
850 Query::Lte(field) => gt_gte(&self.trees, &**field, false),
851 q @ Query::And(_) | q @ Query::Or(_) | q @ Query::Not(_) => {
852 let matches = self.query(q)?;
853 Ok(all(&self.trees)?.diff(&matches))
854 }
855 },
856 }
857 }
858}