1// Wire
2// Copyright (C) 2022 Wire Swiss GmbH
34// This program is free software: you can redistribute it and/or modify
5// it under the terms of the GNU General Public License as published by
6// the Free Software Foundation, either version 3 of the License, or
7// (at your option) any later version.
89// This program is distributed in the hope that it will be useful,
10// but WITHOUT ANY WARRANTY; without even the implied warranty of
11// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12// GNU General Public License for more details.
1314// You should have received a copy of the GNU General Public License
15// along with this program. If not, see http://www.gnu.org/licenses/.
1617/// These errors wrap each of the module-specific errors in CoreCrypto.
18///
19/// The goal here is to reduce the need to redeclare each of these error
20/// types as an individual variant of a module-specific error type.
21#[derive(Debug)]
22pub enum RecursiveError {
23/// Wrap a [crate::Error] for recursion.
24Root {
25/// What was happening in the caller
26context: &'static str,
27/// What happened
28source: Box<crate::Error>,
29 },
30/// Wrap a [crate::e2e_identity::Error] for recursion.
31E2e {
32/// What was happening in the caller
33context: &'static str,
34/// What happened
35source: Box<crate::e2e_identity::Error>,
36 },
37/// Wrap a [crate::mls::Error] for recursion.
38Mls {
39/// What was happening in the caller
40context: &'static str,
41/// What happened
42source: Box<crate::mls::Error>,
43 },
44/// Wrap a [crate::mls::client::Error] for recursion.
45MlsClient {
46/// What was happening in the caller
47context: &'static str,
48/// What happened
49source: Box<crate::mls::client::Error>,
50 },
51/// Wrap a [crate::mls::conversation::Error] for recursion.
52MlsConversation {
53/// What was happening in the caller
54context: &'static str,
55/// What happened
56source: Box<crate::mls::conversation::Error>,
57 },
58/// Wrap a [crate::mls::credential::Error] for recursion.
59MlsCredential {
60/// What was happening in the caller
61context: &'static str,
62/// What happened
63source: Box<crate::mls::credential::Error>,
64 },
65/// Wrap a [crate::test_utils::TestError] for recursion.
66#[cfg(test)]
67Test(Box<crate::test_utils::TestError>),
68}
6970impl RecursiveError {
71/// Convert a [crate::Error] into a [RecursiveError], with context
72pub fn root<E: Into<crate::Error>>(context: &'static str) -> impl FnOnce(E) -> Self {
73move |into_source| Self::Root {
74 context,
75 source: Box::new(into_source.into()),
76 }
77 }
7879/// Convert a [crate::e2e_identity::Error] into a [RecursiveError], with context
80pub fn e2e_identity<E: Into<crate::e2e_identity::Error>>(context: &'static str) -> impl FnOnce(E) -> Self {
81move |into_source| Self::E2e {
82 context,
83 source: Box::new(into_source.into()),
84 }
85 }
8687/// Convert a [crate::mls::Error] into a [RecursiveError], with context
88pub fn mls<E: Into<crate::mls::Error>>(context: &'static str) -> impl FnOnce(E) -> Self {
89move |into_source| Self::Mls {
90 context,
91 source: Box::new(into_source.into()),
92 }
93 }
9495/// Convert a [crate::mls::client::Error] into a [RecursiveError], with context
96pub fn mls_client<E: Into<crate::mls::client::Error>>(context: &'static str) -> impl FnOnce(E) -> Self {
97move |into_source| Self::MlsClient {
98 context,
99 source: Box::new(into_source.into()),
100 }
101 }
102103/// Convert a [crate::mls::conversation::Error] into a [RecursiveError], with context
104pub fn mls_conversation<E: Into<crate::mls::conversation::Error>>(context: &'static str) -> impl FnOnce(E) -> Self {
105move |into_source| Self::MlsConversation {
106 context,
107 source: Box::new(into_source.into()),
108 }
109 }
110111/// Convert a [crate::mls::credential::Error] into a [RecursiveError], with context
112pub fn mls_credential<E: Into<crate::mls::credential::Error>>(context: &'static str) -> impl FnOnce(E) -> Self {
113move |into_source| Self::MlsCredential {
114 context,
115 source: Box::new(into_source.into()),
116 }
117 }
118119#[cfg(test)]
120pub(crate) fn test<E: Into<crate::test_utils::TestError>>() -> impl FnOnce(E) -> Self {
121move |into_source| Self::Test(Box::new(into_source.into()))
122 }
123}
124125impl std::fmt::Display for RecursiveError {
126fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
127#[cfg(test)]
128use std::ops::Deref;
129130let context = match self {
131 RecursiveError::Root { context, .. } => context,
132 RecursiveError::E2e { context, .. } => context,
133 RecursiveError::Mls { context, .. } => context,
134 RecursiveError::MlsClient { context, .. } => context,
135 RecursiveError::MlsConversation { context, .. } => context,
136 RecursiveError::MlsCredential { context, .. } => context,
137#[cfg(test)]
138RecursiveError::Test(e) => return e.deref().fmt(f),
139 };
140write!(f, "{}", context)
141 }
142}
143144impl std::error::Error for RecursiveError {
145fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
146match self {
147 RecursiveError::Root { source, .. } => Some(source.as_ref()),
148 RecursiveError::E2e { source, .. } => Some(source.as_ref()),
149 RecursiveError::Mls { source, .. } => Some(source.as_ref()),
150 RecursiveError::MlsClient { source, .. } => Some(source.as_ref()),
151 RecursiveError::MlsConversation { source, .. } => Some(source.as_ref()),
152 RecursiveError::MlsCredential { source, .. } => Some(source.as_ref()),
153#[cfg(test)]
154RecursiveError::Test(source) => Some(source.as_ref()),
155 }
156 }
157}
158159/// Like [`Into`], but different, because we don't actually want to implement `Into` for our subordinate error types.
160///
161/// By forcing ourselves to map errors everywhere in order for question mark operators to work, we ensure that
162pub trait ToRecursiveError {
163/// Construct a recursive error given the current context
164fn construct_recursive(self, context: &'static str) -> RecursiveError;
165}
166167macro_rules! impl_to_recursive_error_for {
168 ($($for:path => $variant:ident),+ $(,)?) => {
169 $(
170impl ToRecursiveError for $for {
171fn construct_recursive(self, context: &'static str) -> RecursiveError {
172 RecursiveError::$variant {
173 context,
174 source: Box::new(self),
175 }
176 }
177 }
178 )+
179 };
180}
181182impl_to_recursive_error_for!(
183crate::Error => Root,
184crate::e2e_identity::Error => E2e,
185crate::mls::Error => Mls,
186crate::mls::client::Error => MlsClient,
187crate::mls::conversation::Error => MlsConversation,
188crate::mls::credential::Error => MlsCredential,
189);