Skip to main content

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)]
18pub enum RepositoryError {
19    #[error("Internal error: {0}")]
20    Internal(String),
21}
22
23// Need to implement this From<> impl in order to handle unexpected callback errors.  See the
24// following page in the Uniffi user guide:
25// <https://mozilla.github.io/uniffi-rs/foreign_traits.html#error-handling>
26impl From<uniffi::UnexpectedUniFFICallbackError> for RepositoryError {
27    fn from(e: uniffi::UnexpectedUniFFICallbackError) -> Self {
28        Self::Internal(e.reason)
29    }
30}
31
32impl From<RepositoryError> for bitwarden_state::repository::RepositoryError {
33    fn from(e: RepositoryError) -> Self {
34        match e {
35            RepositoryError::Internal(msg) => Self::Internal(msg),
36        }
37    }
38}
39
40/// This macro creates a Uniffi repository trait and its implementation for the
41/// [bitwarden_state::repository::Repository] trait
42macro_rules! create_uniffi_repositories {
43    ( $container_name:ident ; $( $qualified_type_name:ty, $type_name:ident, $field_name:ident, $repo_name:ident );+ $(;)? ) => {
44
45        #[derive(::uniffi::Record)]
46        pub struct $container_name {
47            $(
48                pub $field_name: Option<::std::sync::Arc<dyn $repo_name>>,
49            )+
50        }
51
52        impl $container_name {
53            pub fn register_all(self, client: &bitwarden_core::platform::StateClient) {
54                $(
55                    if let Some(repo) = self.$field_name {
56                        let bridge = $crate::platform::repository::UniffiRepositoryBridge::new(repo);
57                        client.register_client_managed(bridge);
58                    }
59                )+
60            }
61        }
62
63        $(
64            #[::uniffi::export(with_foreign)]
65            #[::async_trait::async_trait]
66            pub trait $repo_name: Send + Sync {
67                async fn get(
68                    &self,
69                    id: String,
70                ) -> Result<Option<$qualified_type_name>, $crate::platform::repository::RepositoryError>;
71                async fn list(&self)
72                    -> Result<Vec<$qualified_type_name>, $crate::platform::repository::RepositoryError>;
73                async fn set(
74                    &self,
75                    id: String,
76                    value: $qualified_type_name,
77                ) -> Result<(), $crate::platform::repository::RepositoryError>;
78                async fn set_bulk(
79                    &self,
80                    values: std::collections::HashMap<String, $qualified_type_name>,
81                ) -> Result<(), $crate::platform::repository::RepositoryError>;
82                async fn remove(
83                    &self,
84                    id: String,
85                ) -> Result<(), $crate::platform::repository::RepositoryError>;
86                async fn remove_bulk(
87                    &self,
88                    keys: Vec<String>,
89                ) -> Result<(), $crate::platform::repository::RepositoryError>;
90                async fn remove_all(&self)
91                    -> Result<(), $crate::platform::repository::RepositoryError>;
92
93                async fn has(
94                    &self,
95                    id: String,
96                ) -> Result<bool, $crate::platform::repository::RepositoryError>;
97            }
98
99            #[async_trait::async_trait]
100            impl bitwarden_state::repository::Repository<$qualified_type_name>
101                for $crate::platform::repository::UniffiRepositoryBridge<Arc<dyn $repo_name>>
102            {
103                async fn get(
104                    &self,
105                    key: <$qualified_type_name as bitwarden_state::repository::RepositoryItem>::Key,
106                ) -> Result<Option<$qualified_type_name>, bitwarden_state::repository::RepositoryError> {
107                    let key = key.to_string();
108                    self.0.get(key).await.map_err(Into::into)
109                }
110                async fn list(&self) -> Result<Vec<$qualified_type_name>, bitwarden_state::repository::RepositoryError> {
111                    self.0.list().await.map_err(Into::into)
112                }
113                async fn set(
114                    &self,
115                    key: <$qualified_type_name as bitwarden_state::repository::RepositoryItem>::Key,
116                    value: $qualified_type_name,
117                ) -> Result<(), bitwarden_state::repository::RepositoryError> {
118                    let key = key.to_string();
119                    self.0.set(key, value).await.map_err(Into::into)
120                }
121                async fn set_bulk(
122                    &self,
123                    values: Vec<(<$qualified_type_name as bitwarden_state::repository::RepositoryItem>::Key, $qualified_type_name)>,
124                ) -> Result<(), bitwarden_state::repository::RepositoryError> {
125                    let map = values.into_iter().map(|(k, v)| (k.to_string(), v)).collect();
126                    self.0.set_bulk(map).await.map_err(Into::into)
127                }
128                async fn remove(
129                    &self,
130                    key: <$qualified_type_name as bitwarden_state::repository::RepositoryItem>::Key,
131                ) -> Result<(), bitwarden_state::repository::RepositoryError> {
132                    let key = key.to_string();
133                    self.0.remove(key).await.map_err(Into::into)
134                }
135                async fn remove_bulk(
136                    &self,
137                    keys: Vec<<$qualified_type_name as bitwarden_state::repository::RepositoryItem>::Key>,
138                ) -> Result<(), bitwarden_state::repository::RepositoryError> {
139                    let keys = keys.into_iter().map(|k| k.to_string()).collect();
140                    self.0.remove_bulk(keys).await.map_err(Into::into)
141                }
142                async fn remove_all(&self) -> Result<(), bitwarden_state::repository::RepositoryError> {
143                    self.0.remove_all().await.map_err(Into::into)
144                }
145            }
146        )+
147    };
148}
149
150pub(super) use create_uniffi_repositories;