bitwarden_state/settings/setting.rs
1//! Setting types for type-safe access to individual settings.
2
3use std::sync::Arc;
4
5use serde::{Deserialize, Serialize};
6use thiserror::Error;
7
8use super::Key;
9use crate::{
10 registry::StateRegistryError,
11 repository::{Repository, RepositoryError},
12};
13
14/// Internal setting value stored in the settings repository.
15///
16/// This type wraps a JSON value for flexible storage. Users should not work with
17/// this type directly - use the [`Setting<T>`] handle via `StateClient::setting()` instead,
18/// which provides type-safe access.
19#[doc(hidden)]
20#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
21pub struct SettingItem(pub(crate) serde_json::Value);
22
23// Register SettingItem for repository usage
24crate::register_repository_item!(String => SettingItem, "Setting");
25
26/// A handle to a single setting value in storage.
27///
28/// This type provides async methods to get, update, and delete the setting value.
29/// Obtained via `StateClient::setting()`.
30///
31/// # Example
32/// ```rust,ignore
33/// use bitwarden_state::register_setting_key;
34///
35/// register_setting_key!(const THEME: String = "theme");
36///
37/// let setting = client.platform().state().setting(THEME)?;
38///
39/// // Get the current value
40/// let value: Option<String> = setting.get().await?;
41///
42/// // Update the value
43/// setting.update("dark".to_string()).await?;
44///
45/// // Delete the value
46/// setting.delete().await?;
47/// ```
48#[derive(Clone)]
49pub struct Setting<T> {
50 repository: Arc<dyn Repository<SettingItem>>,
51 key: Key<T>,
52}
53
54impl<T> Setting<T> {
55 /// Create a new setting handle from a repository and key.
56 pub fn new(repository: Arc<dyn Repository<SettingItem>>, key: Key<T>) -> Self {
57 Self { repository, key }
58 }
59
60 /// Get the current value of this setting.
61 ///
62 /// Returns `None` if the setting doesn't exist in storage.
63 ///
64 /// # Errors
65 ///
66 /// Returns an error if deserialization fails, which may indicate:
67 /// - Schema evolution problems (type definition changed)
68 /// - Data corruption
69 /// - Type mismatch (wrong `Key<T>` type for stored data)
70 pub async fn get(&self) -> Result<Option<T>, SettingsError>
71 where
72 T: for<'de> Deserialize<'de>,
73 {
74 match self.repository.get(self.key.name.to_string()).await? {
75 Some(item) => Ok(Some(serde_json::from_value::<T>(item.0)?)),
76 None => Ok(None),
77 }
78 }
79
80 /// Update (or create) this setting with a new value.
81 pub async fn update(&self, value: T) -> Result<(), SettingsError>
82 where
83 T: Serialize,
84 {
85 let json_value = serde_json::to_value(&value)?;
86 let item = SettingItem(json_value);
87
88 self.repository.set(self.key.name.to_string(), item).await?;
89
90 Ok(())
91 }
92
93 /// Delete this setting from storage.
94 pub async fn delete(&self) -> Result<(), SettingsError> {
95 self.repository.remove(self.key.name.to_string()).await?;
96
97 Ok(())
98 }
99}
100
101/// Errors that can occur when working with settings.
102#[derive(Debug, Error)]
103pub enum SettingsError {
104 /// Failed to serialize/deserialize setting value
105 #[error("Failed to serialize/deserialize setting: {0}")]
106 Json(#[from] serde_json::Error),
107 /// Repository operation failed
108 #[error(transparent)]
109 Repository(#[from] RepositoryError),
110 /// State registry operation failed
111 #[error(transparent)]
112 Registry(#[from] StateRegistryError),
113}