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}