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