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}