1#![cfg_attr(not(feature = "std"), no_std)]
42
43#[cfg(not(feature = "std"))]
45mod std {
46 pub use core::iter;
47}
48
49#[allow(unused_imports)]
51#[macro_use]
52extern crate stringly_typed_derive;
53#[doc(hidden)]
54pub use stringly_typed_derive::*;
55
56pub const DOUBLE_TYPE: &'static str = "double";
57pub const INTEGER_TYPE: &'static str = "integer";
58pub const STRING_TYPE: &'static str = "string";
59
60pub trait StringlyTyped {
62 fn get(&self, key: &str) -> Result<Value, UpdateError> {
63 self.get_value(key.split("."))
64 }
65
66 fn set(&mut self, key: &str, value: Value) -> Result<(), UpdateError> {
67 self.set_value(key.split("."), value)
68 }
69
70 fn set_value<K, S>(&mut self, keys: K, value: Value) -> Result<(), UpdateError>
71 where
72 K: IntoIterator<Item = S>,
73 S: AsRef<str>;
74
75 fn get_value<K, S>(&self, keys: K) -> Result<Value, UpdateError>
76 where
77 K: IntoIterator<Item = S>,
78 S: AsRef<str>;
79
80 fn data_type(&self) -> &'static str;
81}
82
83#[derive(Debug, Copy, Clone, PartialEq)]
84pub enum UpdateError {
85 TypeError {
86 found: &'static str,
87 expected: &'static str,
88 },
89 TooManyKeys {
90 elements_remaning: usize,
91 },
92 UnknownField {
93 valid_fields: &'static [&'static str],
94 },
95 CantSerialize { data_type: &'static str },
96}
97
98#[derive(Debug, Clone, PartialEq)]
100pub enum Value {
101 Integer(i64),
102 Double(f64),
103 #[cfg(feature = "std")]
104 String(String),
105 #[doc(hidden)]
106 __NonExhaustive,
107}
108
109impl Value {
110 pub fn data_type(&self) -> &'static str {
111 match *self {
112 Value::Integer(_) => INTEGER_TYPE,
113 Value::Double(_) => DOUBLE_TYPE,
114 #[cfg(feature = "std")]
115 Value::String(_) => STRING_TYPE,
116 Value::__NonExhaustive => unreachable!(),
117 }
118 }
119}
120
121impl From<i64> for Value {
122 fn from(other: i64) -> Value {
123 Value::Integer(other)
124 }
125}
126
127impl From<f64> for Value {
128 fn from(other: f64) -> Value {
129 Value::Double(other)
130 }
131}
132
133#[cfg(feature = "std")]
134impl From<String> for Value {
135 fn from(other: String) -> Value {
136 Value::String(other)
137 }
138}
139
140#[cfg(feature = "std")]
141impl<'a> From<&'a str> for Value {
142 fn from(other: &'a str) -> Value {
143 Value::String(other.to_string())
144 }
145}
146
147macro_rules! impl_primitive_type {
148 ($(#[$attr:meta])* $type:ty, $variant:ident, $data_type:expr) => {
149 $(#[$attr])*
150 impl StringlyTyped for $type {
151 fn set_value<K, S>(&mut self, keys: K, value: Value) -> Result<(), UpdateError>
152 where K: IntoIterator<Item = S>,
153 S: AsRef<str>
154 {
155 let mut keys = keys.into_iter();
156
157 if let Some(_) = keys.next() {
158 let elements_remaning = keys.count() + 1;
159 return Err(UpdateError::TooManyKeys { elements_remaning });
160 }
161
162 match value {
163 Value::$variant(v) => {
164 *self = v;
165 Ok(())
166 }
167 _ => {
168 let e = UpdateError::TypeError {
169 expected: self.data_type(),
170 found: value.data_type(),
171 };
172 Err(e)
173 }
174 }
175 }
176
177 fn get_value<K, S>(&self, keys: K) -> Result<Value, UpdateError>
178 where K: IntoIterator<Item = S>,
179 S: AsRef<str>,
180 {
181 let mut keys = keys.into_iter();
182
183 if let Some(_) = keys.next() {
184 let elements_remaning = keys.count() + 1;
185 return Err(UpdateError::TooManyKeys { elements_remaning });
186 }
187
188 Ok(self.clone().into())
189 }
190
191 fn data_type(&self) -> &'static str {
192 $data_type
193 }
194 }
195 };
196}
197
198impl_primitive_type!(i64, Integer, INTEGER_TYPE);
199impl_primitive_type!(f64, Double, DOUBLE_TYPE);
200impl_primitive_type!(#[cfg(feature = "std")] String, String, STRING_TYPE);
201
202#[cfg(test)]
203mod tests {
204 use super::*;
205 use std::iter;
206
207 #[test]
208 fn update_some_primitives() {
209 let empty = iter::empty::<&str>();
210
211 let mut integer: i64 = 42;
212 integer
213 .set_value(empty.clone(), Value::Integer(-7))
214 .unwrap();
215 assert_eq!(integer, -7);
216
217 let mut float: f64 = 3.14;
218 float.set_value(empty.clone(), Value::Double(42.0)).unwrap();
219 assert_eq!(float, 42.0);
220 }
221
222 #[cfg(feature = "std")]
223 #[test]
224 fn update_a_string() {
225 let empty = iter::empty::<&str>();
226
227 let mut string = String::from("before");
228 let new_value = String::from("after");
229 string
230 .set_value(empty.clone(), new_value.clone().into())
231 .unwrap();
232 assert_eq!(string, new_value);
233 }
234
235 #[test]
236 fn get_some_primitives() {
237 let empty = iter::empty::<&str>();
238
239 let integer: i64 = 42;
240 let got = integer.get_value(empty.clone()).unwrap();
241 assert_eq!(got, Value::from(integer));
242
243 let float: f64 = 3.14;
244 let got = float.get_value(empty.clone()).unwrap();
245 assert_eq!(got, Value::from(float));
246 }
247
248 #[cfg(feature = "std")]
249 #[test]
250 fn get_a_string() {
251 let empty = iter::empty::<&str>();
252
253 let string = String::from("before");
254 let got = string.get_value(empty.clone()).unwrap();
255 assert_eq!(got, Value::from(string));
256 }
257
258 #[test]
259 fn primitives_detect_type_errors() {
260 let empty = iter::empty::<&str>();
261
262 let mut integer: i64 = 42;
263 let got = integer
264 .set_value(empty.clone(), Value::Double(0.0))
265 .unwrap_err();
266 assert_eq!(
267 got,
268 UpdateError::TypeError {
269 found: DOUBLE_TYPE,
270 expected: INTEGER_TYPE,
271 }
272 );
273
274 let mut float: f64 = 3.14;
275 let got = float
276 .set_value(empty.clone(), Value::Integer(0))
277 .unwrap_err();
278 assert_eq!(
279 got,
280 UpdateError::TypeError {
281 found: INTEGER_TYPE,
282 expected: DOUBLE_TYPE,
283 }
284 );
285 }
286
287 #[test]
288 fn primitives_detect_over_indexing() {
289 let key = "foo.bar".split(".");
290 let mut n: i64 = 42;
291 let should_be = UpdateError::TooManyKeys {
292 elements_remaning: 2,
293 };
294
295 let got = n.set_value(key, Value::Integer(7)).unwrap_err();
296 assert_eq!(got, should_be);
297 }
298}