use super::super::{cause::*, error::*, implementation::*, problem::*, receiver::*};
use std::{any::*, collections::*, error::Error, fmt, slice::*};
pub const PROBLEMS_DISPLAY_PREFIX: &str = "• ";
#[derive(Debug, Default)]
pub struct Problems {
pub problems: Vector<Problem>,
pub critical_error_types: HashSet<TypeId>,
}
impl Problems {
pub fn with_capacity(capacity: usize) -> Self {
Vector::with_capacity(capacity).into()
}
pub fn is_empty(&self) -> bool {
self.problems.is_empty()
}
pub fn count(&self) -> usize {
self.problems.len()
}
pub fn iter(&self) -> Iter<'_, Problem> {
self.into_iter()
}
pub fn handle_type_as_critical<ErrorT>(&mut self)
where
ErrorT: Any + Error,
{
self.critical_error_types.insert(TypeId::of::<ErrorT>());
}
pub fn is_critical(&self, problem: &Problem) -> bool {
problem
.top()
.map(|cause| self.is_error_critical(&cause.error))
.unwrap_or(false)
}
pub fn is_error_critical(&self, error: &CapturedError) -> bool {
self.critical_error_types.contains(&error.type_id())
}
pub fn add<ProblemT>(&mut self, problem: ProblemT)
where
ProblemT: Into<Problem>,
{
self.problems.push(problem.into())
}
pub fn check(self) -> Result<Self, Self> {
if self.is_empty() { Ok(self) } else { Err(self) }
}
pub fn into_unique(self) -> Self {
Self::from_iter(self.iter_unique())
}
pub fn iter_unique(self) -> impl Iterator<Item = Problem> {
iter_unique_problems(self.problems)
}
pub fn iter_unique_refs<'this>(&'this self) -> impl Iterator<Item = &'this Problem> {
iter_unique_problem_refs(&self.problems)
}
pub fn flatten(self) -> Self {
if !self.iter().any(|problem| problem.has_error_type::<Self>()) {
return self;
}
let mut flat_problems = Self::default();
for problem in self {
let mut flat_problem = Problem::default();
for cause in problem {
if cause.error.downcast_ref::<Self>().is_some() {
let problems = cause.error.downcast::<Self>().expect("downcast");
flat_problems.problems.extend(problems.flatten().problems);
} else {
flat_problem.causes.push(cause);
}
}
flat_problems.add(flat_problem);
}
flat_problems
}
}
impl ProblemReceiver for Problems {
fn give(&mut self, problem: Problem) -> Result<(), Problem> {
match self.is_critical(&problem) {
true => Err(problem),
false => {
self.add(problem);
Ok(())
}
}
}
}
impl fmt::Display for Problems {
fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
let mut iterator = self.into_iter().peekable();
while let Some(problem) = iterator.next() {
write!(formatter, "{}{}", PROBLEMS_DISPLAY_PREFIX, problem)?;
if iterator.peek().is_some() {
writeln!(formatter)?;
}
}
Ok(())
}
}
impl Error for Problems {}
impl From<Vector<Problem>> for Problems {
fn from(problems: Vector<Problem>) -> Self {
Self {
problems,
critical_error_types: Default::default(),
}
}
}
impl<'this> IntoIterator for &'this Problems {
type Item = &'this Problem;
type IntoIter = Iter<'this, Problem>;
fn into_iter(self) -> Self::IntoIter {
self.problems.iter()
}
}
impl FromIterator<Problem> for Problems {
fn from_iter<IntoIteratorT>(iterator: IntoIteratorT) -> Self
where
IntoIteratorT: IntoIterator<Item = Problem>,
{
iterator.into_iter().collect::<Vector<_>>().into()
}
}
impl<ErrorT> FromIterator<ErrorT> for Problems
where
ErrorT: 'static + Error + Send + Sync,
{
fn from_iter<IntoIteratorT>(iterator: IntoIteratorT) -> Self
where
IntoIteratorT: IntoIterator<Item = ErrorT>,
{
Self::from_iter(iterator.into_iter().map(Problem::from))
}
}