use predicates::Predicate;
use std::fmt;
use crate::{
CapturedEvents, CapturedSpan, CapturedSpans, DescendantEvents, DescendantSpans, Storage,
};
pub trait ScanExt<'a>: Sized {
fn scan_spans(self) -> Scanner<Self, CapturedSpans<'a>>;
fn scan_events(self) -> Scanner<Self, CapturedEvents<'a>>;
}
impl<'a> ScanExt<'a> for &'a Storage {
fn scan_spans(self) -> Scanner<Self, CapturedSpans<'a>> {
Scanner::new(self, Storage::all_spans)
}
fn scan_events(self) -> Scanner<Self, CapturedEvents<'a>> {
Scanner::new(self, Storage::all_events)
}
}
impl<'a> ScanExt<'a> for CapturedSpan<'a> {
fn scan_spans(self) -> Scanner<Self, CapturedSpans<'a>> {
Scanner::new(self, |span| span.children())
}
fn scan_events(self) -> Scanner<Self, CapturedEvents<'a>> {
Scanner::new(self, |span| span.events())
}
}
impl<'a> CapturedSpan<'a> {
pub fn deep_scan_spans(self) -> Scanner<Self, DescendantSpans<'a>> {
Scanner::new(self, |span| span.descendants())
}
pub fn deep_scan_events(self) -> Scanner<Self, DescendantEvents<'a>> {
Scanner::new(self, |span| span.descendant_events())
}
}
#[derive(Debug)]
pub struct Scanner<T, I> {
items: T,
into_iter: fn(T) -> I,
}
impl<T: Clone, I> Clone for Scanner<T, I> {
fn clone(&self) -> Self {
Self {
items: self.items.clone(),
into_iter: self.into_iter,
}
}
}
impl<T: Copy, I> Copy for Scanner<T, I> {}
impl<T, I> Scanner<T, I>
where
I: Iterator,
I::Item: fmt::Debug,
{
fn new(items: T, into_iter: fn(T) -> I) -> Self {
Self { items, into_iter }
}
fn iter(self) -> I {
(self.into_iter)(self.items)
}
pub fn single<P: Predicate<I::Item> + ?Sized>(self, predicate: &P) -> I::Item {
let mut iter = self.iter();
let first = iter
.find(|item| predicate.eval(item))
.unwrap_or_else(|| panic!("no items have matched predicate {predicate}"));
let second = iter.find(|item| predicate.eval(item));
if let Some(second) = second {
panic!(
"multiple items match predicate {predicate}: {:#?}",
[first, second]
);
}
first
}
pub fn first<P: Predicate<I::Item> + ?Sized>(self, predicate: &P) -> I::Item {
let mut iter = self.iter();
iter.find(|item| predicate.eval(item))
.unwrap_or_else(|| panic!("no items have matched predicate {predicate}"))
}
pub fn all<P: Predicate<I::Item> + ?Sized>(self, predicate: &P) {
let mut iter = self.iter();
if let Some(item) = iter.find(|item| !predicate.eval(item)) {
panic!("item does not match predicate {predicate}: {item:#?}");
}
}
pub fn none<P: Predicate<I::Item> + ?Sized>(self, predicate: &P) {
let mut iter = self.iter();
if let Some(item) = iter.find(|item| predicate.eval(item)) {
panic!("item matched predicate {predicate}: {item:#?}");
}
}
}
impl<T, I> Scanner<T, I>
where
I: DoubleEndedIterator,
I::Item: fmt::Debug,
{
pub fn last<P: Predicate<I::Item> + ?Sized>(self, predicate: &P) -> I::Item {
let mut iter = self.iter().rev();
iter.find(|item| predicate.eval(item))
.unwrap_or_else(|| panic!("no items have matched predicate {predicate}"))
}
}