dbstruct/wrapper/
option.rs

1use core::fmt;
2use std::borrow::Borrow;
3use std::marker::PhantomData;
4
5use serde::de::DeserializeOwned;
6use serde::Serialize;
7
8use crate::traits::{data_store, DataStore};
9use crate::Error;
10
11/// Here missing values are represented by [`Option::None`].
12pub struct OptionValue<T, DS>
13where
14    DS: DataStore,
15{
16    phantom: PhantomData<T>,
17    ds: DS,
18    key: u8,
19}
20
21impl<T, E, DS> OptionValue<T, DS>
22where
23    E: fmt::Debug,
24    T: Serialize + DeserializeOwned,
25    DS: DataStore<DbError = E>,
26{
27    #[doc(hidden)]
28    pub fn new(ds: DS, key: u8) -> Self {
29        Self {
30            phantom: PhantomData,
31            ds,
32            key,
33        }
34    }
35
36    /// Sets the value of this database item.
37    ///
38    /// The argument may be any borrowed form of value type, but the
39    /// serialized form must match that of the value type.
40    ///
41    /// # Errors
42    /// This can fail if the underlying database ran into a problem
43    /// or if serialization failed.
44    ///
45    /// # Examples
46    /// ```
47    /// #[dbstruct::dbstruct(db=btreemap)]
48    /// struct Test {
49    ///	    name: Option<String>,
50    ///	}
51    ///
52    ///	# fn main() -> Result<(), Box<dyn std::error::Error>> {
53    /// let db = Test::new()?;
54    /// db.name().set("Artemis")?;
55    /// assert_eq!(db.name().get()?, Some("Artemis".to_owned()));
56    /// # Ok(())
57    /// # }
58    /// ```
59    pub fn set<Q>(&mut self, value: &Q) -> Result<(), Error<E>>
60    where
61        T: Borrow<Q>,
62        Q: Serialize + ?Sized,
63    {
64        self.ds.insert::<_, Q, T>(&self.key, value)?;
65        Ok(())
66    }
67
68    /// Get the current value of this item.
69    ///
70    /// # Errors
71    /// This can fail if the underlying database ran into a problem
72    /// or if serialization failed.
73    ///
74    /// # Examples
75    /// ```
76    /// #[dbstruct::dbstruct(db=btreemap)]
77    /// struct Test {
78    ///	    name: Option<String>,
79    ///	}
80    ///
81    ///	# fn main() -> Result<(), Box<dyn std::error::Error>> {
82    /// let db = Test::new()?;
83    /// assert_eq!(db.name().get()?, None);
84    /// db.name().set("Artemis")?;
85    /// assert_eq!(db.name().get()?, Some("Artemis".to_owned()));
86    /// # Ok(())
87    /// # }
88    /// ```
89    pub fn get(&self) -> Result<Option<T>, Error<E>> {
90        self.ds.get(&self.key)
91    }
92}
93
94impl<T, E, DS> OptionValue<T, DS>
95where
96    E: fmt::Debug,
97    T: Serialize + DeserializeOwned,
98    DS: data_store::Atomic<DbError = E>,
99{
100    /// Updates the value in the database by applying the function `op` on it.
101    ///
102    /// # Errors
103    /// This can fail if the underlying database ran into a problem
104    /// or if serialization failed.
105    ///
106    /// # Examples
107    /// ```
108    /// #[dbstruct::dbstruct(db=btreemap)]
109    /// struct Test {
110    ///	    name: Option<String>,
111    ///	}
112    ///
113    ///	fn first_name(s: String) -> String {
114    ///     s.split_once(" ")
115    ///         .map(|(first, last)| first.to_owned())
116    ///         .unwrap_or(s)
117    ///	}
118    ///
119    ///	# fn main() -> Result<(), Box<dyn std::error::Error>> {
120    /// let db = Test::new()?;
121    /// db.name().set("Elijah Baley")?;
122    /// db.name().update(first_name);
123    /// assert_eq!(db.name().get()?, Some("Elijah".to_owned()));
124    /// # Ok(())
125    /// # }
126    /// ```
127    pub fn update(&self, op: impl FnMut(T) -> T + Clone) -> Result<(), Error<E>> {
128        self.ds.atomic_update(&self.key, op)?;
129        Ok(())
130    }
131
132    /// Set the value in the database to new if it is currently old.
133    ///
134    /// The arguments may be any borrowed form of value type, but the
135    /// serialized form must match that of the value type.
136    ///
137    /// # Errors
138    /// This can fail if the underlying database ran into a problem
139    /// or if serialization failed.
140    ///
141    /// # Examples
142    /// ```
143    /// #[dbstruct::dbstruct(db=btreemap)]
144    /// struct Test {
145    ///	    name: Option<String>,
146    ///	}
147    ///
148    ///	# fn main() -> Result<(), Box<dyn std::error::Error>> {
149    /// let db = Test::new()?;
150    /// db.name().set("Artemis")?;
151    /// db.name().conditional_update("Artemis", "Helios");
152    /// assert_eq!(db.name().get()?, Some("Helios".to_owned()));
153    /// db.name().conditional_update("Artemis", "Zeus");
154    /// assert_eq!(db.name().get()?, Some("Helios".to_owned()));
155    /// # Ok(())
156    /// # }
157    /// ```
158    pub fn conditional_update<Q>(&self, old: &Q, new: &Q) -> Result<(), Error<E>>
159    where
160        T: Borrow<Q>,
161        Q: Serialize + ?Sized,
162    {
163        Ok(self.ds.conditional_update(&self.key, &new, &old)?)
164    }
165}
166
167impl<T, E, DS> fmt::Debug for OptionValue<T, DS>
168where
169    E: fmt::Debug,
170    T: Serialize + DeserializeOwned + fmt::Debug,
171    DS: DataStore<DbError = E>,
172{
173    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
174        f.write_fmt(format_args!("{:?}", self.get()))
175    }
176}