Skip to main content

acts_expr/
value.rs

1//! The value type an expression reads and produces, and the injection surface:
2//! objects are [`Map`]s, methods are [`Value::Function`]s.
3
4use crate::{Error, Result};
5use std::collections::HashMap;
6use std::fmt;
7use std::sync::Arc;
8
9/// An object: a string-keyed map of values. Usually behind an [`Arc`], so
10/// reading a member is a pointer clone.
11pub type Map = HashMap<String, Value>;
12
13/// A native method. The receiver of a method call is its first argument, so
14/// `name.upper()` and `upper(name)` are the same call.
15pub type NativeFunction = dyn Fn(&[Value]) -> Result<Value> + Send + Sync;
16
17/// One expression value.
18///
19/// Values are immutable and cheap to clone: strings, lists, maps and functions
20/// are behind an [`Arc`].
21///
22/// `PartialEq` is the expression language's `==` (see [`Value::equals`]), so a
23/// host comparing values in Rust compares them the way the workflow does.
24#[derive(Clone, Default)]
25pub enum Value {
26    #[default]
27    Null,
28    Bool(bool),
29    /// A 64-bit integer: what an integer literal is, and what `+`, `-`, `*`,
30    /// `/` and `%` stay in while both operands are ints.
31    Int(i64),
32    /// An integer above `i64::MAX` — what JSON gives a host for one, since a
33    /// JSON integer is an `i64` or a `u64` and nothing else represents
34    /// `u64::MAX` exactly. A value this wide is never produced from a literal
35    /// and only ever shows up injected; arithmetic that mixes it with an `int`
36    /// is exact.
37    UInt(u64),
38    /// A 64-bit float. Mixed int/float arithmetic produces a float.
39    Float(f64),
40    Str(Arc<str>),
41    List(Arc<[Value]>),
42    /// An injected object. `a.b` reads a member, `a['b']` the same key.
43    Map(Arc<Map>),
44    /// An injected method. `f(x)` calls it directly, `a.f(x)` calls it with
45    /// `a` as its first argument, and a function stored *in* a map is called
46    /// the same way when reached through that map.
47    Function(Arc<NativeFunction>),
48}
49
50impl Value {
51    /// Wrap a closure as an injectable method.
52    ///
53    /// ```rust
54    /// use acts_expr::Value;
55    ///
56    /// let upper = Value::function(|args| match args {
57    ///     [Value::Str(s)] => Ok(Value::from(s.to_uppercase())),
58    ///     _ => Err(acts_expr::Error::Type { operation: "upper", got: "other" }),
59    /// });
60    /// ```
61    pub fn function<F>(f: F) -> Value
62    where
63        F: Fn(&[Value]) -> Result<Value> + Send + Sync + 'static,
64    {
65        Value::Function(Arc::new(f))
66    }
67
68    /// Build an object from key/value pairs.
69    ///
70    /// ```rust
71    /// use acts_expr::Value;
72    ///
73    /// let step = Value::map([("id", Value::from("step1")), ("retries", Value::from(2))]);
74    /// ```
75    pub fn map<K, V, I>(entries: I) -> Value
76    where
77        K: Into<String>,
78        V: Into<Value>,
79        I: IntoIterator<Item = (K, V)>,
80    {
81        Value::Map(Arc::new(
82            entries
83                .into_iter()
84                .map(|(k, v)| (k.into(), v.into()))
85                .collect(),
86        ))
87    }
88
89    /// Build a list.
90    pub fn list<I, V>(items: I) -> Value
91    where
92        I: IntoIterator<Item = V>,
93        V: Into<Value>,
94    {
95        Value::List(items.into_iter().map(Into::into).collect())
96    }
97
98    /// The type name the errors and `Display` use.
99    pub fn type_name(&self) -> &'static str {
100        match self {
101            Value::Null => "null",
102            Value::Bool(_) => "bool",
103            Value::Int(_) => "int",
104            Value::UInt(_) => "uint",
105            Value::Float(_) => "float",
106            Value::Str(_) => "string",
107            Value::List(_) => "list",
108            Value::Map(_) => "map",
109            Value::Function(_) => "function",
110        }
111    }
112
113    pub fn is_null(&self) -> bool {
114        matches!(self, Value::Null)
115    }
116
117    /// Whether the value is an `int`, a `uint` or a `float`.
118    pub fn is_number(&self) -> bool {
119        matches!(self, Value::Int(_) | Value::UInt(_) | Value::Float(_))
120    }
121
122    pub fn as_bool(&self) -> Option<bool> {
123        match self {
124            Value::Bool(b) => Some(*b),
125            _ => None,
126        }
127    }
128
129    pub fn as_int(&self) -> Option<i64> {
130        match self {
131            Value::Int(i) => Some(*i),
132            _ => None,
133        }
134    }
135
136    /// The value as a `u64`, for an `int` that is not negative too.
137    pub fn as_u64(&self) -> Option<u64> {
138        match self {
139            Value::Int(i) => u64::try_from(*i).ok(),
140            Value::UInt(u) => Some(*u),
141            _ => None,
142        }
143    }
144
145    /// The value as a 128-bit integer: exact for both integer kinds, which is
146    /// what lets `int` and `uint` mix without a rounding step.
147    pub fn as_i128(&self) -> Option<i128> {
148        match self {
149            Value::Int(i) => Some(i128::from(*i)),
150            Value::UInt(u) => Some(i128::from(*u)),
151            _ => None,
152        }
153    }
154
155    pub fn as_float(&self) -> Option<f64> {
156        match self {
157            Value::Float(f) => Some(*f),
158            _ => None,
159        }
160    }
161
162    /// The number as an `f64`, whatever kind of number it is.
163    pub fn as_number(&self) -> Option<f64> {
164        match self {
165            Value::Int(i) => Some(*i as f64),
166            Value::UInt(u) => Some(*u as f64),
167            Value::Float(f) => Some(*f),
168            _ => None,
169        }
170    }
171
172    pub fn as_str(&self) -> Option<&str> {
173        match self {
174            Value::Str(s) => Some(s),
175            _ => None,
176        }
177    }
178
179    pub fn as_list(&self) -> Option<&[Value]> {
180        match self {
181            Value::List(items) => Some(items),
182            _ => None,
183        }
184    }
185
186    pub fn as_map(&self) -> Option<&Map> {
187        match self {
188            Value::Map(map) => Some(map),
189            _ => None,
190        }
191    }
192
193    pub fn is_function(&self) -> bool {
194        matches!(self, Value::Function(_))
195    }
196
197    /// Value equality, as `==` defines it: numbers compare across `int` and
198    /// `float`, `null` is only equal to `null`, lists and maps compare
199    /// element-wise, and values of different kinds are simply not equal.
200    pub fn equals(&self, other: &Value) -> bool {
201        match (self, other) {
202            (Value::Null, Value::Null) => true,
203            (Value::Bool(a), Value::Bool(b)) => a == b,
204            (Value::Str(a), Value::Str(b)) => a == b,
205            (Value::Int(a), Value::Int(b)) => a == b,
206            (Value::UInt(a), Value::UInt(b)) => a == b,
207            (Value::Float(a), Value::Float(b)) => a == b,
208            // Exact across the integer kinds, in the one width both fit.
209            (Value::Int(a), Value::UInt(b)) | (Value::UInt(b), Value::Int(a)) => {
210                i128::from(*a) == i128::from(*b)
211            }
212            (Value::Int(a), Value::Float(b)) | (Value::Float(b), Value::Int(a)) => {
213                (*a as f64) == *b
214            }
215            (Value::UInt(a), Value::Float(b)) | (Value::Float(b), Value::UInt(a)) => {
216                (*a as f64) == *b
217            }
218            // Immutable and usually shared, so the pointer check answers the
219            // common case (a value compared with itself) without walking.
220            (Value::List(a), Value::List(b)) => {
221                std::ptr::addr_eq(Arc::as_ptr(a), Arc::as_ptr(b))
222                    || (a.len() == b.len() && a.iter().zip(b.iter()).all(|(x, y)| x.equals(y)))
223            }
224            (Value::Map(a), Value::Map(b)) => {
225                std::ptr::addr_eq(Arc::as_ptr(a), Arc::as_ptr(b))
226                    || (a.len() == b.len()
227                        && a.iter()
228                            .all(|(k, v)| b.get(k).is_some_and(|other| v.equals(other))))
229            }
230            (Value::Function(a), Value::Function(b)) => Arc::ptr_eq(a, b),
231            _ => false,
232        }
233    }
234
235    /// Ordering for `<`, `<=`, `>` and `>=`: numbers across `int` and `float`,
236    /// and strings by their bytes. `None` for every other pair, which the
237    /// evaluator reports as a type error.
238    pub fn compare(&self, other: &Value) -> Option<std::cmp::Ordering> {
239        match (self, other) {
240            (Value::Int(a), Value::Int(b)) => Some(a.cmp(b)),
241            (Value::UInt(a), Value::UInt(b)) => Some(a.cmp(b)),
242            (Value::Int(a), Value::UInt(b)) => i128::from(*a).partial_cmp(&i128::from(*b)),
243            (Value::UInt(a), Value::Int(b)) => i128::from(*a).partial_cmp(&i128::from(*b)),
244            (Value::Str(a), Value::Str(b)) => Some(a.as_ref().cmp(b.as_ref())),
245            (Value::Int(a), Value::Float(b)) => (*a as f64).partial_cmp(b),
246            (Value::UInt(a), Value::Float(b)) => (*a as f64).partial_cmp(b),
247            (Value::Float(a), Value::Int(b)) => a.partial_cmp(&(*b as f64)),
248            (Value::Float(a), Value::UInt(b)) => a.partial_cmp(&(*b as f64)),
249            (Value::Float(a), Value::Float(b)) => a.partial_cmp(b),
250            _ => None,
251        }
252    }
253
254    /// A JSON value for this value. Functions have no JSON form and are an
255    /// error; a non-finite float is too.
256    #[cfg(feature = "json")]
257    pub fn to_json(&self) -> Result<serde_json::Value> {
258        use serde_json::Value as Json;
259
260        Ok(match self {
261            Value::Null => Json::Null,
262            Value::Bool(b) => Json::Bool(*b),
263            Value::Int(i) => Json::from(*i),
264            Value::UInt(u) => Json::from(*u),
265            Value::Float(f) => serde_json::Number::from_f64(*f)
266                .map(Json::Number)
267                .ok_or_else(|| Error::Convert {
268                    message: format!("{f} has no JSON representation"),
269                })?,
270            Value::Str(s) => Json::String(s.to_string()),
271            Value::List(items) => {
272                Json::Array(items.iter().map(Value::to_json).collect::<Result<_>>()?)
273            }
274            Value::Map(map) => Json::Object(
275                map.iter()
276                    .map(|(k, v)| Ok((k.clone(), v.to_json()?)))
277                    .collect::<Result<_>>()?,
278            ),
279            Value::Function(_) => {
280                return Err(Error::Convert {
281                    message: "a function has no JSON representation".to_string(),
282                });
283            }
284        })
285    }
286}
287
288impl fmt::Debug for Value {
289    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
290        match self {
291            Value::Null => f.write_str("null"),
292            Value::Bool(b) => write!(f, "{b}"),
293            Value::Int(i) => write!(f, "{i}"),
294            Value::UInt(u) => write!(f, "{u}"),
295            Value::Float(v) => write!(f, "{v}"),
296            Value::Str(s) => write!(f, "{s:?}"),
297            Value::List(items) => f.debug_list().entries(items.iter()).finish(),
298            Value::Map(map) => f.debug_map().entries(map.iter()).finish(),
299            Value::Function(_) => f.write_str("<function>"),
300        }
301    }
302}
303
304impl PartialEq for Value {
305    fn eq(&self, other: &Value) -> bool {
306        self.equals(other)
307    }
308}
309
310impl fmt::Display for Value {
311    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
312        match self {
313            Value::Null => write!(f, "null"),
314            Value::Bool(b) => write!(f, "{b}"),
315            Value::Int(i) => write!(f, "{i}"),
316            Value::UInt(u) => write!(f, "{u}"),
317            Value::Float(v) => write!(f, "{v}"),
318            Value::Str(s) => write!(f, "{s}"),
319            Value::List(items) => {
320                write!(f, "[")?;
321                for (i, item) in items.iter().enumerate() {
322                    if i > 0 {
323                        write!(f, ", ")?;
324                    }
325                    write!(f, "{item}")?;
326                }
327                write!(f, "]")
328            }
329            Value::Map(map) => {
330                write!(f, "{{")?;
331                for (i, (k, v)) in map.iter().enumerate() {
332                    if i > 0 {
333                        write!(f, ", ")?;
334                    }
335                    write!(f, "{k}: {v}")?;
336                }
337                write!(f, "}}")
338            }
339            Value::Function(_) => write!(f, "<function>"),
340        }
341    }
342}
343
344impl From<()> for Value {
345    fn from(_: ()) -> Self {
346        Value::Null
347    }
348}
349
350impl From<bool> for Value {
351    fn from(value: bool) -> Self {
352        Value::Bool(value)
353    }
354}
355
356impl From<i32> for Value {
357    fn from(value: i32) -> Self {
358        Value::Int(value as i64)
359    }
360}
361
362impl From<i64> for Value {
363    fn from(value: i64) -> Self {
364        Value::Int(value)
365    }
366}
367
368impl From<u32> for Value {
369    fn from(value: u32) -> Self {
370        Value::Int(i64::from(value))
371    }
372}
373
374impl From<u64> for Value {
375    /// A `u64` that fits an `i64` becomes one, so a `uint` only ever holds a
376    /// value that needs the wider type.
377    fn from(value: u64) -> Self {
378        match i64::try_from(value) {
379            Ok(value) => Value::Int(value),
380            Err(_) => Value::UInt(value),
381        }
382    }
383}
384
385impl From<usize> for Value {
386    fn from(value: usize) -> Self {
387        Value::from(value as u64)
388    }
389}
390
391impl From<f64> for Value {
392    fn from(value: f64) -> Self {
393        Value::Float(value)
394    }
395}
396
397impl From<&str> for Value {
398    fn from(value: &str) -> Self {
399        Value::Str(Arc::from(value))
400    }
401}
402
403impl From<String> for Value {
404    fn from(value: String) -> Self {
405        Value::Str(Arc::from(value))
406    }
407}
408
409impl From<Arc<str>> for Value {
410    fn from(value: Arc<str>) -> Self {
411        Value::Str(value)
412    }
413}
414
415impl From<Vec<Value>> for Value {
416    fn from(value: Vec<Value>) -> Self {
417        Value::List(value.into())
418    }
419}
420
421impl From<Map> for Value {
422    fn from(value: Map) -> Self {
423        Value::Map(Arc::new(value))
424    }
425}
426
427impl<T: Into<Value>> From<Option<T>> for Value {
428    fn from(value: Option<T>) -> Self {
429        value.map_or(Value::Null, Into::into)
430    }
431}
432
433#[cfg(feature = "json")]
434impl From<serde_json::Value> for Value {
435    fn from(value: serde_json::Value) -> Self {
436        use serde_json::Value as Json;
437
438        match value {
439            Json::Null => Value::Null,
440            Json::Bool(b) => Value::Bool(b),
441            // The same ladder `serde_json` reads its own numbers with: an
442            // `i64`, then a `u64`, and a float only past both.
443            Json::Number(n) => match (n.as_i64(), n.as_u64()) {
444                (Some(i), _) => Value::Int(i),
445                (None, Some(u)) => Value::UInt(u),
446                (None, None) => Value::Float(n.as_f64().unwrap_or(f64::NAN)),
447            },
448            Json::String(s) => Value::Str(Arc::from(s)),
449            Json::Array(items) => Value::List(items.into_iter().map(Value::from).collect()),
450            Json::Object(map) => Value::Map(Arc::new(
451                map.into_iter().map(|(k, v)| (k, Value::from(v))).collect(),
452            )),
453        }
454    }
455}
456
457#[cfg(test)]
458mod tests {
459    use super::*;
460    use std::collections::HashMap;
461
462    #[test]
463    fn constructors_build_the_kinds() {
464        assert_eq!(Value::from(1), Value::Int(1));
465        assert_eq!(Value::from(1.5), Value::Float(1.5));
466        assert_eq!(Value::from(true), Value::Bool(true));
467        assert_eq!(Value::from("text"), Value::from("text"));
468        assert_eq!(Value::from("text"), Value::Str(Arc::from("text")));
469        assert_eq!(
470            Value::from(vec![Value::from(1)]),
471            Value::List(Arc::from(vec![Value::from(1)]))
472        );
473        assert_eq!(
474            Value::map([("k", 1)]),
475            Value::Map(Arc::new(HashMap::from([("k".to_string(), Value::Int(1))])))
476        );
477        assert_eq!(
478            Value::list([1, 2]),
479            Value::List(Arc::from(vec![Value::Int(1), Value::Int(2)]))
480        );
481        assert!(Value::default().is_null());
482    }
483
484    #[test]
485    fn from_conversions_cover_each_width() {
486        assert_eq!(Value::from(()), Value::Null);
487        assert_eq!(Value::from(false), Value::Bool(false));
488        assert_eq!(Value::from(1i32), Value::Int(1));
489        assert_eq!(Value::from(-1i64), Value::Int(-1));
490        assert_eq!(Value::from(1u32), Value::Int(1));
491        assert_eq!(Value::from(1u64), Value::Int(1));
492        assert_eq!(Value::from(u64::MAX), Value::UInt(u64::MAX));
493        assert_eq!(Value::from(7usize), Value::Int(7));
494        assert_eq!(Value::from(usize::MAX), Value::from(usize::MAX as u64));
495        assert_eq!(Value::from(2.5f64), Value::Float(2.5));
496        assert_eq!(Value::from(String::from("s")), Value::Str(Arc::from("s")));
497        assert_eq!(
498            Value::from(Arc::<str>::from("s")),
499            Value::Str(Arc::from("s"))
500        );
501        assert_eq!(Value::from(Some(3)), Value::Int(3));
502        assert_eq!(Value::from(None::<i32>), Value::Null);
503
504        let map: Map = HashMap::from([("k".to_string(), Value::Int(1))]);
505        assert_eq!(Value::from(map), Value::map([("k", 1)]));
506    }
507
508    #[test]
509    fn type_names_and_kind_predicates() {
510        let cases = [
511            (Value::Null, "null"),
512            (Value::Bool(true), "bool"),
513            (Value::Int(1), "int"),
514            (Value::UInt(1), "uint"),
515            (Value::Float(1.0), "float"),
516            (Value::from("s"), "string"),
517            (Value::list([1]), "list"),
518            (Value::map([("k", 1)]), "map"),
519            (Value::function(|_| Ok(Value::Null)), "function"),
520        ];
521
522        for (value, name) in cases {
523            assert_eq!(value.type_name(), name);
524            assert_eq!(value.is_null(), name == "null");
525            assert_eq!(value.is_number(), matches!(name, "int" | "uint" | "float"));
526            assert_eq!(value.is_function(), name == "function");
527        }
528    }
529
530    #[test]
531    fn accessors_answer_only_for_their_kind() {
532        assert_eq!(Value::Bool(true).as_bool(), Some(true));
533        assert_eq!(Value::Int(1).as_bool(), None);
534
535        assert_eq!(Value::Int(-2).as_int(), Some(-2));
536        assert_eq!(Value::UInt(2).as_int(), None);
537
538        assert_eq!(Value::Int(2).as_u64(), Some(2));
539        assert_eq!(Value::Int(-2).as_u64(), None);
540        assert_eq!(Value::UInt(u64::MAX).as_u64(), Some(u64::MAX));
541        assert_eq!(Value::Float(1.0).as_u64(), None);
542
543        assert_eq!(Value::Int(-2).as_i128(), Some(-2));
544        assert_eq!(Value::UInt(u64::MAX).as_i128(), Some(i128::from(u64::MAX)));
545        assert_eq!(Value::Bool(true).as_i128(), None);
546
547        assert_eq!(Value::Float(1.5).as_float(), Some(1.5));
548        assert_eq!(Value::Int(1).as_float(), None);
549
550        assert_eq!(Value::Int(1).as_number(), Some(1.0));
551        assert_eq!(Value::UInt(2).as_number(), Some(2.0));
552        assert_eq!(Value::Float(3.5).as_number(), Some(3.5));
553        assert_eq!(Value::from("1").as_number(), None);
554
555        assert_eq!(Value::from("s").as_str(), Some("s"));
556        assert_eq!(Value::Int(1).as_str(), None);
557
558        assert_eq!(
559            Value::list([1, 2]).as_list(),
560            Some(&[Value::Int(1), Value::Int(2)][..])
561        );
562        assert_eq!(Value::Int(1).as_list(), None);
563
564        assert_eq!(Value::map([("k", 1)]).as_map().unwrap().len(), 1);
565        assert_eq!(Value::Int(1).as_map(), None);
566    }
567
568    #[test]
569    fn equality_follows_the_expression_language() {
570        assert!(Value::Null.equals(&Value::Null));
571        assert!(!Value::Null.equals(&Value::Int(0)));
572        assert!(Value::Bool(true).equals(&Value::Bool(true)));
573        assert!(!Value::Bool(true).equals(&Value::Bool(false)));
574        assert!(Value::from("a").equals(&Value::from("a")));
575        assert!(!Value::from("a").equals(&Value::from("b")));
576
577        assert!(Value::Int(1).equals(&Value::Int(1)));
578        assert!(Value::UInt(1).equals(&Value::UInt(1)));
579        assert!(Value::Float(1.5).equals(&Value::Float(1.5)));
580        assert!(Value::Int(1).equals(&Value::UInt(1)));
581        assert!(Value::UInt(1).equals(&Value::Int(1)));
582        assert!(Value::Int(1).equals(&Value::Float(1.0)));
583        assert!(Value::Float(1.0).equals(&Value::Int(1)));
584        assert!(Value::UInt(1).equals(&Value::Float(1.0)));
585        assert!(Value::Float(1.0).equals(&Value::UInt(1)));
586        assert!(!Value::Int(1).equals(&Value::UInt(2)));
587
588        // A shared list or map answers by pointer, a rebuilt one by content.
589        let list = Value::list([1, 2]);
590        assert!(list.equals(&list));
591        assert!(list.equals(&Value::list([1, 2])));
592        assert!(!list.equals(&Value::list([1, 2, 3])));
593        assert!(!list.equals(&Value::list([1, 3])));
594
595        let map = Value::map([("a", 1), ("b", 2)]);
596        assert!(map.equals(&map));
597        assert!(map.equals(&Value::map([("a", 1), ("b", 2)])));
598        assert!(!map.equals(&Value::map([("a", 1)])));
599        assert!(!map.equals(&Value::map([("a", 1), ("b", 3)])));
600
601        let function = Value::function(|_| Ok(Value::Null));
602        assert!(function.equals(&function));
603        assert!(!function.equals(&Value::function(|_| Ok(Value::Null))));
604        assert!(!function.equals(&Value::Null));
605
606        assert_eq!(Value::Int(1), Value::Float(1.0));
607        assert_ne!(Value::Int(1), Value::UInt(2));
608    }
609
610    #[test]
611    fn ordering_covers_both_number_kinds_and_strings() {
612        use std::cmp::Ordering::{Equal, Greater, Less};
613
614        assert_eq!(Value::Int(1).compare(&Value::Int(2)), Some(Less));
615        assert_eq!(Value::UInt(2).compare(&Value::UInt(2)), Some(Equal));
616        assert_eq!(Value::Int(-1).compare(&Value::UInt(1)), Some(Less));
617        assert_eq!(
618            Value::UInt(u64::MAX).compare(&Value::Int(-1)),
619            Some(Greater)
620        );
621        assert_eq!(Value::from("a").compare(&Value::from("b")), Some(Less));
622        assert_eq!(Value::Int(1).compare(&Value::Float(1.5)), Some(Less));
623        assert_eq!(Value::UInt(2).compare(&Value::Float(1.5)), Some(Greater));
624        assert_eq!(Value::Float(1.5).compare(&Value::Int(1)), Some(Greater));
625        assert_eq!(Value::Float(1.5).compare(&Value::UInt(2)), Some(Less));
626        assert_eq!(Value::Float(1.0).compare(&Value::Float(2.0)), Some(Less));
627        assert_eq!(Value::Bool(true).compare(&Value::Bool(true)), None);
628        assert_eq!(Value::Null.compare(&Value::Null), None);
629    }
630
631    #[test]
632    fn display_and_debug_render_each_kind() {
633        assert_eq!(Value::Null.to_string(), "null");
634        assert_eq!(Value::Bool(true).to_string(), "true");
635        assert_eq!(Value::Int(-1).to_string(), "-1");
636        assert_eq!(Value::UInt(u64::MAX).to_string(), u64::MAX.to_string());
637        assert_eq!(Value::Float(1.5).to_string(), "1.5");
638        assert_eq!(Value::from("a\nb").to_string(), "a\nb");
639        assert_eq!(
640            Value::list([Value::from(1), Value::from("x")]).to_string(),
641            "[1, x]"
642        );
643        assert_eq!(Value::map([("k", 1)]).to_string(), "{k: 1}");
644        assert_eq!(
645            Value::function(|_| Ok(Value::Null)).to_string(),
646            "<function>"
647        );
648
649        assert_eq!(format!("{:?}", Value::Null), "null");
650        assert_eq!(format!("{:?}", Value::Bool(false)), "false");
651        assert_eq!(format!("{:?}", Value::Int(2)), "2");
652        assert_eq!(format!("{:?}", Value::UInt(2)), "2");
653        assert_eq!(format!("{:?}", Value::Float(1.5)), "1.5");
654        assert_eq!(format!("{:?}", Value::from("a\nb")), "\"a\\nb\"");
655        assert_eq!(format!("{:?}", Value::list([1, 2])), "[1, 2]");
656        assert_eq!(format!("{:?}", Value::map([("k", 1)])), "{\"k\": 1}");
657        assert_eq!(
658            format!("{:?}", Value::function(|_| Ok(Value::Null))),
659            "<function>"
660        );
661
662        assert_eq!(
663            format!("{}", Value::list(std::iter::empty::<Value>())),
664            "[]"
665        );
666        assert_eq!(format!("{}", Value::map(Map::new())), "{}");
667    }
668
669    #[cfg(feature = "json")]
670    #[test]
671    fn json_conversion_covers_every_kind() {
672        use serde_json::json;
673
674        assert_eq!(Value::from(json!(null)), Value::Null);
675        assert_eq!(Value::from(json!(true)), Value::Bool(true));
676        assert_eq!(Value::from(json!(-3)), Value::Int(-3));
677        assert_eq!(Value::from(json!(u64::MAX)), Value::UInt(u64::MAX));
678        assert_eq!(Value::from(json!(1.5)), Value::Float(1.5));
679        assert_eq!(Value::from(json!("s")), Value::from("s"));
680        assert_eq!(
681            Value::from(json!([1, "two"])),
682            Value::list([Value::from(1), Value::from("two")])
683        );
684        assert_eq!(Value::from(json!({"k": false})), Value::map([("k", false)]));
685
686        assert_eq!(Value::Null.to_json().unwrap(), json!(null));
687        assert_eq!(Value::Bool(true).to_json().unwrap(), json!(true));
688        assert_eq!(Value::Int(1).to_json().unwrap(), json!(1));
689        assert_eq!(Value::UInt(u64::MAX).to_json().unwrap(), json!(u64::MAX));
690        assert_eq!(Value::Float(1.5).to_json().unwrap(), json!(1.5));
691        assert_eq!(Value::from("s").to_json().unwrap(), json!("s"));
692        assert_eq!(
693            Value::list([Value::from(1), Value::from("two")])
694                .to_json()
695                .unwrap(),
696            json!([1, "two"])
697        );
698        assert_eq!(
699            Value::map([("k", false)]).to_json().unwrap(),
700            json!({"k": false})
701        );
702    }
703
704    #[cfg(feature = "json")]
705    #[test]
706    fn json_rejects_functions_and_non_finite_floats() {
707        let function = Value::function(|_| Ok(Value::Null));
708        assert_eq!(
709            function.to_json().unwrap_err(),
710            Error::Convert {
711                message: "a function has no JSON representation".to_string()
712            }
713        );
714        assert_eq!(
715            Value::from(f64::NAN).to_json().unwrap_err(),
716            Error::Convert {
717                message: "NaN has no JSON representation".to_string()
718            }
719        );
720        assert_eq!(
721            Value::from(f64::INFINITY).to_json().unwrap_err(),
722            Error::Convert {
723                message: "inf has no JSON representation".to_string()
724            }
725        );
726
727        // A nested function fails the enclosing list or map too.
728        assert!(
729            Value::list([Value::from(1), function.clone()])
730                .to_json()
731                .is_err()
732        );
733        assert!(Value::map([("f", function)]).to_json().is_err());
734    }
735}