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 crate::{persist::Persist, registry::StateRegistryError, sdk_managed::DatabaseError};
9
10/// Internal setting value as stored in the SDK-managed database.
11///
12/// This type wraps a JSON value for flexible storage. Users should not work with
13/// this type directly - use the [`Setting<T>`] handle via `StateClient::setting()` instead,
14/// which provides type-safe access.
15#[doc(hidden)]
16#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
17pub struct SettingItem(pub(crate) serde_json::Value);
18
19crate::register_repository_item!(String => SettingItem, "Setting");
20
21#[doc(hidden)]
22#[async_trait::async_trait]
23pub trait SettingTrait<T: Persist>: Send + Sync {
24    async fn get(&self) -> Result<Option<T>, SettingsError>;
25    async fn set(&self, value: T) -> Result<(), SettingsError>;
26    async fn remove(&self) -> Result<(), SettingsError>;
27}
28
29/// A handle to a single setting value in storage.
30///
31/// This type provides async methods to get, update, and delete the setting value.
32/// Obtained via `StateClient::setting()`.
33///
34/// # Example
35/// ```rust,ignore
36/// use bitwarden_state::register_setting_key;
37///
38/// register_setting_key!(const THEME: String = "theme");
39///
40/// let setting = client.platform().state().setting(THEME)?;
41///
42/// // Get the current value
43/// let value: Option<String> = setting.get().await?;
44///
45/// // Update the value
46/// setting.update("dark".to_string()).await?;
47///
48/// // Delete the value
49/// setting.delete().await?;
50/// ```
51#[derive(Clone)]
52pub struct Setting<T: Persist> {
53    backend: Arc<dyn SettingTrait<T>>,
54}
55
56impl<T: Persist> Setting<T> {
57    /// Create a new setting handle from a backend.
58    ///
59    /// The backend is already bound to a single key, so it decides where the value is stored.
60    pub fn new(backend: Arc<dyn SettingTrait<T>>) -> Self {
61        Self { backend }
62    }
63
64    /// Get the current value of this setting.
65    ///
66    /// Returns `None` if the setting doesn't exist in storage.
67    ///
68    /// # Errors
69    ///
70    /// Returns an error if deserialization fails, which may indicate:
71    /// - Schema evolution problems (type definition changed)
72    /// - Data corruption
73    /// - Type mismatch (wrong `Key<T>` type for stored data)
74    pub async fn get(&self) -> Result<Option<T>, SettingsError> {
75        self.backend.get().await
76    }
77
78    /// Update (or create) this setting with a new value.
79    pub async fn update(&self, value: T) -> Result<(), SettingsError> {
80        self.backend.set(value).await
81    }
82
83    /// Delete this setting from storage.
84    pub async fn delete(&self) -> Result<(), SettingsError> {
85        self.backend.remove().await
86    }
87}
88
89/// Errors that can occur when working with settings.
90#[derive(Debug, Error)]
91pub enum SettingsError {
92    /// Failed to serialize/deserialize setting value
93    #[error("Failed to serialize/deserialize setting: {0}")]
94    Json(#[from] serde_json::Error),
95    /// Database operation failed
96    #[error(transparent)]
97    Database(#[from] DatabaseError),
98    /// State registry operation failed
99    #[error(transparent)]
100    Registry(#[from] StateRegistryError),
101}