use alloc::vec;
use alloc::vec::Vec;
use core::error::Error;
use core::fmt::{Debug, Display};
use crate::gerr::Source;
use crate::{Config, DataSource, GErr, GErrBox, GErrSource, IdSource};
impl<'a, C: Config, D> IntoIterator for &'a GErr<C, D>
where
C::Id: IdSource + 'static,
D: DataSource + 'static,
{
type Item = GErrNode<'a, C, D>;
type IntoIter = GErrTree<'a, C, D>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.iter()
}
}
impl<'a, C: Config, D> IntoIterator for &'a GErrBox<C, D>
where
C::Id: IdSource + 'static,
D: DataSource + 'static,
{
type Item = GErrNode<'a, C, D>;
type IntoIter = GErrTree<'a, C, D>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
(*self).iter()
}
}
impl<C: Config, D> GErr<C, D>
where
C::Id: IdSource + 'static,
D: DataSource + 'static,
{
#[inline]
pub fn iter(&self) -> GErrTree<'_, C, D> {
GErrTree {
nodes: vec![GErrNode::Root(self)],
}
}
}
pub enum GErrNode<'a, C: Config, D> {
Root(&'a GErr<C, D>),
LeafErr(&'a (dyn Error + Send + Sync + 'static)),
LeafGErr(&'a GErrSource),
}
impl<'a, C: Config, D> Display for GErrNode<'a, C, D>
where
C::Id: IdSource + 'static,
D: DataSource + 'static,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Root(root) => write!(f, "{}", root),
Self::LeafErr(err) => write!(f, "{}", err),
Self::LeafGErr(gerr) => write!(f, "{}", gerr),
}
}
}
impl<'a, C: Config, D> Debug for GErrNode<'a, C, D>
where
C::Id: IdSource + 'static,
D: DataSource + 'static,
{
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
match self {
Self::Root(root) => write!(f, "root: {:#?}", root),
Self::LeafErr(err) => write!(f, "err: {:#?}", err),
Self::LeafGErr(gerr) => write!(f, "gerr: {:#?}", gerr),
}
}
}
pub struct GErrTree<'a, C: Config, D> {
nodes: Vec<GErrNode<'a, C, D>>,
}
impl<'a, C: Config, D> Iterator for GErrTree<'a, C, D>
where
C::Id: IdSource + 'static,
D: DataSource + 'static,
{
type Item = GErrNode<'a, C, D>;
fn next(&mut self) -> Option<Self::Item> {
let current = self.nodes.pop()?;
match ¤t {
GErrNode::Root(gerr) => {
if let Some(sources) = gerr.sources() {
for source in sources.iter().rev() {
match &source {
Source::Err(err) => {
self.nodes.push(GErrNode::LeafErr(err.as_ref()));
}
Source::GErr(gerr) => {
self.nodes.push(GErrNode::LeafGErr(gerr.as_ref()));
}
}
}
}
}
GErrNode::LeafErr(_) => {}
GErrNode::LeafGErr(gerr) => {
if let Some(sources) = gerr.sources.as_deref() {
for source in sources.iter().rev() {
match &source {
Source::Err(err) => {
self.nodes.push(GErrNode::LeafErr(err.as_ref()));
}
Source::GErr(gerr) => {
self.nodes.push(GErrNode::LeafGErr(gerr.as_ref()));
}
}
}
}
}
}
Some(current)
}
}