Skip to main content

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}