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!(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/// ```
48pub struct Setting<T> {
49    repository: Arc<dyn Repository<SettingItem>>,
50    key: Key<T>,
51}
52
53impl<T> Setting<T> {
54    /// Create a new setting handle from a repository and key.
55    pub fn new(repository: Arc<dyn Repository<SettingItem>>, key: Key<T>) -> Self {
56        Self { repository, key }
57    }
58
59    /// Get the current value of this setting.
60    ///
61    /// Returns `None` if the setting doesn't exist in storage.
62    ///
63    /// # Errors
64    ///
65    /// Returns an error if deserialization fails, which may indicate:
66    /// - Schema evolution problems (type definition changed)
67    /// - Data corruption
68    /// - Type mismatch (wrong `Key<T>` type for stored data)
69    pub async fn get(&self) -> Result<Option<T>, SettingsError>
70    where
71        T: for<'de> Deserialize<'de>,
72    {
73        match self.repository.get(self.key.name.to_string()).await? {
74            Some(item) => Ok(Some(serde_json::from_value::<T>(item.0)?)),
75            None => Ok(None),
76        }
77    }
78
79    /// Update (or create) this setting with a new value.
80    pub async fn update(&self, value: T) -> Result<(), SettingsError>
81    where
82        T: Serialize,
83    {
84        let json_value = serde_json::to_value(&value)?;
85        let item = SettingItem(json_value);
86
87        self.repository.set(self.key.name.to_string(), item).await?;
88
89        Ok(())
90    }
91
92    /// Delete this setting from storage.
93    pub async fn delete(&self) -> Result<(), SettingsError> {
94        self.repository.remove(self.key.name.to_string()).await?;
95
96        Ok(())
97    }
98}
99
100/// Errors that can occur when working with settings.
101#[derive(Debug, Error)]
102pub enum SettingsError {
103    /// Failed to serialize/deserialize setting value
104    #[error("Failed to serialize/deserialize setting: {0}")]
105    Json(#[from] serde_json::Error),
106    /// Repository operation failed
107    #[error(transparent)]
108    Repository(#[from] RepositoryError),
109    /// State registry operation failed
110    #[error(transparent)]
111    Registry(#[from] StateRegistryError),
112}