use super::super::{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)
}
}
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 From<Problem> for Problems {
fn from(problem: Problem) -> Self {
let has_problems = |problem: &Problem| {
for cause in problem {
if cause.error.downcast_ref::<Problems>().is_some() {
return true;
}
}
false
};
if has_problems(&problem) {
for cause in problem {
if let Ok(problems) = cause.error.downcast::<Problems>() {
return *problems;
}
}
panic!("we should have found a Problems");
}
let mut problems = Problems::with_capacity(1);
problems.add(problem);
problems
}
}
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))
}
}