privatus_analytics/
value.rs1use std::borrow::Cow;
2
3#[derive(Clone, Debug, PartialEq)]
9pub enum Value {
10 Null,
13 Bool(bool),
15 Int(i64),
17 UInt(u64),
19 Float(f64),
21 Str(String),
23 List(Vec<Value>),
25}
26
27impl From<bool> for Value {
28 fn from(value: bool) -> Self {
29 Value::Bool(value)
30 }
31}
32
33macro_rules! from_signed {
34 ($($ty:ty),*) => {$(
35 impl From<$ty> for Value {
36 fn from(value: $ty) -> Self {
37 Value::Int(value as i64)
38 }
39 }
40 )*};
41}
42from_signed!(i8, i16, i32, i64, isize);
43
44macro_rules! from_unsigned {
45 ($($ty:ty),*) => {$(
46 impl From<$ty> for Value {
47 fn from(value: $ty) -> Self {
48 let value = value as u64;
49 if value <= i64::MAX as u64 {
50 Value::Int(value as i64)
51 } else {
52 Value::UInt(value)
53 }
54 }
55 }
56 )*};
57}
58from_unsigned!(u8, u16, u32, u64, usize);
59
60impl From<f64> for Value {
61 fn from(value: f64) -> Self {
62 Value::Float(value)
63 }
64}
65
66impl From<f32> for Value {
67 fn from(value: f32) -> Self {
69 Value::Float(value.to_string().parse().unwrap_or(value as f64))
70 }
71}
72
73impl From<&str> for Value {
74 fn from(value: &str) -> Self {
75 Value::Str(value.to_owned())
76 }
77}
78
79impl From<String> for Value {
80 fn from(value: String) -> Self {
81 Value::Str(value)
82 }
83}
84
85impl From<&String> for Value {
86 fn from(value: &String) -> Self {
87 Value::Str(value.clone())
88 }
89}
90
91impl From<Cow<'_, str>> for Value {
92 fn from(value: Cow<'_, str>) -> Self {
93 Value::Str(value.into_owned())
94 }
95}
96
97impl From<char> for Value {
98 fn from(value: char) -> Self {
99 Value::Str(value.to_string())
100 }
101}
102
103impl From<&Value> for Value {
104 fn from(value: &Value) -> Self {
105 value.clone()
106 }
107}
108
109impl<T: Into<Value>> From<Option<T>> for Value {
110 fn from(value: Option<T>) -> Self {
111 value.map_or(Value::Null, Into::into)
112 }
113}
114
115impl<T: Into<Value>> From<Vec<T>> for Value {
116 fn from(value: Vec<T>) -> Self {
117 Value::List(value.into_iter().map(Into::into).collect())
118 }
119}
120
121impl<T: Into<Value>, const N: usize> From<[T; N]> for Value {
122 fn from(value: [T; N]) -> Self {
123 Value::List(value.into_iter().map(Into::into).collect())
124 }
125}
126
127impl<T: Into<Value> + Clone> From<&[T]> for Value {
128 fn from(value: &[T]) -> Self {
129 Value::List(value.iter().cloned().map(Into::into).collect())
130 }
131}
132
133#[derive(Clone, Debug, Default, PartialEq)]
147pub struct Props(Vec<(String, Value)>);
148
149impl Props {
150 pub fn new() -> Self {
152 Props(Vec::new())
153 }
154
155 pub fn with(mut self, key: impl Into<String>, value: impl Into<Value>) -> Self {
157 self.insert(key, value);
158 self
159 }
160
161 pub fn insert(&mut self, key: impl Into<String>, value: impl Into<Value>) {
163 let key = key.into();
164 let value = value.into();
165 match self.0.iter_mut().find(|(existing, _)| *existing == key) {
166 Some(slot) => slot.1 = value,
167 None => self.0.push((key, value)),
168 }
169 }
170
171 pub fn get(&self, key: &str) -> Option<&Value> {
173 self.0.iter().find(|(k, _)| k == key).map(|(_, v)| v)
174 }
175
176 pub fn len(&self) -> usize {
178 self.0.len()
179 }
180
181 pub fn is_empty(&self) -> bool {
183 self.0.is_empty()
184 }
185
186 pub fn iter(&self) -> impl Iterator<Item = (&str, &Value)> {
188 self.0.iter().map(|(k, v)| (k.as_str(), v))
189 }
190}
191
192impl<K: Into<String>, V: Into<Value>> FromIterator<(K, V)> for Props {
193 fn from_iter<I: IntoIterator<Item = (K, V)>>(iter: I) -> Self {
194 let mut props = Props::new();
195 for (key, value) in iter {
196 props.insert(key, value);
197 }
198 props
199 }
200}
201
202impl<K: Into<String>, V: Into<Value>> Extend<(K, V)> for Props {
203 fn extend<I: IntoIterator<Item = (K, V)>>(&mut self, iter: I) {
204 for (key, value) in iter {
205 self.insert(key, value);
206 }
207 }
208}
209
210impl IntoIterator for Props {
211 type Item = (String, Value);
212 type IntoIter = std::vec::IntoIter<(String, Value)>;
213
214 fn into_iter(self) -> Self::IntoIter {
215 self.0.into_iter()
216 }
217}
218
219impl<'a> IntoIterator for &'a Props {
220 type Item = (&'a String, &'a Value);
221 type IntoIter = std::iter::Map<
222 std::slice::Iter<'a, (String, Value)>,
223 fn(&'a (String, Value)) -> (&'a String, &'a Value),
224 >;
225
226 fn into_iter(self) -> Self::IntoIter {
227 self.0.iter().map(|(k, v)| (k, v))
228 }
229}
230
231#[macro_export]
242macro_rules! props {
243 () => { $crate::Props::new() };
244 ($($key:expr => $value:expr),+ $(,)?) => {{
245 let mut props = $crate::Props::new();
246 $( props.insert($key, $value); )+
247 props
248 }};
249}