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}