Skip to main content

mzdata_param/
value_ref.rs

1use std::borrow::Cow;
2use std::fmt::Display;
3use std::hash::Hash;
4use std::str::{self, FromStr};
5use std::mem;
6
7
8use crate::{ParamValue, ParamValueParseError, Value};
9
10/// A borrowed parameter value that may be a string, a number, or empty. It is intended to
11/// be paired with the [`ParamValue`] trait.
12///
13/// The owned equivalent of this type is [`Value`].
14#[derive(Debug, Clone, PartialEq, PartialOrd, Default)]
15#[cfg_attr(feature = "serde", derive(serde::Serialize))]
16pub enum ValueRef<'a> {
17    /// A text value of arbitrary length
18    String(Cow<'a, str>),
19    /// A floating point number
20    Float(f64),
21    /// A integral number
22    Int(i64),
23    /// Arbitrary binary data
24    Buffer(Cow<'a, [u8]>),
25    /// No value specified
26    #[default]
27    Empty,
28    /// A true/false value
29    Boolean(bool),
30    /// A collection of heterogenous [`Value`]
31    List(Cow<'a, [Value]>),
32}
33
34impl Eq for ValueRef<'_> {}
35
36impl From<String> for ValueRef<'_> {
37    fn from(value: String) -> Self {
38        value.parse().unwrap()
39    }
40}
41
42impl<'a> From<&'a str> for ValueRef<'a> {
43    fn from(value: &'a str) -> Self {
44        ValueRef::new(value)
45    }
46}
47
48impl<'a> From<Cow<'a, str>> for ValueRef<'a> {
49    fn from(value: Cow<'a, str>) -> Self {
50        match value {
51            Cow::Borrowed(s) => Self::new(s),
52            Cow::Owned(s) => s.parse().unwrap(),
53        }
54    }
55}
56
57impl PartialEq<String> for ValueRef<'_> {
58    fn eq(&self, other: &String) -> bool {
59        self.as_str() == other.as_str()
60    }
61}
62
63impl PartialEq<str> for ValueRef<'_> {
64    fn eq(&self, other: &str) -> bool {
65        self.as_str() == other
66    }
67}
68
69impl PartialEq<&str> for ValueRef<'_> {
70    fn eq(&self, other: &&str) -> bool {
71        self.as_str() == *other
72    }
73}
74
75impl PartialEq<i64> for ValueRef<'_> {
76    fn eq(&self, other: &i64) -> bool {
77        if let Self::Int(val) = self {
78            val == other
79        } else {
80            false
81        }
82    }
83}
84
85impl PartialEq<f64> for ValueRef<'_> {
86    fn eq(&self, other: &f64) -> bool {
87        if let Self::Float(val) = self {
88            val == other
89        } else {
90            false
91        }
92    }
93}
94
95impl PartialEq<bool> for ValueRef<'_> {
96    fn eq(&self, other: &bool) -> bool {
97        if let Self::Boolean(val) = self {
98            val == other
99        } else {
100            false
101        }
102    }
103}
104
105impl FromStr for ValueRef<'_> {
106    type Err = ParamValueParseError;
107
108    fn from_str(s: &str) -> Result<Self, Self::Err> {
109        if s.is_empty() {
110            return Ok(Self::Empty);
111        }
112        if let Ok(value) = s.parse() {
113            Ok(Self::Int(value))
114        } else if let Ok(value) = s.parse() {
115            Ok(Self::Float(value))
116        } else if let Ok(value) = s.parse() {
117            Ok(Self::Boolean(value))
118        } else {
119            Ok(Self::String(Cow::Owned(s.to_string())))
120        }
121    }
122}
123
124impl Display for ValueRef<'_> {
125    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
126        match self {
127            Self::String(v) => f.write_str(v),
128            Self::Float(v) => v.fmt(f),
129            Self::Int(v) => v.fmt(f),
130            Self::Buffer(v) => f.write_str(&String::from_utf8_lossy(v)),
131            Self::Empty => f.write_str(""),
132            Self::Boolean(v) => v.fmt(f),
133            Self::List(v) => {
134                f.write_str("[ ")?;
135                if let Some(vi) = v.first() {
136                    vi.fmt(f)?;
137                }
138                for vi in v.iter().skip(1) {
139                    f.write_str(", ")?;
140                    vi.fmt(f)?;
141                }
142                f.write_str(" ]")
143            }
144        }
145    }
146}
147
148impl<'a> ValueRef<'a> {
149    /// Convert a string value into a precise value type by trying
150    /// successive types to parse, defaulting to storing the string
151    /// as-is.
152    pub fn new(s: &'a str) -> Self {
153        if s.is_empty() {
154            return Self::Empty;
155        }
156        if let Ok(value) = s.parse::<i64>() {
157            Self::Int(value)
158        } else if let Ok(value) = s.parse::<f64>() {
159            Self::Float(value)
160        } else if let Ok(value) = s.parse() {
161            Self::Boolean(value)
162        } else {
163            Self::String(Cow::Borrowed(s))
164        }
165    }
166
167    /// Create a string [`ValueRef`]
168    pub const fn wrap(s: &'a str) -> Self {
169        Self::String(Cow::Borrowed(s))
170    }
171
172    fn is_empty(&self) -> bool {
173        matches!(self, Self::Empty)
174    }
175
176    fn is_i64(&self) -> bool {
177        matches!(self, Self::Int(_))
178    }
179
180    fn is_f64(&self) -> bool {
181        matches!(self, Self::Float(_))
182    }
183
184    fn is_buffer(&self) -> bool {
185        matches!(self, Self::Buffer(_))
186    }
187
188    fn is_str(&self) -> bool {
189        matches!(self, Self::String(_))
190    }
191
192    fn is_list(&self) -> bool {
193        matches!(self, Self::List(_))
194    }
195
196    fn to_bool(&self) -> Result<bool, ParamValueParseError> {
197        if let Self::Boolean(val) = self {
198            Ok(*val)
199        } else if self.is_numeric() {
200            Ok(self.to_i64()? != 0)
201        } else if let Self::Empty = self {
202            Ok(false)
203        } else if let Ok(v) = self.parse() {
204            Ok(v)
205        } else {
206            Err(ParamValueParseError::FailedToExtractInt(Some(
207                self.to_string(),
208            )))
209        }
210    }
211
212    /// Store the value as a boolean
213    pub fn coerce_bool(&mut self) -> Result<(), ParamValueParseError> {
214        let value = self.to_bool()?;
215        *self = Self::Boolean(value);
216        Ok(())
217    }
218
219    /// Store the value as a floating point number
220    pub fn coerce_f64(&mut self) -> Result<(), ParamValueParseError> {
221        let value = self.to_f64()?;
222        *self = Self::Float(value);
223        Ok(())
224    }
225
226    /// Store the value as an integer
227    pub fn coerce_i64(&mut self) -> Result<(), ParamValueParseError> {
228        let value = self.to_i64()?;
229        *self = Self::Int(value);
230        Ok(())
231    }
232
233    /// Store the value as a string
234    pub fn coerce_str(&mut self) -> Result<(), ParamValueParseError> {
235        if self.is_str() {
236        } else {
237            let value = self.to_string();
238            *self = Self::String(Cow::Owned(value));
239        }
240        Ok(())
241    }
242
243    /// Discard the value, leaving this value [`ValueRef::Empty`]
244    pub fn coerce_empty(&mut self) {
245        *self = Self::Empty;
246    }
247
248    /// Store the value as a byte buffer
249    pub fn coerce_buffer(&mut self) -> Result<(), ParamValueParseError> {
250        if self.is_buffer() {
251            Ok(())
252        } else {
253            let buffer = Cow::Owned(self.to_buffer()?.to_vec());
254            *self = Self::Buffer(buffer);
255            Ok(())
256        }
257    }
258
259    /// Store the value as a list
260    pub fn coerce_list(&mut self) -> Result<(), ParamValueParseError> {
261        if !self.is_list() {
262            let dup = match self {
263                Self::Boolean(v) => Value::Boolean(*v),
264                Self::Empty => Value::Empty,
265                Self::Float(v) => Value::Float(*v),
266                Self::Int(v) => Value::Int(*v),
267                Self::Buffer(v) => Value::Buffer(v.to_vec().into()),
268                Self::String(v) => Value::String(v.to_string()),
269                Self::List(_) => unimplemented!(),
270            };
271            *self = Self::List(Cow::Owned([dup].into()));
272        }
273        Ok(())
274    }
275
276    fn parse<T: FromStr>(&self) -> Result<T, T::Err> {
277        match self {
278            Self::String(s) => s.parse(),
279            Self::Float(v) => v.to_string().parse(),
280            Self::Int(i) => i.to_string().parse(),
281            Self::Buffer(b) => String::from_utf8_lossy(b).parse(),
282            Self::Empty => "".parse(),
283            Self::Boolean(v) => v.to_string().parse(),
284            Self::List(_) => self.to_string().parse(),
285        }
286    }
287
288    fn to_f64(&self) -> Result<f64, ParamValueParseError> {
289        if let Self::Float(val) = self {
290            return Ok(*val);
291        } else if let Self::Int(val) = self {
292            return Ok(*val as f64);
293        } else if let Self::String(val) = self {
294            if let Ok(v) = val.parse() {
295                return Ok(v);
296            }
297        }
298        Err(ParamValueParseError::FailedToExtractFloat(Some(
299            self.to_string(),
300        )))
301    }
302
303    fn to_i64(&self) -> Result<i64, ParamValueParseError> {
304        if let Self::Int(val) = self {
305            return Ok(*val);
306        } else if let Self::Float(val) = self {
307            return Ok(*val as i64);
308        } else if let Self::String(val) = self {
309            if let Ok(v) = val.parse() {
310                return Ok(v);
311            }
312        }
313        Err(ParamValueParseError::FailedToExtractInt(Some(
314            self.to_string(),
315        )))
316    }
317
318    fn to_str(&self) -> Cow<'_, str> {
319        if let Self::String(val) = self {
320            Cow::Borrowed(val)
321        } else {
322            Cow::Owned(self.to_string())
323        }
324    }
325
326    fn to_buffer(&self) -> Result<Cow<'_, [u8]>, ParamValueParseError> {
327        if let Self::Buffer(val) = self {
328            match val {
329                Cow::Borrowed(v) => Ok(Cow::Borrowed(*v)),
330                Cow::Owned(v) => Ok(Cow::Borrowed(v)),
331            }
332        } else if let Self::String(val) = self {
333            Ok(Cow::Borrowed(val.as_bytes()))
334        } else {
335            Err(ParamValueParseError::FailedToExtractBuffer)
336        }
337    }
338}
339
340impl ParamValue for ValueRef<'_> {
341    fn is_empty(&self) -> bool {
342        self.is_empty()
343    }
344
345    fn is_i64(&self) -> bool {
346        self.is_i64()
347    }
348
349    fn is_f64(&self) -> bool {
350        self.is_f64()
351    }
352
353    fn is_buffer(&self) -> bool {
354        self.is_buffer()
355    }
356
357    fn is_str(&self) -> bool {
358        self.is_str()
359    }
360
361    fn is_boolean(&self) -> bool {
362        matches!(self, Self::Boolean(_))
363    }
364
365    fn to_bool(&self) -> Result<bool, ParamValueParseError> {
366        self.to_bool()
367    }
368
369    fn to_f64(&self) -> Result<f64, ParamValueParseError> {
370        self.to_f64()
371    }
372
373    fn to_i64(&self) -> Result<i64, ParamValueParseError> {
374        self.to_i64()
375    }
376
377    fn to_str(&self) -> Cow<'_, str> {
378        self.to_str()
379    }
380
381    fn to_buffer(&self) -> Result<Cow<'_, [u8]>, ParamValueParseError> {
382        self.to_buffer()
383    }
384
385    fn parse<T: FromStr>(&self) -> Result<T, T::Err> {
386        self.parse()
387    }
388
389    fn as_bytes(&self) -> Cow<'_, [u8]> {
390        match self {
391            Self::String(v) => Cow::Borrowed(v.as_bytes()),
392            Self::Buffer(v) => Cow::Borrowed(v.as_ref()),
393            Self::Float(v) => Cow::Owned(v.to_string().into_bytes()),
394            Self::Int(v) => Cow::Owned(v.to_string().into_bytes()),
395            Self::Empty => Cow::Borrowed(b""),
396            Self::Boolean(v) => Cow::Owned(v.to_string().into_bytes()),
397            Self::List(_) => Cow::Owned(self.to_string().into_bytes()),
398        }
399    }
400
401    fn as_ref(&self) -> ValueRef<'_> {
402        self.clone()
403    }
404
405    fn data_len(&self) -> usize {
406        match self {
407            Self::String(v) => v.len(),
408            Self::Buffer(v) => v.len(),
409            Self::Float(_) => 8,
410            Self::Int(_) => 8,
411            Self::Empty => 0,
412            Self::Boolean(_) => mem::size_of::<bool>(),
413            Self::List(v) => v.iter().map(|vi| vi.data_len()).sum(),
414        }
415    }
416
417    fn is_list(&self) -> bool {
418        self.is_list()
419    }
420
421    fn as_slice(&self) -> Cow<'_, [Value]> {
422        match self {
423            Self::List(v) => Cow::Borrowed(v),
424            _ => {
425                let dup = match self {
426                    Self::Boolean(v) => Value::Boolean(*v),
427                    Self::Empty => Value::Empty,
428                    Self::Float(v) => Value::Float(*v),
429                    Self::Int(v) => Value::Int(*v),
430                    Self::Buffer(v) => Value::Buffer(v.to_vec().into()),
431                    Self::String(v) => Value::String(v.to_string()),
432                    Self::List(_) => unimplemented!(),
433                };
434                Cow::Owned([dup].into())
435            }
436        }
437    }
438}
439
440impl<'a> From<&'a Value> for ValueRef<'a> {
441    fn from(value: &'a Value) -> Self {
442        match value {
443            Value::String(s) => Self::String(Cow::Borrowed(s)),
444            Value::Float(v) => Self::Float(*v),
445            Value::Int(v) => Self::Int(*v),
446            Value::Buffer(v) => Self::Buffer(Cow::Borrowed(v)),
447            Value::Empty => Self::Empty,
448            Value::Boolean(v) => Self::Boolean(*v),
449            Value::List(v) => Self::List(Cow::Borrowed(v)),
450        }
451    }
452}
453
454impl PartialEq<Value> for ValueRef<'_> {
455    fn eq(&self, other: &Value) -> bool {
456        *self == other.as_ref()
457    }
458}
459
460impl<'a> PartialEq<ValueRef<'a>> for Value {
461    fn eq(&self, other: &ValueRef<'a>) -> bool {
462        self.as_ref() == *other
463    }
464}
465
466impl<'a> From<ValueRef<'a>> for Value {
467    fn from(value: ValueRef<'a>) -> Self {
468        match value {
469            ValueRef::String(s) => match s {
470                Cow::Borrowed(s) => Self::String(s.to_string()),
471                Cow::Owned(s) => Self::String(s),
472            },
473            ValueRef::Float(v) => Self::Float(v),
474            ValueRef::Int(v) => Self::Int(v),
475            ValueRef::Buffer(v) => Self::Buffer(v.to_vec().into_boxed_slice()),
476            ValueRef::Empty => Self::Empty,
477            ValueRef::Boolean(v) => Self::Boolean(v),
478            ValueRef::List(v) => {
479                let mut ve = Vec::with_capacity(v.len());
480                for vi in v.iter() {
481                    ve.push(vi.clone())
482                }
483                Self::List(ve.into_boxed_slice())
484            }
485        }
486    }
487}
488
489impl Hash for ValueRef<'_> {
490    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
491        core::mem::discriminant(self).hash(state);
492        match self {
493            Self::String(s) => s.hash(state),
494            Self::Float(v) => v.to_bits().hash(state),
495            Self::Int(v) => (*v).hash(state),
496            Self::Buffer(v) => v.hash(state),
497            Self::Empty => 0u8.hash(state),
498            Self::Boolean(v) => (*v).hash(state),
499            Self::List(v) => v.iter().for_each(|vi| vi.hash(state)),
500        }
501    }
502}
503
504macro_rules! param_value_ref_int {
505    ($val:ty) => {
506        impl<'a> From<$val> for ValueRef<'a> {
507            fn from(value: $val) -> Self {
508                Self::Int(value as i64)
509            }
510        }
511
512        impl<'a> From<&$val> for ValueRef<'a> {
513            fn from(value: &$val) -> Self {
514                Self::Int(*value as i64)
515            }
516        }
517
518        impl<'a> From<Option<$val>> for ValueRef<'a> {
519            fn from(value: Option<$val>) -> Self {
520                if let Some(v) = value {
521                    Self::Int(v as i64)
522                } else {
523                    Self::Empty
524                }
525            }
526        }
527    };
528}
529
530macro_rules! param_value_ref_float {
531    ($val:ty) => {
532        impl<'a> From<$val> for ValueRef<'a> {
533            fn from(value: $val) -> Self {
534                Self::Float(value as f64)
535            }
536        }
537
538        impl<'a> From<&$val> for ValueRef<'a> {
539            fn from(value: &$val) -> Self {
540                Self::Float(*value as f64)
541            }
542        }
543
544        impl<'a> From<Option<$val>> for ValueRef<'a> {
545            fn from(value: Option<$val>) -> Self {
546                if let Some(v) = value {
547                    Self::Float(v as f64)
548                } else {
549                    Self::Empty
550                }
551            }
552        }
553    };
554}
555
556impl From<ValueRef<'_>> for f32 {
557    fn from(value: ValueRef<'_>) -> Self {
558        value.to_f32().unwrap()
559    }
560}
561
562impl From<ValueRef<'_>> for f64 {
563    fn from(value: ValueRef<'_>) -> Self {
564        value.to_f64().unwrap()
565    }
566}
567
568impl From<ValueRef<'_>> for i32 {
569    fn from(value: ValueRef<'_>) -> Self {
570        value.to_i32().unwrap()
571    }
572}
573
574impl From<ValueRef<'_>> for i64 {
575    fn from(value: ValueRef<'_>) -> Self {
576        value.to_i64().unwrap()
577    }
578}
579
580impl From<bool> for Value {
581    fn from(value: bool) -> Self {
582        Self::Boolean(value)
583    }
584}
585
586impl From<bool> for ValueRef<'_> {
587    fn from(value: bool) -> Self {
588        Self::Boolean(value)
589    }
590}
591
592param_value_ref_int!(i8);
593param_value_ref_int!(i16);
594param_value_ref_int!(i32);
595param_value_ref_int!(i64);
596
597param_value_ref_int!(u8);
598param_value_ref_int!(u16);
599param_value_ref_int!(u32);
600param_value_ref_int!(u64);
601param_value_ref_int!(usize);
602
603param_value_ref_float!(f32);
604param_value_ref_float!(f64);