bitwarden_uniffi/platform/
repository.rs

1use std::sync::Arc;
2
3pub struct UniffiRepositoryBridge<T>(pub T);
4
5impl<T: ?Sized> UniffiRepositoryBridge<Arc<T>> {
6    pub fn new(store: Arc<T>) -> Arc<Self> {
7        Arc::new(UniffiRepositoryBridge(store))
8    }
9}
10
11impl<T: std::fmt::Debug> std::fmt::Debug for UniffiRepositoryBridge<T> {
12    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
13        self.0.fmt(f)
14    }
15}
16
17#[derive(uniffi::Error, thiserror::Error, Debug)]
18#[uniffi(flat_error)]
19pub enum RepositoryError {
20    #[error("Internal error: {0}")]
21    Internal(String),
22}
23
24// Need to implement this From<> impl in order to handle unexpected callback errors.  See the
25// following page in the Uniffi user guide:
26// <https://mozilla.github.io/uniffi-rs/foreign_traits.html#error-handling>
27impl From<uniffi::UnexpectedUniFFICallbackError> for RepositoryError {
28    fn from(e: uniffi::UnexpectedUniFFICallbackError) -> Self {
29        Self::Internal(e.reason)
30    }
31}
32
33impl From<RepositoryError> for bitwarden_state::repository::RepositoryError {
34    fn from(e: RepositoryError) -> Self {
35        match e {
36            RepositoryError::Internal(msg) => Self::Internal(msg),
37        }
38    }
39}
40
41/// This macro creates a Uniffi repository trait and its implementation for the
42/// [bitwarden_state::repository::Repository] trait
43macro_rules! create_uniffi_repository {
44    ($name:ident, $ty:ty) => {
45        #[uniffi::export(with_foreign)]
46        #[async_trait::async_trait]
47        pub trait $name: Send + Sync {
48            async fn get(
49                &self,
50                id: String,
51            ) -> Result<Option<$ty>, $crate::platform::repository::RepositoryError>;
52            async fn list(&self)
53                -> Result<Vec<$ty>, $crate::platform::repository::RepositoryError>;
54            async fn set(
55                &self,
56                id: String,
57                value: $ty,
58            ) -> Result<(), $crate::platform::repository::RepositoryError>;
59            async fn remove(
60                &self,
61                id: String,
62            ) -> Result<(), $crate::platform::repository::RepositoryError>;
63
64            async fn has(
65                &self,
66                id: String,
67            ) -> Result<bool, $crate::platform::repository::RepositoryError> {
68                match self.get(id).await {
69                    Ok(x) => Ok(x.is_some()),
70                    Err(e) => Err(e),
71                }
72            }
73        }
74
75        #[async_trait::async_trait]
76        impl bitwarden_state::repository::Repository<$ty>
77            for $crate::platform::repository::UniffiRepositoryBridge<Arc<dyn $name>>
78        {
79            async fn get(
80                &self,
81                key: String,
82            ) -> Result<Option<$ty>, bitwarden_state::repository::RepositoryError> {
83                self.0.get(key).await.map_err(Into::into)
84            }
85            async fn list(&self) -> Result<Vec<$ty>, bitwarden_state::repository::RepositoryError> {
86                self.0.list().await.map_err(Into::into)
87            }
88            async fn set(
89                &self,
90                key: String,
91                value: $ty,
92            ) -> Result<(), bitwarden_state::repository::RepositoryError> {
93                self.0.set(key, value).await.map_err(Into::into)
94            }
95            async fn remove(
96                &self,
97                key: String,
98            ) -> Result<(), bitwarden_state::repository::RepositoryError> {
99                self.0.remove(key).await.map_err(Into::into)
100            }
101        }
102    };
103}
104pub(super) use create_uniffi_repository;