1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use core::fmt;
use std::{error::Error, sync::Arc};

use thiserror::Error;

#[cfg(send_sync)]
pub type ContextErrorSource = Box<dyn Error + Send + Sync + 'static>;
#[cfg(not(send_sync))]
pub type ContextErrorSource = Box<dyn Error + 'static>;

#[derive(Debug, Error)]
#[error(
    "In {fn_ident}{}{}{}",
    if self.label.is_empty() { "" } else { ", label = '" },
    self.label,
    if self.label.is_empty() { "" } else { "'" }
)]
pub struct ContextError {
    pub fn_ident: &'static str,
    #[source]
    pub source: ContextErrorSource,
    pub label: String,
}

/// Don't use this error type with thiserror's #[error(transparent)]
#[derive(Clone)]
pub struct MultiError {
    inner: Vec<Arc<dyn Error + Send + Sync + 'static>>,
}

impl MultiError {
    pub fn new<T: Error + Send + Sync + 'static>(
        iter: impl ExactSizeIterator<Item = T>,
    ) -> Option<Self> {
        if iter.len() == 0 {
            return None;
        }
        Some(Self {
            inner: iter.map(Box::from).map(Arc::from).collect(),
        })
    }

    pub fn errors(&self) -> Box<dyn Iterator<Item = &(dyn Error + Send + Sync + 'static)> + '_> {
        Box::new(self.inner.iter().map(|e| e.as_ref()))
    }
}

impl fmt::Debug for MultiError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        fmt::Debug::fmt(&self.inner[0], f)
    }
}

impl fmt::Display for MultiError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> {
        fmt::Display::fmt(&self.inner[0], f)
    }
}

impl Error for MultiError {
    fn source(&self) -> Option<&(dyn Error + 'static)> {
        self.inner[0].source()
    }
}