core_crypto/error/
recursive.rs

1#![allow(missing_docs)]
2
3/// These errors wrap each of the module-specific errors in CoreCrypto.
4///
5/// The goal here is to reduce the need to redeclare each of these error
6/// types as an individual variant of a module-specific error type.
7#[derive(Debug)]
8pub enum RecursiveError {
9    Root {
10        context: &'static str,
11        source: Box<crate::Error>,
12    },
13    TransactionContext {
14        context: &'static str,
15        source: Box<crate::transaction_context::Error>,
16    },
17    E2e {
18        context: &'static str,
19        source: Box<crate::e2e_identity::Error>,
20    },
21    Mls {
22        context: &'static str,
23        source: Box<crate::mls::Error>,
24    },
25    MlsClient {
26        context: &'static str,
27        source: Box<crate::mls::session::Error>,
28    },
29    MlsConversation {
30        context: &'static str,
31        source: Box<crate::mls::conversation::Error>,
32    },
33    MlsCredential {
34        context: &'static str,
35        source: Box<crate::mls::credential::Error>,
36    },
37    #[cfg(test)]
38    Test(Box<crate::test_utils::TestError>),
39}
40
41impl RecursiveError {
42    pub fn root<E: Into<crate::Error>>(context: &'static str) -> impl FnOnce(E) -> Self {
43        move |into_source| Self::Root {
44            context,
45            source: Box::new(into_source.into()),
46        }
47    }
48
49    pub fn transaction<E: Into<crate::transaction_context::Error>>(context: &'static str) -> impl FnOnce(E) -> Self {
50        move |into_source| Self::TransactionContext {
51            context,
52            source: Box::new(into_source.into()),
53        }
54    }
55
56    pub fn e2e_identity<E: Into<crate::e2e_identity::Error>>(context: &'static str) -> impl FnOnce(E) -> Self {
57        move |into_source| Self::E2e {
58            context,
59            source: Box::new(into_source.into()),
60        }
61    }
62
63    pub fn mls<E: Into<crate::mls::Error>>(context: &'static str) -> impl FnOnce(E) -> Self {
64        move |into_source| Self::Mls {
65            context,
66            source: Box::new(into_source.into()),
67        }
68    }
69
70    pub fn mls_client<E: Into<crate::mls::session::Error>>(context: &'static str) -> impl FnOnce(E) -> Self {
71        move |into_source| Self::MlsClient {
72            context,
73            source: Box::new(into_source.into()),
74        }
75    }
76
77    pub fn mls_conversation<E: Into<crate::mls::conversation::Error>>(context: &'static str) -> impl FnOnce(E) -> Self {
78        move |into_source| Self::MlsConversation {
79            context,
80            source: Box::new(into_source.into()),
81        }
82    }
83
84    pub fn mls_credential<E: Into<crate::mls::credential::Error>>(context: &'static str) -> impl FnOnce(E) -> Self {
85        move |into_source| Self::MlsCredential {
86            context,
87            source: Box::new(into_source.into()),
88        }
89    }
90
91    #[cfg(test)]
92    pub(crate) fn test<E: Into<crate::test_utils::TestError>>() -> impl FnOnce(E) -> Self {
93        move |into_source| Self::Test(Box::new(into_source.into()))
94    }
95}
96
97impl std::fmt::Display for RecursiveError {
98    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
99        #[cfg(test)]
100        use std::ops::Deref;
101
102        let context = match self {
103            RecursiveError::Root { context, .. } => context,
104            RecursiveError::E2e { context, .. } => context,
105            RecursiveError::Mls { context, .. } => context,
106            RecursiveError::MlsClient { context, .. } => context,
107            RecursiveError::MlsConversation { context, .. } => context,
108            RecursiveError::MlsCredential { context, .. } => context,
109            RecursiveError::TransactionContext { context, .. } => context,
110            #[cfg(test)]
111            RecursiveError::Test(e) => return e.deref().fmt(f),
112        };
113        write!(f, "{}", context)
114    }
115}
116
117impl std::error::Error for RecursiveError {
118    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
119        match self {
120            RecursiveError::Root { source, .. } => Some(source.as_ref()),
121            RecursiveError::E2e { source, .. } => Some(source.as_ref()),
122            RecursiveError::Mls { source, .. } => Some(source.as_ref()),
123            RecursiveError::MlsClient { source, .. } => Some(source.as_ref()),
124            RecursiveError::MlsConversation { source, .. } => Some(source.as_ref()),
125            RecursiveError::MlsCredential { source, .. } => Some(source.as_ref()),
126            RecursiveError::TransactionContext { source, .. } => Some(source.as_ref()),
127            #[cfg(test)]
128            RecursiveError::Test(source) => Some(source.as_ref()),
129        }
130    }
131}
132
133/// Like [`Into`], but different, because we don't actually want to implement `Into` for our subordinate error types.
134///
135/// By forcing ourselves to map errors everywhere in order for question mark operators to work, we ensure that
136pub trait ToRecursiveError {
137    /// Construct a recursive error given the current context
138    fn construct_recursive(self, context: &'static str) -> RecursiveError;
139}
140
141macro_rules! impl_to_recursive_error_for {
142    ($($for:path => $variant:ident),+ $(,)?) => {
143        $(
144            impl ToRecursiveError for $for {
145                fn construct_recursive(self, context: &'static str) -> RecursiveError {
146                    RecursiveError::$variant {
147                        context,
148                        source: Box::new(self),
149                    }
150                }
151            }
152        )+
153    };
154}
155
156impl_to_recursive_error_for!(
157    crate::Error => Root,
158    crate::e2e_identity::Error => E2e,
159    crate::mls::Error => Mls,
160    crate::mls::session::Error => MlsClient,
161    crate::mls::conversation::Error => MlsConversation,
162    crate::mls::credential::Error => MlsCredential,
163    crate::transaction_context::Error => TransactionContext,
164);