core_crypto/error/
keystore.rs

1// Wire
2// Copyright (C) 2022 Wire Swiss GmbH
3
4// 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.
8
9// 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.
13
14// 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/.
16
17/// A key store operation failed
18//
19// This uses a `Box<dyn>` pattern because we do not directly import `keystore` from here right now,
20// and it feels a bit silly to add the dependency only for this.
21#[derive(Debug, thiserror::Error)]
22#[error("{context}")]
23pub struct KeystoreError {
24    /// What was happening in the caller
25    pub context: &'static str,
26    /// What happened with the keystore
27    #[source]
28    pub source: Box<dyn std::error::Error + Send + Sync>,
29}
30
31impl KeystoreError {
32    #[cfg(not(target_family = "wasm"))]
33    pub(crate) fn wrap<E>(context: &'static str) -> impl FnOnce(E) -> Self
34    where
35        E: 'static + std::error::Error + Send + Sync,
36    {
37        move |source| Self {
38            source: Box::new(source),
39            context,
40        }
41    }
42
43    /// Some of the error variants for WASM are not thread-safe at all
44    /// (looking at you, [idb::Error]), so we have to construct an approximation
45    /// of them instead.
46    #[cfg(target_family = "wasm")]
47    pub(crate) fn wrap<E>(context: &'static str) -> impl FnOnce(E) -> Self
48    where
49        E: std::error::Error,
50    {
51        move |source| {
52            let ts = threadsafe_error::Threadsafe::from(&source);
53            Self {
54                source: Box::new(ts),
55                context,
56            }
57        }
58    }
59}
60
61#[cfg(target_family = "wasm")]
62mod threadsafe_error {
63    #[derive(Debug, thiserror::Error)]
64    #[error("{message}")]
65    pub(crate) struct Threadsafe {
66        message: String,
67        #[source]
68        inner: Option<Box<Threadsafe>>,
69    }
70
71    impl Threadsafe {
72        fn new(message: impl ToString) -> Self {
73            Self {
74                message: message.to_string(),
75                inner: None,
76            }
77        }
78
79        fn set_inner(&mut self, inner: Self) {
80            self.inner = Some(Box::new(inner));
81        }
82    }
83
84    impl<E: std::error::Error + ?Sized> From<&E> for Threadsafe {
85        fn from(err: &E) -> Self {
86            let mut ts = Self::new(err);
87            if let Some(source) = err.source() {
88                ts.set_inner(Self::from(source))
89            }
90            ts
91        }
92    }
93}