use std::{borrow::Cow, ops::ControlFlow};
use derail::{Error, VisitContext, Visitor};
#[cfg(feature = "alloc")]
mod impls_alloc;
mod impls_core;
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord)]
pub(crate) enum Event<'a, D> {
Visit {
message: Cow<'a, str>,
next_sibling_message: Option<Cow<'a, str>>,
details: D,
},
Push,
Pop,
}
impl<'a, D> Event<'a, D> {
pub(crate) fn visit<S1, S2>(
message: S1,
details: D,
next_sibling_message: Option<S2>,
) -> Self
where
S1: Into<Cow<'a, str>>,
S2: Into<Cow<'a, str>>,
{
Self::Visit {
message: message.into(),
details,
next_sibling_message: next_sibling_message.map(Into::into),
}
}
}
pub(crate) struct TestVisitor<D> {
pub(crate) events: Vec<Event<'static, D>>,
pub(crate) break_on_ascend: bool,
}
impl<D> TestVisitor<D> {
pub(crate) fn new() -> Self {
Self {
break_on_ascend: false,
events: Vec::new(),
}
}
}
impl<D> Visitor for TestVisitor<D> {
type Details = D;
fn visit(
&mut self,
visitee: &dyn Error<Details = Self::Details>,
ctx: VisitContext<'_, Self::Details>,
) -> ControlFlow<()> {
self.events.push(Event::visit(
visitee.to_string(),
visitee.details(),
ctx.next_sibling().map(ToString::to_string),
));
ControlFlow::Continue(())
}
fn push(&mut self) -> ControlFlow<()> {
self.events.push(Event::Push);
ControlFlow::Continue(())
}
fn pop(&mut self) -> ControlFlow<()> {
if self.break_on_ascend {
return ControlFlow::Break(());
}
self.events.push(Event::Pop);
ControlFlow::Continue(())
}
}
#[test]
fn dyn_safe() {
#[expect(dead_code)]
fn inner(_: &dyn Visitor<Details = ()>) {}
}