core_crypto/error/
keystore.rs

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