use core::{
fmt::{self, Write as _},
marker::PhantomData,
ops::ControlFlow,
};
use derail::{Error, ErrorExt as _, VisitContext, Visitor, VisitorExt as _};
use crate::{BufferFactory, buffer::Buffer, sealed::Sealed};
#[derive(Clone, Copy, Default)]
struct Element {
has_next_sibling: bool,
has_children: bool,
}
#[cfg_attr(
feature = "alloc",
doc = "\n\n[`HeapFactory`](crate::HeapFactory) does not have this \
limitation."
)]
pub fn display<'a, I, E, B>(errors: I) -> impl fmt::Display
where
I: IntoIterator<Item = &'a E> + Clone,
E: Error + ?Sized + 'a,
B: BufferFactory,
{
DisplayImpl(errors, PhantomData::<B>)
}
struct DisplayImpl<I, B>(I, PhantomData<B>);
impl<'a, I, E, B> fmt::Display for DisplayImpl<I, B>
where
I: IntoIterator<Item = &'a E> + Clone,
E: Error + ?Sized + 'a,
B: BufferFactory,
{
fn fmt(&self, mut f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[")?;
let mut visitor = VisitorImpl {
writer: &mut f,
result: Ok(()),
buffer: B::new(Sealed),
details: PhantomData::<E::Details>,
};
let _: ControlFlow<(), ()> = visitor.visit_many(self.0.clone());
visitor.result?;
write!(f, "]")
}
}
struct WriteEscaped<W>(W);
impl<W> fmt::Write for WriteEscaped<W>
where
W: fmt::Write,
{
fn write_str(&mut self, s: &str) -> fmt::Result {
write!(self.0, "{}", s.escape_debug())
}
}
struct VisitorImpl<W, B, D> {
writer: W,
result: fmt::Result,
buffer: B,
details: PhantomData<D>,
}
impl<W, B, D> Visitor for VisitorImpl<W, B, D>
where
W: fmt::Write,
B: Buffer<Element>,
{
type Details = D;
fn visit(
&mut self,
visitee: &dyn Error<Details = Self::Details>,
ctx: VisitContext<'_, Self::Details>,
) -> ControlFlow<()> {
attempt!(write!(self.writer, "\""), self.result);
attempt!(
write!(WriteEscaped(&mut self.writer), "{visitee}"),
self.result
);
attempt!(write!(self.writer, "\""), self.result);
let has_next_sibling = ctx.next_sibling().is_some();
let has_children = visitee.has_children();
if let Some(x) = self.buffer.last_mut(Sealed) {
x.has_next_sibling = has_next_sibling;
x.has_children = has_children;
}
if has_next_sibling && !has_children {
attempt!(write!(self.writer, ","), self.result);
}
ControlFlow::Continue(())
}
fn push(&mut self) -> ControlFlow<()> {
self.buffer.push(Sealed);
attempt!(write!(self.writer, ":["), self.result);
ControlFlow::Continue(())
}
fn pop(&mut self) -> ControlFlow<()> {
self.buffer.pop(Sealed);
attempt!(write!(self.writer, "]"), self.result);
if let Some(x) = self.buffer.last_mut(Sealed) {
if x.has_next_sibling && x.has_children {
attempt!(write!(self.writer, ","), self.result);
x.has_next_sibling = false;
x.has_children = false;
}
}
ControlFlow::Continue(())
}
}