eva_common/value/
mod.rs

1//! Based on https://github.com/arcnmx/serde-value
2#![allow(
3    clippy::cast_possible_truncation,
4    clippy::cast_precision_loss,
5    clippy::cast_sign_loss,
6    clippy::cast_possible_wrap,
7    clippy::cast_lossless
8)]
9
10use crate::{EResult, Error};
11use ordered_float::OrderedFloat;
12use rust_decimal::prelude::*;
13use serde::{Deserialize, Deserializer, Serialize};
14use std::cmp::Ordering;
15use std::collections::{BTreeMap, HashSet};
16use std::convert::AsRef;
17use std::convert::{TryFrom, TryInto};
18use std::fmt;
19use std::hash::{BuildHasher, Hash, Hasher};
20use std::iter::FromIterator;
21#[cfg(feature = "extended-value")]
22use std::path::Path;
23#[cfg(feature = "extended-value")]
24use std::time::Duration;
25
26pub use de::*;
27pub use ser::*;
28
29//pub use ser::SerializerError;
30//pub use de::DeserializerError;
31
32mod de;
33mod index;
34mod ser;
35
36pub use index::{Index, IndexSlice};
37
38impl From<de::DeserializerError> for Error {
39    fn from(err: de::DeserializerError) -> Error {
40        Error::invalid_data(err)
41    }
42}
43
44impl From<ser::SerializerError> for Error {
45    fn from(err: ser::SerializerError) -> Error {
46        Error::invalid_data(err)
47    }
48}
49
50const ERR_INVALID_VALUE: &str = "Invalid value";
51const ERR_INVALID_BOOLEAN_VALUE: &str = "Invalid boolean value";
52const ERR_EXPECTED_VEC_OR_STRING: &str = "Expected Vec or String";
53const ERR_UNABLE_PARSE_FLOAT: &str = "Unable to parse float";
54const ERR_UNABLE_CONVERT_FLOAT: &str = "Unable to convert float";
55const ERR_TOO_BIG_NUMBER: &str = "Value too big";
56const ERR_TOO_SMALL_NUMBER: &str = "Value too small";
57
58macro_rules! float_from_bool {
59    ($v: expr) => {
60        if $v { 1.0 } else { 0.0 }
61    };
62}
63
64#[allow(clippy::module_name_repetitions)]
65#[derive(Debug, Serialize, Clone, Eq, PartialEq, Default)]
66#[serde(untagged)]
67pub enum ValueOptionOwned {
68    #[default]
69    No,
70    Value(Value),
71}
72
73impl ValueOptionOwned {
74    pub fn is_none(&self) -> bool {
75        matches!(self, ValueOptionOwned::No)
76    }
77
78    pub fn is_some(&self) -> bool {
79        !matches!(self, ValueOptionOwned::No)
80    }
81
82    pub fn as_ref(&self) -> Option<&Value> {
83        match self {
84            ValueOptionOwned::No => None,
85            ValueOptionOwned::Value(v) => Some(v),
86        }
87    }
88}
89
90impl From<ValueOptionOwned> for Option<Value> {
91    fn from(vo: ValueOptionOwned) -> Self {
92        match vo {
93            ValueOptionOwned::No => None,
94            ValueOptionOwned::Value(v) => Some(v),
95        }
96    }
97}
98
99impl From<Option<Value>> for ValueOptionOwned {
100    fn from(v: Option<Value>) -> Self {
101        if let Some(val) = v {
102            ValueOptionOwned::Value(val)
103        } else {
104            ValueOptionOwned::No
105        }
106    }
107}
108
109#[allow(clippy::module_name_repetitions)]
110#[derive(Debug, Serialize, Clone, Eq, PartialEq, Default)]
111#[serde(untagged)]
112pub enum ValueOption<'a> {
113    #[default]
114    No,
115    Value(&'a Value),
116}
117
118impl ValueOption<'_> {
119    pub fn is_none(&self) -> bool {
120        matches!(self, ValueOption::No)
121    }
122
123    pub fn is_some(&self) -> bool {
124        !matches!(self, ValueOption::No)
125    }
126}
127
128impl<'de> Deserialize<'de> for ValueOptionOwned {
129    fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
130    where
131        D: Deserializer<'de>,
132    {
133        Ok(ValueOptionOwned::Value(Value::deserialize(deserializer)?))
134    }
135}
136
137#[cfg(feature = "time")]
138#[inline]
139fn parse_time_frame(s: &str) -> Option<f64> {
140    if s.len() < 2 {
141        None
142    } else if let Ok(v) = s[..s.len() - 1].parse::<f64>() {
143        match &s[s.len() - 1..] {
144            "S" => Some(v),
145            "T" => Some(v * 60.0),
146            "H" => Some(v * 3_600.0),
147            "D" => Some(v * 86_400.0),
148            "W" => Some(v * 604_800.0),
149            _ => None,
150        }
151    } else {
152        None
153    }
154}
155
156const ERR_INVALID_JSON_PATH: &str = "invalid JSON path, does not start with $.";
157const ERR_UNSUPPORTED_JSON_PATH_DOUBLE_DOT: &str = "unsupported JSON path (..)";
158
159fn value_jp_lookup<'a>(
160    value: &'a Value,
161    sp: &mut std::str::Split<'_, char>,
162    allow_empty: bool,
163) -> EResult<Option<&'a Value>> {
164    macro_rules! abort {
165        () => {
166            return Ok(None)
167        };
168    }
169    if let Some(x) = sp.next() {
170        if x.is_empty() {
171            if allow_empty {
172                return value_jp_lookup(value, sp, false);
173            }
174            return Err(Error::invalid_params(ERR_UNSUPPORTED_JSON_PATH_DOUBLE_DOT));
175        }
176        let (field, idx) = if x.ends_with(']') {
177            let mut spx = x.rsplitn(2, '[');
178            let idx_s = spx.next().unwrap();
179            let idx: usize = idx_s[..idx_s.len() - 1]
180                .parse()
181                .map_err(|e| Error::invalid_params(format!("invalid path index: {} ({})", x, e)))?;
182            let field = spx
183                .next()
184                .ok_or_else(|| Error::invalid_params(format!("invalid path: {}", x)))?;
185            (if field.is_empty() { None } else { Some(field) }, Some(idx))
186        } else {
187            (Some(x), None)
188        };
189        let field_val = if let Some(f) = field {
190            let Value::Map(m) = value else { abort!() };
191            let Some(v) = m.get(&Value::String(f.to_owned())) else {
192                abort!()
193            };
194            v
195        } else {
196            value
197        };
198        let field_indexed = if let Some(i) = idx {
199            let Value::Seq(s) = field_val else { abort!() };
200            let Some(v) = s.get(i) else { abort!() };
201            v
202        } else {
203            field_val
204        };
205        return value_jp_lookup(field_indexed, sp, true);
206    }
207    Ok(Some(value))
208}
209
210fn value_jp_insert(
211    source: &mut Value,
212    sp: &mut std::str::Split<'_, char>,
213    value: Value,
214    allow_empty: bool,
215) -> EResult<()> {
216    macro_rules! abort {
217        ($err:expr) => {
218            return Err(Error::invalid_data_static($err))
219        };
220    }
221    if let Some(x) = sp.next() {
222        if x.is_empty() {
223            if allow_empty {
224                return value_jp_insert(source, sp, value, false);
225            }
226            return Err(Error::invalid_params(ERR_UNSUPPORTED_JSON_PATH_DOUBLE_DOT));
227        }
228        let (field, idx) = if x.ends_with(']') {
229            let mut spx = x.rsplitn(2, '[');
230            let idx_s = spx.next().unwrap();
231            let idx: usize = idx_s[..idx_s.len() - 1]
232                .parse()
233                .map_err(|e| Error::invalid_params(format!("invalid path index: {} ({})", x, e)))?;
234            let field = spx
235                .next()
236                .ok_or_else(|| Error::invalid_params(format!("invalid path: {}", x)))?;
237            (if field.is_empty() { None } else { Some(field) }, Some(idx))
238        } else {
239            (Some(x), None)
240        };
241        let field_val = if let Some(f) = field {
242            if *source == Value::Unit {
243                *source = Value::Map(<_>::default());
244            }
245            let Value::Map(m) = source else {
246                abort!("source is not a map")
247            };
248            m.entry(Value::String(f.to_owned())).or_insert(Value::Unit)
249        } else {
250            source
251        };
252        let field_indexed = if let Some(i) = idx {
253            if *field_val == Value::Unit {
254                *field_val = Value::Seq(<_>::default());
255            }
256            let Value::Seq(s) = field_val else {
257                abort!("source is not a sequence")
258            };
259            if s.len() < i + 1 {
260                s.resize(i + 1, Value::Unit);
261            }
262            s.get_mut(i).unwrap()
263        } else {
264            field_val
265        };
266        return value_jp_insert(field_indexed, sp, value, true);
267    }
268    *source = value;
269    Ok(())
270}
271
272#[inline]
273fn parse_jp(path: &str) -> EResult<std::str::Split<'_, char>> {
274    if let Some(p) = path.strip_prefix("$.") {
275        Ok(p.split('.'))
276    } else {
277        Err(Error::invalid_params(ERR_INVALID_JSON_PATH))
278    }
279}
280
281#[derive(Clone, Debug, Default)]
282pub enum Value {
283    Bool(bool),
284
285    U8(u8),
286    U16(u16),
287    U32(u32),
288    U64(u64),
289
290    I8(i8),
291    I16(i16),
292    I32(i32),
293    I64(i64),
294
295    F32(f32),
296    F64(f64),
297
298    Char(char),
299    String(String),
300
301    #[default]
302    Unit,
303    Option(Option<Box<Value>>),
304    Newtype(Box<Value>),
305    Seq(Vec<Value>),
306    Map(BTreeMap<Value, Value>),
307    Bytes(Vec<u8>),
308}
309
310impl fmt::Display for Value {
311    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
312        match self {
313            Value::Bool(v) => write!(f, "{}", v),
314            Value::U8(v) => write!(f, "{}", v),
315            Value::U16(v) => write!(f, "{}", v),
316            Value::U32(v) => write!(f, "{}", v),
317            Value::U64(v) => write!(f, "{}", v),
318            Value::I8(v) => write!(f, "{}", v),
319            Value::I16(v) => write!(f, "{}", v),
320            Value::I32(v) => write!(f, "{}", v),
321            Value::I64(v) => write!(f, "{}", v),
322            Value::F32(v) => write!(f, "{}", v),
323            Value::F64(v) => write!(f, "{}", v),
324            Value::Char(v) => write!(f, "{}", v),
325            Value::String(v) => write!(f, "{}", v),
326            Value::Unit => write!(f, ""),
327            Value::Option(v) => {
328                if let Some(val) = v {
329                    write!(f, "{}", val)
330                } else {
331                    write!(f, "")
332                }
333            }
334            Value::Newtype(v) => write!(f, "{}", v),
335            Value::Seq(v) => write!(f, "{:?}", v),
336            Value::Map(v) => write!(f, "{:?}", v),
337            Value::Bytes(v) => write!(f, "{:?}", v),
338        }
339    }
340}
341
342impl Hash for Value {
343    fn hash<H>(&self, hasher: &mut H)
344    where
345        H: Hasher,
346    {
347        self.discriminant().hash(hasher);
348        match *self {
349            Value::Bool(v) => v.hash(hasher),
350            Value::U8(v) => v.hash(hasher),
351            Value::U16(v) => v.hash(hasher),
352            Value::U32(v) => v.hash(hasher),
353            Value::U64(v) => v.hash(hasher),
354            Value::I8(v) => v.hash(hasher),
355            Value::I16(v) => v.hash(hasher),
356            Value::I32(v) => v.hash(hasher),
357            Value::I64(v) => v.hash(hasher),
358            Value::F32(v) => OrderedFloat(v).hash(hasher),
359            Value::F64(v) => OrderedFloat(v).hash(hasher),
360            Value::Char(v) => v.hash(hasher),
361            Value::String(ref v) => v.hash(hasher),
362            Value::Unit => 0_u8.hash(hasher),
363            Value::Option(ref v) => v.hash(hasher),
364            Value::Newtype(ref v) => v.hash(hasher),
365            Value::Seq(ref v) => v.hash(hasher),
366            Value::Map(ref v) => v.hash(hasher),
367            Value::Bytes(ref v) => v.hash(hasher),
368        }
369    }
370}
371
372macro_rules! cmp_number {
373    ($n: expr, $v: expr, $t: ty) => {
374        if $v.is_numeric_type() {
375            <$t>::try_from($v).map_or(false, |v| $n == v)
376        } else {
377            false
378        }
379    };
380}
381
382impl PartialEq for Value {
383    fn eq(&self, rhs: &Self) -> bool {
384        match (self, rhs) {
385            (&Value::Bool(v0), &Value::Bool(v1)) if v0 == v1 => true,
386            (v0, &Value::F32(v1)) => cmp_number!(v1, v0, f32),
387            (v0, &Value::F64(v1)) => cmp_number!(v1, v0, f64),
388            (&Value::U8(v0), v1) => cmp_number!(v0, v1, u8),
389            (&Value::U16(v0), v1) => cmp_number!(v0, v1, u16),
390            (&Value::U32(v0), v1) => cmp_number!(v0, v1, u32),
391            (&Value::U64(v0), v1) => cmp_number!(v0, v1, u64),
392            (&Value::I8(v0), v1) => cmp_number!(v0, v1, i8),
393            (&Value::I16(v0), v1) => cmp_number!(v0, v1, i16),
394            (&Value::I32(v0), v1) => cmp_number!(v0, v1, i32),
395            (&Value::I64(v0), v1) => cmp_number!(v0, v1, i64),
396            (&Value::F32(v0), v1) => cmp_number!(v0, v1, f32),
397            (&Value::F64(v0), v1) => cmp_number!(v0, v1, f64),
398            (&Value::Char(v0), &Value::Char(v1)) if v0 == v1 => true,
399            (Value::String(v0), Value::String(v1)) if v0 == v1 => true,
400            (&Value::Unit, &Value::Unit) => true,
401            (Value::Option(v0), Value::Option(v1)) if v0 == v1 => true,
402            (Value::Newtype(v0), Value::Newtype(v1)) if v0 == v1 => true,
403            (Value::Seq(v0), Value::Seq(v1)) if v0 == v1 => true,
404            (Value::Map(v0), Value::Map(v1)) if v0 == v1 => true,
405            (Value::Bytes(v0), Value::Bytes(v1)) if v0 == v1 => true,
406            _ => false,
407        }
408    }
409}
410
411impl Ord for Value {
412    fn cmp(&self, rhs: &Self) -> Ordering {
413        match (self, rhs) {
414            (Value::Bool(v0), Value::Bool(v1)) => v0.cmp(v1),
415            (Value::U8(v0), Value::U8(v1)) => v0.cmp(v1),
416            (Value::U16(v0), Value::U16(v1)) => v0.cmp(v1),
417            (Value::U32(v0), Value::U32(v1)) => v0.cmp(v1),
418            (Value::U64(v0), Value::U64(v1)) => v0.cmp(v1),
419            (Value::I8(v0), Value::I8(v1)) => v0.cmp(v1),
420            (Value::I16(v0), Value::I16(v1)) => v0.cmp(v1),
421            (Value::I32(v0), Value::I32(v1)) => v0.cmp(v1),
422            (Value::I64(v0), Value::I64(v1)) => v0.cmp(v1),
423            (&Value::F32(v0), &Value::F32(v1)) => OrderedFloat(v0).cmp(&OrderedFloat(v1)),
424            (&Value::F64(v0), &Value::F64(v1)) => OrderedFloat(v0).cmp(&OrderedFloat(v1)),
425            (Value::Char(v0), Value::Char(v1)) => v0.cmp(v1),
426            (Value::String(v0), Value::String(v1)) => v0.cmp(v1),
427            (&Value::Unit, &Value::Unit) => Ordering::Equal,
428            (Value::Option(v0), Value::Option(v1)) => v0.cmp(v1),
429            (Value::Newtype(v0), Value::Newtype(v1)) => v0.cmp(v1),
430            (Value::Seq(v0), Value::Seq(v1)) => v0.cmp(v1),
431            (Value::Map(v0), Value::Map(v1)) => v0.cmp(v1),
432            (Value::Bytes(v0), Value::Bytes(v1)) => v0.cmp(v1),
433            (v0, v1) => v0.discriminant().cmp(&v1.discriminant()),
434        }
435    }
436}
437
438fn strip_bytes_rec(value: Value) -> Value {
439    if let Value::Bytes(_) = value {
440        Value::String("<binary>".to_owned())
441    } else if let Value::Seq(s) = value {
442        let v: Vec<Value> = s.into_iter().map(strip_bytes_rec).collect();
443        Value::Seq(v)
444    } else if let Value::Map(m) = value {
445        let mut result = BTreeMap::new();
446        for (k, v) in m {
447            result.insert(k, strip_bytes_rec(v));
448        }
449        Value::Map(result)
450    } else {
451        value
452    }
453}
454
455fn flat_seq_value_rec(v: Value, result: &mut Vec<Value>) {
456    if let Value::Seq(s) = v {
457        for val in s {
458            flat_seq_value_rec(val, result);
459        }
460    } else {
461        result.push(v);
462    }
463}
464
465impl Value {
466    pub fn jp_lookup<'a>(&'a self, path: &str) -> EResult<Option<&'a Value>> {
467        let mut sp = parse_jp(path)?;
468        value_jp_lookup(self, &mut sp, true)
469    }
470    pub fn jp_insert(&mut self, path: &str, value: Value) -> EResult<()> {
471        let mut sp = parse_jp(path)?;
472        value_jp_insert(self, &mut sp, value, true)
473    }
474    pub fn into_seq_flatten(self) -> Value {
475        let result = if self.is_seq() {
476            let mut result = Vec::new();
477            flat_seq_value_rec(self, &mut result);
478            result
479        } else {
480            vec![self]
481        };
482        Value::Seq(result)
483    }
484    pub fn into_seq_reshaped(self, dimensions: &[usize]) -> Value {
485        let default = match self {
486            Value::Bool(_) => Value::Bool(false),
487            Value::String(_) => Value::String(String::new()),
488            Value::Unit => Value::Unit,
489            _ => Value::U8(0),
490        };
491        let Value::Seq(mut v) = self.into_seq_flatten() else {
492            return Value::Unit;
493        };
494        if dimensions.is_empty() {
495            return Value::Seq(v);
496        }
497        let mut len = 1;
498        for d in dimensions {
499            len *= d;
500        }
501        v.resize(len, default);
502        for d in dimensions[1..].iter().rev() {
503            let d = *d;
504            let len = v.len();
505            let mut result: Vec<Value> = Vec::with_capacity(len / d);
506            for _ in (0..len).step_by(d) {
507                let tail = v.split_off(d);
508                result.push(Value::Seq(v));
509                v = tail;
510            }
511            v = result;
512        }
513        Value::Seq(v)
514    }
515    #[inline]
516    pub fn get_by_index(&self, idx: &Index) -> Option<&Value> {
517        self.get_by_index_slice(idx.as_slice())
518    }
519    fn get_by_index_slice(&self, idx: IndexSlice<'_>) -> Option<&Value> {
520        if idx.0.is_empty() {
521            return Some(self);
522        }
523        if let Value::Seq(s) = self {
524            if let Some(s) = s.get(idx.0[0]) {
525                return s.get_by_index_slice(IndexSlice(&idx.0[1..]));
526            }
527        } else if idx.0.len() == 1 && idx.0[0] == 0 {
528            return Some(self);
529        }
530        None
531    }
532
533    /// Rounds value to digits after comma, if the value is float
534    #[allow(clippy::cast_possible_truncation)]
535    #[allow(clippy::cast_sign_loss)]
536    pub fn rounded(self, precision: Option<u32>) -> EResult<Value> {
537        if let Some(precs) = precision {
538            if let Value::F64(vf) = self {
539                if precs > 0 {
540                    let d = Decimal::from_f64_retain(vf)
541                        .ok_or_else(|| Error::invalid_data_static(ERR_UNABLE_PARSE_FLOAT))?;
542                    let rounded = d.round_dp(precs);
543                    return Ok(Value::F64(rounded.to_f64().ok_or_else(|| {
544                        Error::invalid_data_static(ERR_UNABLE_CONVERT_FLOAT)
545                    })?));
546                }
547                return Ok(Value::I64(vf.round() as i64));
548            }
549            if let Value::F32(vf) = self {
550                if precs > 0 {
551                    let d = Decimal::from_f32_retain(vf)
552                        .ok_or_else(|| Error::invalid_data_static(ERR_UNABLE_PARSE_FLOAT))?;
553                    let rounded = d.round_dp(precs);
554                    return Ok(Value::F32(rounded.to_f32().ok_or_else(|| {
555                        Error::invalid_data_static(ERR_UNABLE_CONVERT_FLOAT)
556                    })?));
557                }
558                return Ok(Value::I32(vf.round() as i32));
559            }
560        }
561        Ok(self)
562    }
563
564    pub fn to_no_bytes(self) -> Value {
565        strip_bytes_rec(self)
566    }
567
568    #[cfg(feature = "time")]
569    #[inline]
570    /// Tries to convert Value to f64 timestamp
571    ///
572    /// Valid options are:
573    ///
574    /// number - timestamp as-is
575    /// time frame as N<S|T|H|D|W>, e.g. 5T for 5 minutes: now - time frame
576    /// other string - tries to parse the string into date/time
577    pub fn as_timestamp(&self) -> EResult<f64> {
578        self.as_ts(true)
579    }
580
581    #[cfg(feature = "time")]
582    #[inline]
583    /// Same as as_timestamp() but time frames are added to now
584    pub fn as_future_timestamp(&self) -> EResult<f64> {
585        self.as_ts(false)
586    }
587
588    #[cfg(feature = "time")]
589    #[allow(clippy::cast_precision_loss)]
590    fn as_ts(&self, tf_past: bool) -> EResult<f64> {
591        if let Ok(v) = f64::try_from(self) {
592            Ok(v)
593        } else if let Value::String(s) = self {
594            if let Some(v) = parse_time_frame(s) {
595                let now = crate::time::now_ns_float();
596                Ok(if tf_past { now - v } else { now + v })
597            } else {
598                let d = dateparser::parse(s).map_err(Error::invalid_data)?;
599                let timestamp =
600                    d.timestamp() as f64 + f64::from(d.timestamp_subsec_nanos()) / 1_000_000_000.0;
601                Ok(timestamp)
602            }
603        } else {
604            Err(Error::invalid_data_static("unsupported date/time format"))
605        }
606    }
607
608    pub fn is_true(&self) -> bool {
609        match self {
610            Value::Bool(v) => *v,
611            Value::U8(v) => *v != 0,
612            Value::U16(v) => *v != 0,
613            Value::U32(v) => *v != 0,
614            Value::U64(v) => *v != 0,
615            Value::I8(v) => *v != 0,
616            Value::I16(v) => *v != 0,
617            Value::I32(v) => *v != 0,
618            Value::I64(v) => *v != 0,
619            Value::F32(v) => *v != 0.0,
620            Value::F64(v) => *v != 0.0,
621            Value::String(v) => {
622                let v_l = v.to_lowercase();
623                v_l == "true" || v_l == "yes" || v_l == "1"
624            }
625            _ => false,
626        }
627    }
628
629    pub fn to_alphanumeric_string(self) -> EResult<String> {
630        match self {
631            Value::Bool(v) => Ok(v.to_string()),
632            Value::U8(v) => Ok(v.to_string()),
633            Value::U16(v) => Ok(v.to_string()),
634            Value::U32(v) => Ok(v.to_string()),
635            Value::U64(v) => Ok(v.to_string()),
636            Value::I8(v) => Ok(v.to_string()),
637            Value::I16(v) => Ok(v.to_string()),
638            Value::I32(v) => Ok(v.to_string()),
639            Value::I64(v) => Ok(v.to_string()),
640            Value::F32(v) => Ok(v.to_string()),
641            Value::F64(v) => Ok(v.to_string()),
642            Value::Char(v) => Ok(v.to_string()),
643            Value::String(v) => {
644                for c in v.chars() {
645                    if !c.is_alphanumeric() {
646                        return Err(Error::invalid_params(format!("invalid symbols in {}", v)));
647                    }
648                }
649                Ok(v)
650            }
651            Value::Unit => Ok("null".to_owned()),
652            _ => Err(Error::invalid_data(format!(
653                "unable to get string from {:?}",
654                self
655            ))),
656        }
657    }
658
659    pub fn to_string_or_pack(self) -> EResult<String> {
660        match self {
661            Value::U8(v) => Ok(v.to_string()),
662            Value::U16(v) => Ok(v.to_string()),
663            Value::U32(v) => Ok(v.to_string()),
664            Value::U64(v) => Ok(v.to_string()),
665            Value::I8(v) => Ok(v.to_string()),
666            Value::I16(v) => Ok(v.to_string()),
667            Value::I32(v) => Ok(v.to_string()),
668            Value::I64(v) => Ok(v.to_string()),
669            Value::F32(v) => Ok(v.to_string()),
670            Value::F64(v) => Ok(v.to_string()),
671            Value::Char(v) => Ok(v.to_string()),
672            Value::String(v) => Ok(v),
673            _ => Ok(format!("!!{}", serde_json::to_string(&self)?)),
674        }
675    }
676
677    pub fn unpack(self) -> EResult<Self> {
678        if let Value::String(ref v) = self
679            && let Some(s) = v.strip_prefix("!!")
680        {
681            return serde_json::from_str(s).map_err(Into::into);
682        }
683        Ok(self)
684    }
685
686    fn discriminant(&self) -> usize {
687        match *self {
688            Value::Bool(..) => 0,
689            Value::U8(..) => 1,
690            Value::U16(..) => 2,
691            Value::U32(..) => 3,
692            Value::U64(..) => 4,
693            Value::I8(..) => 5,
694            Value::I16(..) => 6,
695            Value::I32(..) => 7,
696            Value::I64(..) => 8,
697            Value::F32(..) => 9,
698            Value::F64(..) => 10,
699            Value::Char(..) => 11,
700            Value::String(..) => 12,
701            Value::Unit => 13,
702            Value::Option(..) => 14,
703            Value::Newtype(..) => 15,
704            Value::Seq(..) => 16,
705            Value::Map(..) => 17,
706            Value::Bytes(..) => 18,
707        }
708    }
709
710    fn unexpected(&self) -> serde::de::Unexpected<'_> {
711        match *self {
712            Value::Bool(b) => serde::de::Unexpected::Bool(b),
713            Value::U8(n) => serde::de::Unexpected::Unsigned(u64::from(n)),
714            Value::U16(n) => serde::de::Unexpected::Unsigned(u64::from(n)),
715            Value::U32(n) => serde::de::Unexpected::Unsigned(u64::from(n)),
716            Value::U64(n) => serde::de::Unexpected::Unsigned(n),
717            Value::I8(n) => serde::de::Unexpected::Signed(i64::from(n)),
718            Value::I16(n) => serde::de::Unexpected::Signed(i64::from(n)),
719            Value::I32(n) => serde::de::Unexpected::Signed(i64::from(n)),
720            Value::I64(n) => serde::de::Unexpected::Signed(n),
721            Value::F32(n) => serde::de::Unexpected::Float(f64::from(n)),
722            Value::F64(n) => serde::de::Unexpected::Float(n),
723            Value::Char(c) => serde::de::Unexpected::Char(c),
724            Value::String(ref s) => serde::de::Unexpected::Str(s),
725            Value::Unit => serde::de::Unexpected::Unit,
726            Value::Option(_) => serde::de::Unexpected::Option,
727            Value::Newtype(_) => serde::de::Unexpected::NewtypeStruct,
728            Value::Seq(_) => serde::de::Unexpected::Seq,
729            Value::Map(_) => serde::de::Unexpected::Map,
730            Value::Bytes(ref b) => serde::de::Unexpected::Bytes(b),
731        }
732    }
733
734    pub fn deserialize_into<'de, T: Deserialize<'de>>(self) -> Result<T, DeserializerError> {
735        T::deserialize(self)
736    }
737    pub fn is_empty(&self) -> bool {
738        match self {
739            Value::Unit => true,
740            Value::Option(v) => v.is_none(),
741            Value::String(s) => s.is_empty(),
742            _ => false,
743        }
744    }
745    #[inline]
746    pub fn is_unit(&self) -> bool {
747        *self == Value::Unit
748    }
749    pub fn is_numeric_type(&self) -> bool {
750        matches!(
751            self,
752            Value::U8(_)
753                | Value::U16(_)
754                | Value::U32(_)
755                | Value::U64(_)
756                | Value::I8(_)
757                | Value::I16(_)
758                | Value::I32(_)
759                | Value::I64(_)
760                | Value::F32(_)
761                | Value::F64(_)
762        )
763    }
764    pub fn is_numeric(&self) -> bool {
765        match self {
766            Value::U8(_)
767            | Value::U16(_)
768            | Value::U32(_)
769            | Value::U64(_)
770            | Value::I8(_)
771            | Value::I16(_)
772            | Value::I32(_)
773            | Value::I64(_)
774            | Value::F32(_)
775            | Value::F64(_) => true,
776            Value::String(v) => v.parse::<f64>().is_ok() || v.parse::<i128>().is_ok(),
777            _ => false,
778        }
779    }
780    pub fn is_seq(&self) -> bool {
781        matches!(self, Value::Seq(_))
782    }
783    pub fn is_map(&self) -> bool {
784        matches!(self, Value::Map(_))
785    }
786    #[cfg(feature = "extended-value")]
787    pub async fn extend(self, timeout: Duration, base: &Path) -> EResult<Value> {
788        let op = crate::op::Op::new(timeout);
789        extend_value(self, &op, base).await
790    }
791}
792
793#[cfg(feature = "extended-value")]
794#[async_recursion::async_recursion]
795async fn extend_value(value: Value, op: &crate::op::Op, base: &Path) -> EResult<Value> {
796    match value {
797        Value::String(s) => Ok(extend_string_value(s, op, base).await?),
798        Value::Seq(s) => {
799            let mut result = Vec::with_capacity(s.len());
800            for val in s {
801                result.push(extend_value(val, op, base).await?);
802            }
803            Ok(Value::Seq(result))
804        }
805        Value::Map(m) => {
806            let mut result = BTreeMap::new();
807            for (k, v) in m {
808                result.insert(k, extend_value(v, op, base).await?);
809            }
810            Ok(Value::Map(result))
811        }
812        _ => Ok(value),
813    }
814}
815
816impl FromStr for Value {
817    type Err = std::convert::Infallible;
818    fn from_str(s: &str) -> Result<Self, Self::Err> {
819        Ok(if let Ok(v) = s.parse::<u64>() {
820            Value::U64(v)
821        } else if let Ok(v) = s.parse::<i64>() {
822            Value::I64(v)
823        } else if let Ok(v) = s.parse::<f64>() {
824            Value::F64(v)
825        } else {
826            serde_json::from_str(s).unwrap_or_else(|_| {
827                let s_l = s.to_lowercase();
828                match s_l.as_str() {
829                    "true" => Value::Bool(true),
830                    "false" => Value::Bool(false),
831                    "none" | "null" => Value::Unit,
832                    _ => Value::String(s.to_owned()),
833                }
834            })
835        })
836    }
837}
838
839#[cfg(feature = "extended-value")]
840async fn extend_string_value(val: String, op: &crate::op::Op, base: &Path) -> EResult<Value> {
841    if let Some(s) = val.strip_prefix('^') {
842        let mut sp = s.splitn(2, ' ');
843        let cmd = sp.next().unwrap();
844        macro_rules! pipe {
845            () => {{
846                let cmd = sp
847                    .next()
848                    .ok_or_else(|| Error::invalid_params("xvalue pipe: command not specified"))?;
849                let cd_cmd = format!("cd \"{}\" && {}", base.to_string_lossy(), cmd);
850                let res = bmart::process::command(
851                    "sh",
852                    &["-c", &cd_cmd],
853                    op.timeout()?,
854                    bmart::process::Options::default(),
855                )
856                .await?;
857                if res.ok() {
858                    res.out.join("\n")
859                } else {
860                    return Err(Error::failed(format!(
861                        "xvalue pipe command failed to execute: {}",
862                        res.err.join("\n")
863                    )));
864                }
865            }};
866        }
867        match cmd {
868            "include" => {
869                let fname = sp.next().ok_or_else(|| {
870                    Error::invalid_params("xvalue include: file name not specified")
871                })?;
872                let mut path = base.to_path_buf();
873                path.push(fname);
874                let content = tokio::time::timeout(op.timeout()?, tokio::fs::read(path)).await??;
875                let val: Value = serde_yaml::from_str(std::str::from_utf8(&content)?)
876                    .map_err(Error::invalid_data)?;
877                Ok(val)
878            }
879            "include-text" => {
880                let fname = sp.next().ok_or_else(|| {
881                    Error::invalid_params("xvalue include: file name not specified")
882                })?;
883                let mut path = base.to_path_buf();
884                path.push(fname);
885                let content =
886                    tokio::time::timeout(op.timeout()?, tokio::fs::read_to_string(path)).await??;
887                Ok(Value::String(content.trim_end().to_string()))
888            }
889            "pipe" => {
890                let s = pipe!();
891                let val: Value = serde_yaml::from_str(&s).map_err(Error::invalid_data)?;
892                Ok(val)
893            }
894            "pipe-text" => {
895                let s = pipe!();
896                Ok(Value::String(s.trim_end().to_string()))
897            }
898            _ => Ok(Value::String(if s.starts_with('^') {
899                s.to_owned()
900            } else {
901                val
902            })),
903        }
904    } else {
905        Ok(Value::String(val))
906    }
907}
908
909impl Eq for Value {}
910impl PartialOrd for Value {
911    fn partial_cmp(&self, rhs: &Self) -> Option<Ordering> {
912        Some(self.cmp(rhs))
913    }
914}
915
916macro_rules! impl_from {
917    ($v: ty, $val: expr) => {
918        impl From<$v> for Value {
919            fn from(src: $v) -> Value {
920                $val(src)
921            }
922        }
923    };
924}
925
926impl_from!(bool, Value::Bool);
927impl_from!(u8, Value::U8);
928impl_from!(i8, Value::I8);
929impl_from!(u16, Value::U16);
930impl_from!(i16, Value::I16);
931impl_from!(u32, Value::U32);
932impl_from!(i32, Value::I32);
933impl_from!(u64, Value::U64);
934impl_from!(i64, Value::I64);
935impl_from!(f32, Value::F32);
936impl_from!(f64, Value::F64);
937impl_from!(String, Value::String);
938
939// comparing $from unsigned bigger
940macro_rules! ngt {
941    ($n: expr, $from: ident, $to: ident) => {
942        if $n > $to::MAX as $from {
943            return Err(Error::invalid_data_static(ERR_TOO_BIG_NUMBER));
944        } else {
945            $n as $to
946        }
947    };
948}
949// comparing $from signed bigger $to signed/unsigned smaller
950macro_rules! ngt_nlt {
951    ($n: expr, $from: ident, $to: ident) => {
952        if $n > $to::MAX as $from {
953            return Err(Error::invalid_data_static(ERR_TOO_BIG_NUMBER));
954        } else if $n < $to::MIN as $from {
955            return Err(Error::invalid_data_static(ERR_TOO_SMALL_NUMBER));
956        } else {
957            $n as $to
958        }
959    };
960}
961// comparing $from smaller signed with $to unsigned (check that $from is zero-positive)
962macro_rules! nltz {
963    ($n: expr, $from: ident, $to: ident) => {
964        if $n < 0 as $from {
965            return Err(Error::invalid_data_static(ERR_TOO_SMALL_NUMBER));
966        } else {
967            $n as $to
968        }
969    };
970}
971
972impl TryFrom<Value> for u8 {
973    type Error = Error;
974
975    fn try_from(value: Value) -> EResult<u8> {
976        match value {
977            Value::Bool(v) => Ok(u8::from(v)),
978            Value::U8(v) => Ok(v),
979            Value::U16(v) => Ok(ngt!(v, u16, u8)),
980            Value::U32(v) => Ok(ngt!(v, u32, u8)),
981            Value::U64(v) => Ok(ngt!(v, u64, u8)),
982            Value::I8(v) => Ok(nltz!(v, i8, u8)),
983            Value::I16(v) => Ok(ngt_nlt!(v, i16, u8)),
984            Value::I32(v) => Ok(ngt_nlt!(v, i32, u8)),
985            Value::I64(v) => Ok(ngt_nlt!(v, i64, u8)),
986            Value::F32(v) => Ok(ngt_nlt!(v, f32, u8)),
987            Value::F64(v) => Ok(ngt_nlt!(v, f64, u8)),
988            Value::String(v) => Ok(v.parse::<u8>()?),
989            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
990        }
991    }
992}
993
994impl TryFrom<&Value> for u8 {
995    type Error = Error;
996
997    fn try_from(value: &Value) -> EResult<u8> {
998        match value {
999            Value::Bool(v) => Ok(u8::from(*v)),
1000            Value::U8(v) => Ok(*v),
1001            Value::U16(v) => Ok(ngt!(*v, u16, u8)),
1002            Value::U32(v) => Ok(ngt!(*v, u32, u8)),
1003            Value::U64(v) => Ok(ngt!(*v, u64, u8)),
1004            Value::I8(v) => Ok(nltz!(*v, i8, u8)),
1005            Value::I16(v) => Ok(ngt_nlt!(*v, i16, u8)),
1006            Value::I32(v) => Ok(ngt_nlt!(*v, i32, u8)),
1007            Value::I64(v) => Ok(ngt_nlt!(*v, i64, u8)),
1008            Value::F32(v) => Ok(ngt_nlt!(*v, f32, u8)),
1009            Value::F64(v) => Ok(ngt_nlt!(*v, f64, u8)),
1010            Value::String(v) => Ok(v.parse::<u8>()?),
1011            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
1012        }
1013    }
1014}
1015
1016impl TryFrom<Value> for i8 {
1017    type Error = Error;
1018
1019    fn try_from(value: Value) -> EResult<i8> {
1020        match value {
1021            Value::Bool(v) => Ok(i8::from(v)),
1022            Value::U8(v) => Ok(ngt!(v, u8, i8)),
1023            Value::U16(v) => Ok(ngt!(v, u16, i8)),
1024            Value::U32(v) => Ok(ngt!(v, u32, i8)),
1025            Value::U64(v) => Ok(ngt!(v, u64, i8)),
1026            Value::I8(v) => Ok(v),
1027            Value::I16(v) => Ok(ngt_nlt!(v, i16, i8)),
1028            Value::I32(v) => Ok(ngt_nlt!(v, i32, i8)),
1029            Value::I64(v) => Ok(ngt_nlt!(v, i64, i8)),
1030            Value::F32(v) => Ok(ngt_nlt!(v, f32, i8)),
1031            Value::F64(v) => Ok(ngt_nlt!(v, f64, i8)),
1032            Value::String(v) => Ok(v.parse::<i8>()?),
1033            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
1034        }
1035    }
1036}
1037
1038impl TryFrom<&Value> for i8 {
1039    type Error = Error;
1040
1041    fn try_from(value: &Value) -> EResult<i8> {
1042        match value {
1043            Value::Bool(v) => Ok(i8::from(*v)),
1044            Value::U8(v) => Ok(ngt!(*v, u8, i8)),
1045            Value::U16(v) => Ok(ngt!(*v, u16, i8)),
1046            Value::U32(v) => Ok(ngt!(*v, u32, i8)),
1047            Value::U64(v) => Ok(ngt!(*v, u64, i8)),
1048            Value::I8(v) => Ok(*v),
1049            Value::I16(v) => Ok(ngt_nlt!(*v, i16, i8)),
1050            Value::I32(v) => Ok(ngt_nlt!(*v, i32, i8)),
1051            Value::I64(v) => Ok(ngt_nlt!(*v, i64, i8)),
1052            Value::F32(v) => Ok(ngt_nlt!(*v, f32, i8)),
1053            Value::F64(v) => Ok(ngt_nlt!(*v, f64, i8)),
1054            Value::String(v) => Ok(v.parse::<i8>()?),
1055            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
1056        }
1057    }
1058}
1059
1060impl TryFrom<Value> for u16 {
1061    type Error = Error;
1062
1063    fn try_from(value: Value) -> EResult<u16> {
1064        match value {
1065            Value::Bool(v) => Ok(u16::from(v)),
1066            Value::U8(v) => Ok(u16::from(v)),
1067            Value::U16(v) => Ok(v),
1068            Value::U32(v) => Ok(ngt!(v, u32, u16)),
1069            Value::U64(v) => Ok(ngt!(v, u64, u16)),
1070            Value::I8(v) => Ok(nltz!(v, i8, u16)),
1071            Value::I16(v) => Ok(nltz!(v, i16, u16)),
1072            Value::I32(v) => Ok(ngt_nlt!(v, i32, u16)),
1073            Value::I64(v) => Ok(ngt_nlt!(v, i64, u16)),
1074            Value::F32(v) => Ok(ngt_nlt!(v, f32, u16)),
1075            Value::F64(v) => Ok(ngt_nlt!(v, f64, u16)),
1076            Value::String(v) => Ok(v.parse::<u16>()?),
1077            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
1078        }
1079    }
1080}
1081
1082impl TryFrom<&Value> for u16 {
1083    type Error = Error;
1084
1085    fn try_from(value: &Value) -> EResult<u16> {
1086        match value {
1087            Value::Bool(v) => Ok(u16::from(*v)),
1088            Value::U8(v) => Ok(u16::from(*v)),
1089            Value::U16(v) => Ok(*v),
1090            Value::U32(v) => Ok(ngt!(*v, u32, u16)),
1091            Value::U64(v) => Ok(ngt!(*v, u64, u16)),
1092            Value::I8(v) => Ok(nltz!(*v, i8, u16)),
1093            Value::I16(v) => Ok(nltz!(*v, i16, u16)),
1094            Value::I32(v) => Ok(ngt_nlt!(*v, i32, u16)),
1095            Value::I64(v) => Ok(ngt_nlt!(*v, i64, u16)),
1096            Value::F32(v) => Ok(ngt_nlt!(*v, f32, u16)),
1097            Value::F64(v) => Ok(ngt_nlt!(*v, f64, u16)),
1098            Value::String(v) => Ok(v.parse::<u16>()?),
1099            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
1100        }
1101    }
1102}
1103
1104impl TryFrom<Value> for i16 {
1105    type Error = Error;
1106
1107    fn try_from(value: Value) -> EResult<i16> {
1108        match value {
1109            Value::Bool(v) => Ok(i16::from(v)),
1110            Value::U8(v) => Ok(i16::from(v)),
1111            Value::U16(v) => Ok(ngt!(v, u16, i16)),
1112            Value::U32(v) => Ok(ngt!(v, u32, i16)),
1113            Value::U64(v) => Ok(ngt!(v, u64, i16)),
1114            Value::I8(v) => Ok(i16::from(v)),
1115            Value::I16(v) => Ok(v),
1116            Value::I32(v) => Ok(ngt_nlt!(v, i32, i16)),
1117            Value::I64(v) => Ok(ngt_nlt!(v, i64, i16)),
1118            Value::F32(v) => Ok(ngt_nlt!(v, f32, i16)),
1119            Value::F64(v) => Ok(ngt_nlt!(v, f64, i16)),
1120            Value::String(v) => Ok(v.parse::<i16>()?),
1121            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
1122        }
1123    }
1124}
1125
1126impl TryFrom<&Value> for i16 {
1127    type Error = Error;
1128
1129    fn try_from(value: &Value) -> EResult<i16> {
1130        match value {
1131            Value::Bool(v) => Ok(i16::from(*v)),
1132            Value::U8(v) => Ok(i16::from(*v)),
1133            Value::U16(v) => Ok(ngt!(*v, u16, i16)),
1134            Value::U32(v) => Ok(ngt!(*v, u32, i16)),
1135            Value::U64(v) => Ok(ngt!(*v, u64, i16)),
1136            Value::I8(v) => Ok(i16::from(*v)),
1137            Value::I16(v) => Ok(*v),
1138            Value::I32(v) => Ok(ngt_nlt!(*v, i32, i16)),
1139            Value::I64(v) => Ok(ngt_nlt!(*v, i64, i16)),
1140            Value::F32(v) => Ok(ngt_nlt!(*v, f32, i16)),
1141            Value::F64(v) => Ok(ngt_nlt!(*v, f64, i16)),
1142            Value::String(v) => Ok(v.parse::<i16>()?),
1143            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
1144        }
1145    }
1146}
1147
1148impl TryFrom<Value> for u32 {
1149    type Error = Error;
1150
1151    fn try_from(value: Value) -> EResult<u32> {
1152        match value {
1153            Value::Bool(v) => Ok(u32::from(v)),
1154            Value::U8(v) => Ok(u32::from(v)),
1155            Value::U16(v) => Ok(u32::from(v)),
1156            Value::U32(v) => Ok(v),
1157            Value::U64(v) => Ok(ngt!(v, u64, u32)),
1158            Value::I8(v) => Ok(nltz!(v, i8, u32)),
1159            Value::I16(v) => Ok(nltz!(v, i16, u32)),
1160            Value::I32(v) => Ok(nltz!(v, i32, u32)),
1161            Value::I64(v) => Ok(ngt_nlt!(v, i64, u32)),
1162            Value::F32(v) => Ok(nltz!(v, f32, u32)),
1163            Value::F64(v) => Ok(ngt_nlt!(v, f64, u32)),
1164            Value::String(v) => Ok(v.parse::<u32>()?),
1165            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
1166        }
1167    }
1168}
1169
1170impl TryFrom<&Value> for u32 {
1171    type Error = Error;
1172
1173    fn try_from(value: &Value) -> EResult<u32> {
1174        match value {
1175            Value::Bool(v) => Ok(u32::from(*v)),
1176            Value::U8(v) => Ok(u32::from(*v)),
1177            Value::U16(v) => Ok(u32::from(*v)),
1178            Value::U32(v) => Ok(*v),
1179            Value::U64(v) => Ok(ngt!(*v, u64, u32)),
1180            Value::I8(v) => Ok(nltz!(*v, i8, u32)),
1181            Value::I16(v) => Ok(nltz!(*v, i16, u32)),
1182            Value::I32(v) => Ok(nltz!(*v, i32, u32)),
1183            Value::I64(v) => Ok(ngt_nlt!(*v, i64, u32)),
1184            Value::F32(v) => Ok(nltz!(*v, f32, u32)),
1185            Value::F64(v) => Ok(ngt_nlt!(*v, f64, u32)),
1186            Value::String(v) => Ok(v.parse::<u32>()?),
1187            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
1188        }
1189    }
1190}
1191
1192impl TryFrom<Value> for i32 {
1193    type Error = Error;
1194
1195    fn try_from(value: Value) -> EResult<i32> {
1196        match value {
1197            Value::Bool(v) => Ok(i32::from(v)),
1198            Value::U8(v) => Ok(i32::from(v)),
1199            Value::U16(v) => Ok(i32::from(v)),
1200            Value::U32(v) => Ok(ngt!(v, u32, i32)),
1201            Value::U64(v) => Ok(ngt!(v, u64, i32)),
1202            Value::I8(v) => Ok(i32::from(v)),
1203            Value::I16(v) => Ok(i32::from(v)),
1204            Value::I32(v) => Ok(v),
1205            Value::I64(v) => Ok(ngt_nlt!(v, i64, i32)),
1206            #[allow(clippy::cast_possible_truncation)]
1207            Value::F32(v) => Ok(v as i32),
1208            Value::F64(v) => Ok(ngt_nlt!(v, f64, i32)),
1209            Value::String(v) => Ok(v.parse::<i32>()?),
1210            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
1211        }
1212    }
1213}
1214
1215impl TryFrom<&Value> for i32 {
1216    type Error = Error;
1217
1218    fn try_from(value: &Value) -> EResult<i32> {
1219        match value {
1220            Value::Bool(v) => Ok(i32::from(*v)),
1221            Value::U8(v) => Ok(i32::from(*v)),
1222            Value::U16(v) => Ok(i32::from(*v)),
1223            Value::U32(v) => Ok(ngt!(*v, u32, i32)),
1224            Value::U64(v) => Ok(ngt!(*v, u64, i32)),
1225            Value::I8(v) => Ok(i32::from(*v)),
1226            Value::I16(v) => Ok(i32::from(*v)),
1227            Value::I32(v) => Ok(*v),
1228            Value::I64(v) => Ok(ngt_nlt!(*v, i64, i32)),
1229            #[allow(clippy::cast_possible_truncation)]
1230            Value::F32(v) => Ok(*v as i32),
1231            Value::F64(v) => Ok(ngt_nlt!(*v, f64, i32)),
1232            Value::String(v) => Ok(v.parse::<i32>()?),
1233            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
1234        }
1235    }
1236}
1237
1238impl TryFrom<&Value> for u64 {
1239    type Error = Error;
1240
1241    fn try_from(value: &Value) -> EResult<u64> {
1242        match value {
1243            Value::Bool(v) => Ok(u64::from(*v)),
1244            Value::U8(v) => Ok(u64::from(*v)),
1245            Value::U16(v) => Ok(u64::from(*v)),
1246            Value::U32(v) => Ok(u64::from(*v)),
1247            Value::U64(v) => Ok(*v),
1248            Value::I8(v) => Ok(nltz!(*v, i8, u64)),
1249            Value::I16(v) => Ok(nltz!(*v, i16, u64)),
1250            Value::I32(v) => Ok(nltz!(*v, i32, u64)),
1251            Value::I64(v) => Ok(nltz!(*v, i64, u64)),
1252            Value::F32(v) => Ok(nltz!(*v, f32, u64)),
1253            Value::F64(v) => Ok(nltz!(*v, f64, u64)),
1254            Value::String(v) => Ok(v.parse::<u64>()?),
1255            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
1256        }
1257    }
1258}
1259
1260impl TryFrom<Value> for u64 {
1261    type Error = Error;
1262
1263    fn try_from(value: Value) -> EResult<u64> {
1264        match value {
1265            Value::Bool(v) => Ok(u64::from(v)),
1266            Value::U8(v) => Ok(u64::from(v)),
1267            Value::U16(v) => Ok(u64::from(v)),
1268            Value::U32(v) => Ok(u64::from(v)),
1269            Value::U64(v) => Ok(v),
1270            Value::I8(v) => Ok(nltz!(v, i8, u64)),
1271            Value::I16(v) => Ok(nltz!(v, i16, u64)),
1272            Value::I32(v) => Ok(nltz!(v, i32, u64)),
1273            Value::I64(v) => Ok(nltz!(v, i64, u64)),
1274            Value::F32(v) => Ok(nltz!(v, f32, u64)),
1275            Value::F64(v) => Ok(nltz!(v, f64, u64)),
1276            Value::String(v) => Ok(v.parse::<u64>()?),
1277            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
1278        }
1279    }
1280}
1281
1282impl TryFrom<&Value> for i64 {
1283    type Error = Error;
1284
1285    fn try_from(value: &Value) -> EResult<i64> {
1286        match value {
1287            Value::Bool(v) => Ok(i64::from(*v)),
1288            Value::U8(v) => Ok(i64::from(*v)),
1289            Value::U16(v) => Ok(i64::from(*v)),
1290            Value::U32(v) => Ok(i64::from(*v)),
1291            Value::U64(v) => Ok(ngt!(*v, u64, i64)),
1292            Value::I8(v) => Ok(i64::from(*v)),
1293            Value::I16(v) => Ok(i64::from(*v)),
1294            Value::I32(v) => Ok(i64::from(*v)),
1295            Value::I64(v) => Ok(*v),
1296            #[allow(clippy::cast_possible_truncation)]
1297            Value::F32(v) => Ok(*v as i64),
1298            #[allow(clippy::cast_possible_truncation)]
1299            Value::F64(v) => Ok(*v as i64),
1300            Value::String(v) => Ok(v.parse::<i64>()?),
1301            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
1302        }
1303    }
1304}
1305
1306impl TryFrom<Value> for i64 {
1307    type Error = Error;
1308
1309    fn try_from(value: Value) -> EResult<i64> {
1310        match value {
1311            Value::Bool(v) => Ok(i64::from(v)),
1312            Value::U8(v) => Ok(i64::from(v)),
1313            Value::U16(v) => Ok(i64::from(v)),
1314            Value::U32(v) => Ok(i64::from(v)),
1315            Value::U64(v) => Ok(ngt!(v, u64, i64)),
1316            Value::I8(v) => Ok(i64::from(v)),
1317            Value::I16(v) => Ok(i64::from(v)),
1318            Value::I32(v) => Ok(i64::from(v)),
1319            Value::I64(v) => Ok(v),
1320            #[allow(clippy::cast_possible_truncation)]
1321            Value::F32(v) => Ok(v as i64),
1322            #[allow(clippy::cast_possible_truncation)]
1323            Value::F64(v) => Ok(v as i64),
1324            Value::String(v) => Ok(v.parse::<i64>()?),
1325            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
1326        }
1327    }
1328}
1329
1330impl TryFrom<Value> for f32 {
1331    type Error = Error;
1332
1333    fn try_from(value: Value) -> EResult<f32> {
1334        match value {
1335            Value::Bool(v) => Ok(float_from_bool!(v)),
1336            Value::F32(v) => Ok(v),
1337            Value::F64(v) => Ok(ngt_nlt!(v, f64, f32)),
1338            Value::U8(v) => Ok(f32::from(v)),
1339            Value::U16(v) => Ok(f32::from(v)),
1340            Value::U32(v) => Ok(ngt!(v, u32, f32)),
1341            Value::U64(v) => Ok(ngt!(v, u64, f32)),
1342            Value::I8(v) => Ok(f32::from(v)),
1343            Value::I16(v) => Ok(f32::from(v)),
1344            Value::I32(v) => Ok(ngt_nlt!(v, i32, f32)),
1345            Value::I64(v) => Ok(ngt_nlt!(v, i64, f32)),
1346            Value::String(v) => Ok(v.parse::<f32>()?),
1347            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
1348        }
1349    }
1350}
1351
1352impl TryFrom<&Value> for f32 {
1353    type Error = Error;
1354
1355    fn try_from(value: &Value) -> EResult<f32> {
1356        match value {
1357            Value::Bool(v) => Ok(float_from_bool!(*v)),
1358            Value::F32(v) => Ok(*v),
1359            Value::F64(v) => Ok(ngt_nlt!(*v, f64, f32)),
1360            Value::U8(v) => Ok(f32::from(*v)),
1361            Value::U16(v) => Ok(f32::from(*v)),
1362            Value::U32(v) => Ok(ngt!(*v, u32, f32)),
1363            Value::U64(v) => Ok(ngt!(*v, u64, f32)),
1364            Value::I8(v) => Ok(f32::from(*v)),
1365            Value::I16(v) => Ok(f32::from(*v)),
1366            Value::I32(v) => Ok(ngt_nlt!(*v, i32, f32)),
1367            Value::I64(v) => Ok(ngt_nlt!(*v, i64, f32)),
1368            Value::String(v) => Ok(v.parse::<f32>()?),
1369            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
1370        }
1371    }
1372}
1373
1374impl TryFrom<&Value> for f64 {
1375    type Error = Error;
1376
1377    fn try_from(value: &Value) -> EResult<f64> {
1378        match value {
1379            Value::Bool(v) => Ok(float_from_bool!(*v)),
1380            Value::U8(v) => Ok(f64::from(*v)),
1381            Value::U16(v) => Ok(f64::from(*v)),
1382            Value::U32(v) => Ok(f64::from(*v)),
1383            Value::U64(v) => Ok(ngt!(*v, u64, f64)),
1384            Value::I8(v) => Ok(f64::from(*v)),
1385            Value::I16(v) => Ok(f64::from(*v)),
1386            Value::I32(v) => Ok(f64::from(*v)),
1387            Value::I64(v) => Ok(ngt_nlt!(*v, i64, f64)),
1388            Value::F32(v) => Ok(f64::from(*v)),
1389            Value::F64(v) => Ok(*v),
1390            Value::String(v) => Ok(v.parse::<f64>()?),
1391            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
1392        }
1393    }
1394}
1395
1396impl TryFrom<Value> for f64 {
1397    type Error = Error;
1398
1399    fn try_from(value: Value) -> EResult<f64> {
1400        match value {
1401            Value::Bool(v) => Ok(float_from_bool!(v)),
1402            Value::U8(v) => Ok(f64::from(v)),
1403            Value::U16(v) => Ok(f64::from(v)),
1404            Value::U32(v) => Ok(f64::from(v)),
1405            Value::U64(v) => Ok(ngt!(v, u64, f64)),
1406            Value::I8(v) => Ok(f64::from(v)),
1407            Value::I16(v) => Ok(f64::from(v)),
1408            Value::I32(v) => Ok(f64::from(v)),
1409            Value::I64(v) => Ok(ngt_nlt!(v, i64, f64)),
1410            Value::F32(v) => Ok(f64::from(v)),
1411            Value::F64(v) => Ok(v),
1412            Value::String(v) => Ok(v.parse::<f64>()?),
1413            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
1414        }
1415    }
1416}
1417
1418impl TryFrom<Value> for Option<std::time::Duration> {
1419    type Error = Error;
1420
1421    fn try_from(v: Value) -> EResult<Option<std::time::Duration>> {
1422        let t: f64 = v.try_into()?;
1423        if t > 0.0 {
1424            Ok(Some(std::time::Duration::from_secs_f64(t)))
1425        } else {
1426            Ok(None)
1427        }
1428    }
1429}
1430
1431impl TryFrom<Value> for String {
1432    type Error = Error;
1433
1434    fn try_from(v: Value) -> EResult<String> {
1435        match v {
1436            Value::Option(Some(s)) => Ok((*s).try_into()?),
1437            Value::String(s) => Ok(s),
1438            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
1439        }
1440    }
1441}
1442
1443impl TryFrom<&Value> for String {
1444    type Error = Error;
1445
1446    fn try_from(v: &Value) -> EResult<String> {
1447        match v {
1448            Value::Option(Some(s)) => Ok(s.as_ref().try_into()?),
1449            Value::String(s) => Ok(s.clone()),
1450            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
1451        }
1452    }
1453}
1454
1455impl<'a> TryFrom<&'a Value> for &'a str {
1456    type Error = Error;
1457
1458    fn try_from(v: &'a Value) -> EResult<&'a str> {
1459        match v {
1460            Value::Option(Some(s)) => Ok(s.as_ref().try_into()?),
1461            Value::String(s) => Ok(s),
1462            _ => Err(Error::invalid_data_static(ERR_INVALID_VALUE)),
1463        }
1464    }
1465}
1466
1467impl TryFrom<Value> for Option<String> {
1468    type Error = Error;
1469
1470    fn try_from(v: Value) -> EResult<Option<String>> {
1471        let s = match v {
1472            Value::Option(v) => match v {
1473                Some(s) => (*s).try_into()?,
1474                None => return Ok(None),
1475            },
1476            Value::Unit => return Ok(None),
1477            Value::String(s) => s,
1478            _ => {
1479                return Err(Error::invalid_data_static(ERR_INVALID_VALUE));
1480            }
1481        };
1482        Ok(if s.is_empty() { None } else { Some(s) })
1483    }
1484}
1485
1486impl TryFrom<Value> for std::time::Duration {
1487    type Error = Error;
1488
1489    fn try_from(v: Value) -> EResult<std::time::Duration> {
1490        Ok(std::time::Duration::from_secs_f64(v.try_into()?))
1491    }
1492}
1493
1494impl TryFrom<Value> for Vec<Value> {
1495    type Error = Error;
1496
1497    fn try_from(value: Value) -> EResult<Vec<Value>> {
1498        match value {
1499            Value::Seq(vec) => Ok(vec),
1500            Value::String(s) => Ok(s.split(',').map(|s| Value::String(s.to_owned())).collect()),
1501            _ => Err(Error::invalid_data_static(ERR_EXPECTED_VEC_OR_STRING)),
1502        }
1503    }
1504}
1505
1506impl<S: BuildHasher + Default> TryFrom<Value> for HashSet<Value, S> {
1507    type Error = Error;
1508
1509    fn try_from(value: Value) -> EResult<HashSet<Value, S>> {
1510        match value {
1511            Value::Seq(vec) => Ok(HashSet::from_iter(vec)),
1512            Value::String(s) => Ok(s.split(',').map(|s| Value::String(s.to_owned())).collect()),
1513            _ => Err(Error::invalid_data_static(ERR_EXPECTED_VEC_OR_STRING)),
1514        }
1515    }
1516}
1517
1518impl From<HashSet<ipnetwork::IpNetwork>> for Value {
1519    fn from(v: HashSet<ipnetwork::IpNetwork>) -> Value {
1520        to_value(v).unwrap()
1521    }
1522}
1523
1524impl<S: BuildHasher + Default> TryFrom<Value> for HashSet<ipnetwork::IpNetwork, S> {
1525    type Error = Error;
1526
1527    fn try_from(value: Value) -> EResult<HashSet<ipnetwork::IpNetwork, S>> {
1528        match value {
1529            Value::Seq(vec) => {
1530                let mut result = HashSet::default();
1531                for v in vec {
1532                    result.insert(v.deserialize_into()?);
1533                }
1534                Ok(result)
1535            }
1536            Value::String(s) => {
1537                let mut result = HashSet::default();
1538                for v in s.split(',') {
1539                    result.insert(v.parse()?);
1540                }
1541                Ok(result)
1542            }
1543            _ => Err(Error::invalid_data_static(ERR_EXPECTED_VEC_OR_STRING)),
1544        }
1545    }
1546}
1547
1548impl TryFrom<Value> for Vec<String> {
1549    type Error = Error;
1550
1551    fn try_from(value: Value) -> EResult<Vec<String>> {
1552        match value {
1553            Value::Seq(vec) => {
1554                let mut result = Vec::new();
1555                for v in vec {
1556                    result.push(v.try_into()?);
1557                }
1558                Ok(result)
1559            }
1560            Value::String(s) => Ok(s.split(',').map(ToOwned::to_owned).collect()),
1561            _ => Err(Error::invalid_data_static(ERR_EXPECTED_VEC_OR_STRING)),
1562        }
1563    }
1564}
1565
1566impl TryFrom<&Value> for Vec<String> {
1567    type Error = Error;
1568
1569    fn try_from(value: &Value) -> EResult<Vec<String>> {
1570        match value {
1571            Value::Seq(vec) => {
1572                let mut result = Vec::new();
1573                for v in vec {
1574                    result.push(v.try_into()?);
1575                }
1576                Ok(result)
1577            }
1578            Value::String(s) => Ok(s.split(',').map(ToOwned::to_owned).collect()),
1579            _ => Err(Error::invalid_data_static(ERR_EXPECTED_VEC_OR_STRING)),
1580        }
1581    }
1582}
1583
1584impl<'a> TryFrom<&'a Value> for Vec<&'a str> {
1585    type Error = Error;
1586
1587    fn try_from(value: &'a Value) -> EResult<Vec<&'a str>> {
1588        match value {
1589            Value::Seq(vec) => {
1590                let mut result = Vec::new();
1591                for v in vec {
1592                    result.push(v.try_into()?);
1593                }
1594                Ok(result)
1595            }
1596            Value::String(s) => Ok(s.split(',').collect()),
1597            _ => Err(Error::invalid_data_static(ERR_EXPECTED_VEC_OR_STRING)),
1598        }
1599    }
1600}
1601
1602impl TryFrom<Value> for bool {
1603    type Error = Error;
1604
1605    fn try_from(value: Value) -> EResult<bool> {
1606        match value {
1607            Value::Bool(v) => Ok(v),
1608            Value::String(s) => match s.to_lowercase().as_str() {
1609                "true" | "1" | "yes" => Ok(true),
1610                "false" | "0" | "no" => Ok(false),
1611                _ => Err(Error::invalid_data_static(ERR_INVALID_BOOLEAN_VALUE)),
1612            },
1613            _ => {
1614                let n: u64 = value
1615                    .try_into()
1616                    .map_err(|_| Error::invalid_data_static(ERR_INVALID_BOOLEAN_VALUE))?;
1617                if n == 0 {
1618                    Ok(false)
1619                } else if n == 1 {
1620                    Ok(true)
1621                } else {
1622                    Err(Error::invalid_data_static(ERR_INVALID_BOOLEAN_VALUE))
1623                }
1624            }
1625        }
1626    }
1627}
1628
1629impl From<&str> for Value {
1630    fn from(s: &str) -> Value {
1631        Value::String(s.to_owned())
1632    }
1633}
1634
1635impl From<&String> for Value {
1636    fn from(s: &String) -> Value {
1637        Value::String(s.clone())
1638    }
1639}
1640
1641impl From<Vec<Value>> for Value {
1642    fn from(v: Vec<Value>) -> Value {
1643        Value::Seq(v)
1644    }
1645}
1646
1647impl From<HashSet<Value>> for Value {
1648    fn from(v: HashSet<Value>) -> Value {
1649        Value::Seq(Vec::from_iter(v))
1650    }
1651}
1652
1653impl From<Vec<String>> for Value {
1654    fn from(v: Vec<String>) -> Value {
1655        Value::Seq(v.iter().map(Into::into).collect::<Vec<Value>>())
1656    }
1657}
1658
1659impl From<BTreeMap<Value, Value>> for Value {
1660    fn from(v: BTreeMap<Value, Value>) -> Value {
1661        Value::Map(v)
1662    }
1663}
1664
1665impl From<std::time::Duration> for Value {
1666    fn from(v: std::time::Duration) -> Value {
1667        v.as_secs_f64().into()
1668    }
1669}
1670
1671impl From<Option<std::time::Duration>> for Value {
1672    fn from(v: Option<std::time::Duration>) -> Value {
1673        v.map_or(Value::Unit, |d| d.as_secs_f64().into())
1674    }
1675}
1676
1677impl From<Option<f64>> for Value {
1678    fn from(v: Option<f64>) -> Value {
1679        v.map_or(Value::Unit, Value::F64)
1680    }
1681}
1682
1683impl From<Option<String>> for Value {
1684    fn from(v: Option<String>) -> Value {
1685        v.map_or(Value::Unit, Into::into)
1686    }
1687}
1688
1689impl TryFrom<Value> for serde_json::Value {
1690    type Error = Error;
1691    fn try_from(v: Value) -> EResult<Self> {
1692        serde_json::to_value(v).map_err(Into::into)
1693    }
1694}
1695
1696impl TryFrom<serde_json::Value> for Value {
1697    type Error = Error;
1698    fn try_from(v: serde_json::Value) -> EResult<Self> {
1699        serde_json::from_value(v).map_err(Into::into)
1700    }
1701}
1702
1703#[cfg(test)]
1704mod test {
1705    use crate::prelude::*;
1706    use serde::Serialize;
1707
1708    #[test]
1709    fn test_val_pack() -> EResult<()> {
1710        #[derive(Serialize)]
1711        struct My {
1712            test: bool,
1713            abc: usize,
1714        }
1715
1716        let my = My {
1717            test: true,
1718            abc: 123,
1719        };
1720        let mut valx: Value = to_value(my)?;
1721        valx = valx.unpack()?;
1722        let vlstr = valx.clone().to_string_or_pack()?;
1723        dbg!(&vlstr);
1724        let mut val = Value::String(vlstr);
1725        val = val.unpack()?;
1726        assert_eq!(val, valx);
1727        Ok(())
1728    }
1729
1730    #[test]
1731    fn test_val_parse() {
1732        let val: Value = "12345.111".parse().unwrap();
1733        assert_eq!(val, Value::F64(12345.111));
1734        let val: Value = "12345".parse().unwrap();
1735        assert_eq!(val, Value::U64(12345));
1736        let val: Value = "-12345".parse().unwrap();
1737        assert_eq!(val, Value::I64(-12345));
1738        let val: Value = "True".parse().unwrap();
1739        assert_eq!(val, Value::Bool(true));
1740        let val: Value = "False".parse().unwrap();
1741        assert_eq!(val, Value::Bool(false));
1742        let val: Value = "None".parse().unwrap();
1743        assert_eq!(val, Value::Unit);
1744        let val: Value = "Null".parse().unwrap();
1745        assert_eq!(val, Value::Unit);
1746    }
1747}