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