Skip to main content

edn/
types.rs

1// Copyright 2016 Mozilla
2//
3// Licensed under the Apache License, Version 2.0 (the "License"); you may not use
4// this file except in compliance with the License. You may obtain a copy of the
5// License at http://www.apache.org/licenses/LICENSE-2.0
6// Unless required by applicable law or agreed to in writing, software distributed
7// under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR
8// CONDITIONS OF ANY KIND, either express or implied. See the License for the
9// specific language governing permissions and limitations under the License.
10
11#![allow(clippy::linkedlist)]
12
13use std::cmp::{Ord, Ordering, PartialOrd};
14use std::collections::{BTreeMap, BTreeSet, LinkedList};
15use std::f64;
16use std::fmt::{Display, Formatter};
17
18use chrono::{DateTime, SecondsFormat, Utc};
19use num::BigInt;
20use ordered_float::OrderedFloat;
21use uuid::Uuid;
22
23use crate::symbols;
24
25/// Value represents one of the allowed values in an EDN string.
26#[derive(PartialEq, Eq, Hash, Clone, Debug)]
27pub enum Value {
28    Nil,
29    Boolean(bool),
30    Integer(i64),
31    Instant(DateTime<Utc>),
32    BigInteger(BigInt),
33    Float(OrderedFloat<f64>),
34    Text(String),
35    Uuid(Uuid),
36    PlainSymbol(symbols::PlainSymbol),
37    NamespacedSymbol(symbols::NamespacedSymbol),
38    Keyword(symbols::Keyword),
39    Vector(Vec<Value>),
40    // We're using a LinkedList here instead of a Vec or VecDeque because the
41    // LinkedList is faster for appending (which we do a lot of).
42    // See https://github.com/mozilla/mentat/issues/231
43    List(LinkedList<Value>),
44    // We're using BTree{Set, Map} rather than Hash{Set, Map} because the BTree variants
45    // implement Hash. The Hash variants don't in order to preserve O(n) hashing
46    // time, which is hard given recursive data structures.
47    // See https://internals.rust-lang.org/t/implementing-hash-for-hashset-hashmap/3817/1
48    Set(BTreeSet<Value>),
49    Map(BTreeMap<Value, Value>),
50}
51
52/// `SpannedValue` is the parallel to `Value` but used in `ValueAndSpan`.
53/// Container types have `ValueAndSpan` children.
54#[derive(PartialEq, Eq, Hash, Clone, Debug)]
55pub enum SpannedValue {
56    Nil,
57    Boolean(bool),
58    Integer(i64),
59    Instant(DateTime<Utc>),
60    BigInteger(BigInt),
61    Float(OrderedFloat<f64>),
62    Text(String),
63    Uuid(Uuid),
64    PlainSymbol(symbols::PlainSymbol),
65    NamespacedSymbol(symbols::NamespacedSymbol),
66    Keyword(symbols::Keyword),
67    Vector(Vec<ValueAndSpan>),
68    List(LinkedList<ValueAndSpan>),
69    Set(BTreeSet<ValueAndSpan>),
70    Map(BTreeMap<ValueAndSpan, ValueAndSpan>),
71}
72
73/// Span represents the current offset (start, end) into the input string.
74#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
75pub struct Span(pub u32, pub u32);
76
77impl Span {
78    pub fn new(start: usize, end: usize) -> Span {
79        Span(start as u32, end as u32)
80    }
81}
82
83/// A wrapper type around `SpannedValue` and `Span`, representing some EDN value
84/// and the parsing offset (start, end) in the original EDN string.
85#[derive(PartialEq, Eq, Hash, Clone, Debug)]
86pub struct ValueAndSpan {
87    pub inner: SpannedValue,
88    pub span: Span,
89}
90
91impl ValueAndSpan {
92    pub fn new<I>(spanned_value: SpannedValue, span: I) -> ValueAndSpan
93    where
94        I: Into<Option<Span>>,
95    {
96        ValueAndSpan {
97            inner: spanned_value,
98            span: span.into().unwrap_or(Span(0, 0)), // TODO: consider if this has implications.
99        }
100    }
101
102    pub fn into_atom(self) -> Option<ValueAndSpan> {
103        if self.inner.is_atom() {
104            Some(self)
105        } else {
106            None
107        }
108    }
109
110    pub fn is_atom(&self) -> bool {
111        self.inner.is_atom()
112    }
113
114    pub fn as_atom(&self) -> Option<&ValueAndSpan> {
115        if self.inner.is_atom() {
116            Some(self)
117        } else {
118            None
119        }
120    }
121
122    pub fn into_text(self) -> Option<String> {
123        self.inner.into_text()
124    }
125
126    pub fn as_text(&self) -> Option<&String> {
127        self.inner.as_text()
128    }
129}
130
131impl Value {
132    /// For debug use only!
133    ///
134    /// But right now, it's used in the bootstrapper.  We'll fix that soon.
135    pub fn with_spans(self) -> ValueAndSpan {
136        let s = self.to_pretty(120).unwrap();
137        use crate::parse;
138        let with_spans = parse::value(&s).unwrap();
139        assert_eq!(self, with_spans.clone().without_spans());
140        with_spans
141    }
142}
143
144impl From<SpannedValue> for Value {
145    fn from(src: SpannedValue) -> Value {
146        match src {
147            SpannedValue::Nil => Value::Nil,
148            SpannedValue::Boolean(v) => Value::Boolean(v),
149            SpannedValue::Integer(v) => Value::Integer(v),
150            SpannedValue::Instant(v) => Value::Instant(v),
151            SpannedValue::BigInteger(v) => Value::BigInteger(v),
152            SpannedValue::Float(v) => Value::Float(v),
153            SpannedValue::Text(v) => Value::Text(v),
154            SpannedValue::Uuid(v) => Value::Uuid(v),
155            SpannedValue::PlainSymbol(v) => Value::PlainSymbol(v),
156            SpannedValue::NamespacedSymbol(v) => Value::NamespacedSymbol(v),
157            SpannedValue::Keyword(v) => Value::Keyword(v),
158            SpannedValue::Vector(v) => {
159                Value::Vector(v.into_iter().map(|x| x.without_spans()).collect())
160            }
161            SpannedValue::List(v) => {
162                Value::List(v.into_iter().map(|x| x.without_spans()).collect())
163            }
164            SpannedValue::Set(v) => Value::Set(v.into_iter().map(|x| x.without_spans()).collect()),
165            SpannedValue::Map(v) => Value::Map(
166                v.into_iter()
167                    .map(|(x, y)| (x.without_spans(), y.without_spans()))
168                    .collect(),
169            ),
170        }
171    }
172}
173
174impl From<ValueAndSpan> for Value {
175    fn from(src: ValueAndSpan) -> Value {
176        src.inner.into()
177    }
178}
179
180/// Creates `from_$TYPE` helper functions for Value and SpannedValue,
181/// like `from_float()` or `from_ordered_float()`.
182macro_rules! def_from {
183    ($name: ident, $out: ty, $kind: path, $t: ty, $( $transform: expr ),* ) => {
184        pub fn $name(src: $t) -> $out {
185            $( let src = $transform(src); )*
186            $kind(src)
187        }
188    }
189}
190
191/// Creates `from_$TYPE` helper functions for Value or SpannedValue,
192/// like `from_bigint()` where the conversion is optional.
193macro_rules! def_from_option {
194    ($name: ident, $out: ty, $kind: path, $t: ty, $( $transform: expr ),* ) => {
195        pub fn $name(src: $t) -> Option<$out> {
196            $( let src = $transform(src); )*
197            src.map($kind)
198        }
199    }
200}
201
202/// Creates `is_$TYPE` helper functions for Value or SpannedValue, like
203/// `is_big_integer()` or `is_text()`.
204macro_rules! def_is {
205    ($name: ident, $pat: pat) => {
206        pub fn $name(&self) -> bool {
207            match *self {
208                $pat => true,
209                _ => false,
210            }
211        }
212    };
213}
214
215/// Creates `as_$TYPE` helper functions for Value or SpannedValue, like
216/// `as_integer()`, which returns the underlying value representing the
217/// original variable wrapped in an Option, like `Option<i64>`.
218macro_rules! def_as {
219    ($name: ident, $kind: path, $t: ty, $( $transform: expr ),* ) => {
220        pub fn $name(&self) -> Option<$t> {
221            match *self { $kind(v) => { $( let v = $transform(v); )* Some(v) }, _ => None }
222        }
223    }
224}
225
226/// Creates `as_$TYPE` helper functions for Value or SpannedValue, like
227/// `as_big_integer()`, which returns a reference to the underlying value
228/// representing the original variable wrapped in an Option, like `Option<&BigInt>`.
229macro_rules! def_as_ref {
230    ($name: ident, $kind: path, $t: ty) => {
231        pub fn $name(&self) -> Option<&$t> {
232            match *self {
233                $kind(ref v) => Some(v),
234                _ => None,
235            }
236        }
237    };
238}
239
240/// Creates `into_$TYPE` helper functions for Value or SpannedValue, like
241/// `into_big_integer()`, which consumes it returning underlying value
242/// representing the original variable wrapped in an Option, like `Option<BigInt>`.
243macro_rules! def_into {
244    ($name: ident, $kind: path, $t: ty, $( $transform: expr ),* ) => {
245        pub fn $name(self) -> Option<$t> {
246            match self { $kind(v) => { $( let v = $transform(v); )* Some(v) }, _ => None }
247        }
248    }
249}
250
251/// Converts `name` into a plain or namespaced value symbol, depending on
252/// whether or not `namespace` is given.
253///
254/// # Examples
255///
256/// ```ignore
257/// # use edn::types::to_symbol;
258/// # use edn::types::Value;
259/// # use edn::symbols;
260/// let value = to_symbol!("foo", "bar", Value);
261/// assert_eq!(value, Value::NamespacedSymbol(symbols::NamespacedSymbol::namespaced("foo", "bar")));
262///
263/// let value = to_symbol!(None, "baz", Value);
264/// assert_eq!(value, Value::PlainSymbol(symbols::PlainSymbol::plain("baz")));
265///
266/// let value = to_symbol!("foo", "bar", SpannedValue);
267/// assert_eq!(value.into(), to_symbol!("foo", "bar", Value));
268///
269/// let value = to_symbol!(None, "baz", SpannedValue);
270/// assert_eq!(value.into(), to_symbol!(None, "baz", Value));
271/// ```
272macro_rules! to_symbol {
273    ( $namespace:expr, $name:expr, $t:tt ) => {
274        $namespace.into().map_or_else(
275            || $t::PlainSymbol(symbols::PlainSymbol::plain($name)),
276            |ns| $t::NamespacedSymbol(symbols::NamespacedSymbol::namespaced(ns, $name)),
277        )
278    };
279}
280
281/// Converts `name` into a plain or namespaced value keyword, depending on
282/// whether or not `namespace` is given.
283///
284/// # Examples
285///
286/// ```ignore
287/// # use edn::types::to_keyword;
288/// # use edn::types::Value;
289/// # use edn::symbols;
290/// let value = to_keyword!("foo", "bar", Value);
291/// assert_eq!(value, Value::Keyword(symbols::Keyword::namespaced("foo", "bar")));
292///
293/// let value = to_keyword!(None, "baz", Value);
294/// assert_eq!(value, Value::Keyword(symbols::Keyword::plain("baz")));
295///
296/// let value = to_keyword!("foo", "bar", SpannedValue);
297/// assert_eq!(value.into(), to_keyword!("foo", "bar", Value));
298///
299/// let value = to_keyword!(None, "baz", SpannedValue);
300/// assert_eq!(value.into(), to_keyword!(None, "baz", Value));
301/// ```
302macro_rules! to_keyword {
303    ( $namespace:expr, $name:expr, $t:tt ) => {
304        $namespace.into().map_or_else(
305            || $t::Keyword(symbols::Keyword::plain($name)),
306            |ns| $t::Keyword(symbols::Keyword::namespaced(ns, $name)),
307        )
308    };
309}
310
311/// Implements multiple is*, as*, into* and from* methods common to
312/// both Value and SpannedValue.
313macro_rules! def_common_value_methods {
314    ( $t:tt<$tchild:tt> ) => {
315        def_is!(is_nil, $t::Nil);
316        def_is!(is_boolean, $t::Boolean(_));
317        def_is!(is_integer, $t::Integer(_));
318        def_is!(is_instant, $t::Instant(_));
319        def_is!(is_big_integer, $t::BigInteger(_));
320        def_is!(is_float, $t::Float(_));
321        def_is!(is_text, $t::Text(_));
322        def_is!(is_uuid, $t::Uuid(_));
323        def_is!(is_symbol, $t::PlainSymbol(_));
324        def_is!(is_namespaced_symbol, $t::NamespacedSymbol(_));
325        def_is!(is_vector, $t::Vector(_));
326        def_is!(is_list, $t::List(_));
327        def_is!(is_set, $t::Set(_));
328        def_is!(is_map, $t::Map(_));
329
330        pub fn is_keyword(&self) -> bool {
331            match self {
332                &$t::Keyword(ref k) => !k.is_namespaced(),
333                _ => false,
334            }
335        }
336
337        pub fn is_namespaced_keyword(&self) -> bool {
338            match self {
339                &$t::Keyword(ref k) => k.is_namespaced(),
340                _ => false,
341            }
342        }
343
344        /// `as_nil` does not use the macro as it does not have an underlying
345        /// value, and returns `Option<()>`.
346        pub fn as_nil(&self) -> Option<()> {
347            match *self { $t::Nil => Some(()), _ => None }
348        }
349
350        def_as!(as_boolean, $t::Boolean, bool,);
351        def_as!(as_integer, $t::Integer, i64,);
352        def_as!(as_instant, $t::Instant, DateTime<Utc>,);
353        def_as!(as_float, $t::Float, f64, |v: OrderedFloat<f64>| v.into_inner());
354
355        def_as_ref!(as_big_integer, $t::BigInteger, BigInt);
356        def_as_ref!(as_ordered_float, $t::Float, OrderedFloat<f64>);
357        def_as_ref!(as_text, $t::Text, String);
358        def_as_ref!(as_uuid, $t::Uuid, Uuid);
359        def_as_ref!(as_symbol, $t::PlainSymbol, symbols::PlainSymbol);
360        def_as_ref!(as_namespaced_symbol, $t::NamespacedSymbol, symbols::NamespacedSymbol);
361
362        pub fn as_keyword(&self) -> Option<&symbols::Keyword> {
363            match self {
364                &$t::Keyword(ref k) => Some(k),
365                _ => None,
366            }
367        }
368
369        pub fn as_plain_keyword(&self) -> Option<&symbols::Keyword> {
370            match self {
371                &$t::Keyword(ref k) if !k.is_namespaced() => Some(k),
372                _ => None,
373            }
374        }
375
376        pub fn as_namespaced_keyword(&self) -> Option<&symbols::Keyword> {
377            match self {
378                &$t::Keyword(ref k) if k.is_namespaced() => Some(k),
379                _ => None,
380            }
381        }
382
383        def_as_ref!(as_vector, $t::Vector, Vec<$tchild>);
384        def_as_ref!(as_list, $t::List, LinkedList<$tchild>);
385        def_as_ref!(as_set, $t::Set, BTreeSet<$tchild>);
386        def_as_ref!(as_map, $t::Map, BTreeMap<$tchild, $tchild>);
387
388        def_into!(into_boolean, $t::Boolean, bool,);
389        def_into!(into_integer, $t::Integer, i64,);
390        def_into!(into_instant, $t::Instant, DateTime<Utc>,);
391        def_into!(into_big_integer, $t::BigInteger, BigInt,);
392        def_into!(into_ordered_float, $t::Float, OrderedFloat<f64>,);
393        def_into!(into_float, $t::Float, f64, |v: OrderedFloat<f64>| v.into_inner());
394        def_into!(into_text, $t::Text, String,);
395        def_into!(into_uuid, $t::Uuid, Uuid,);
396        def_into!(into_symbol, $t::PlainSymbol, symbols::PlainSymbol,);
397        def_into!(into_namespaced_symbol, $t::NamespacedSymbol, symbols::NamespacedSymbol,);
398
399        pub fn into_keyword(self) -> Option<symbols::Keyword> {
400            match self {
401                $t::Keyword(k) => Some(k),
402                _ => None,
403            }
404        }
405
406        pub fn into_plain_keyword(self) -> Option<symbols::Keyword> {
407            match self {
408                $t::Keyword(k) => {
409                    if !k.is_namespaced() {
410                        Some(k)
411                    } else {
412                        None
413                    }
414                },
415                _ => None,
416            }
417        }
418
419        pub fn into_namespaced_keyword(self) -> Option<symbols::Keyword> {
420            match self {
421                $t::Keyword(k) => {
422                    if k.is_namespaced() {
423                        Some(k)
424                    } else {
425                        None
426                    }
427                },
428                _ => None,
429            }
430        }
431
432
433        def_into!(into_vector, $t::Vector, Vec<$tchild>,);
434        def_into!(into_list, $t::List, LinkedList<$tchild>,);
435        def_into!(into_set, $t::Set, BTreeSet<$tchild>,);
436        def_into!(into_map, $t::Map, BTreeMap<$tchild, $tchild>,);
437
438        def_from_option!(from_bigint, $t, $t::BigInteger, &str, |src: &str| src.parse::<BigInt>().ok());
439        def_from!(from_float, $t, $t::Float, f64, |src: f64| OrderedFloat::from(src));
440        def_from!(from_ordered_float, $t, $t::Float, OrderedFloat<f64>,);
441
442        pub fn from_symbol<'a, T: Into<Option<&'a str>>>(namespace: T, name: &str) -> $t {
443            to_symbol!(namespace, name, $t)
444        }
445
446        pub fn from_keyword<'a, T: Into<Option<&'a str>>>(namespace: T, name: &str) -> $t {
447            to_keyword!(namespace, name, $t)
448        }
449
450        fn precedence(&self) -> i32 {
451            match *self {
452                $t::Nil => 0,
453                $t::Boolean(_) => 1,
454                $t::Integer(_) => 2,
455                $t::BigInteger(_) => 3,
456                $t::Float(_) => 4,
457                $t::Instant(_) => 5,
458                $t::Text(_) => 6,
459                $t::Uuid(_) => 7,
460                $t::PlainSymbol(_) => 8,
461                $t::NamespacedSymbol(_) => 9,
462                $t::Keyword(ref k) if !k.is_namespaced() => 10,
463                $t::Keyword(_) => 11,
464                $t::Vector(_) => 12,
465                $t::List(_) => 13,
466                $t::Set(_) => 14,
467                $t::Map(_) => 15,
468            }
469        }
470
471        pub fn is_collection(&self) -> bool {
472            match *self {
473                $t::Nil => false,
474                $t::Boolean(_) => false,
475                $t::Integer(_) => false,
476                $t::Instant(_) => false,
477                $t::BigInteger(_) => false,
478                $t::Float(_) => false,
479                $t::Text(_) => false,
480                $t::Uuid(_) => false,
481                $t::PlainSymbol(_) => false,
482                $t::NamespacedSymbol(_) => false,
483                $t::Keyword(_) => false,
484                $t::Vector(_) => true,
485                $t::List(_) => true,
486                $t::Set(_) => true,
487                $t::Map(_) => true,
488            }
489        }
490
491        pub fn is_atom(&self) -> bool {
492            !self.is_collection()
493        }
494
495        pub fn into_atom(self) -> Option<$t> {
496            if self.is_atom() {
497                Some(self)
498            } else {
499                None
500            }
501        }
502    }
503}
504
505/// Compares Value or SpannedValue instances and returns Ordering.
506/// Used in `Ord` implementations.
507macro_rules! def_common_value_ord {
508    ( $t:tt, $value:expr, $other:expr ) => {
509        match ($value, $other) {
510            (&$t::Nil, &$t::Nil) => Ordering::Equal,
511            (&$t::Boolean(a), &$t::Boolean(b)) => b.cmp(&a),
512            (&$t::Integer(a), &$t::Integer(b)) => b.cmp(&a),
513            (&$t::Instant(a), &$t::Instant(b)) => b.cmp(&a),
514            (&$t::BigInteger(ref a), &$t::BigInteger(ref b)) => b.cmp(a),
515            (&$t::Float(ref a), &$t::Float(ref b)) => b.cmp(a),
516            (&$t::Text(ref a), &$t::Text(ref b)) => b.cmp(a),
517            (&$t::Uuid(ref a), &$t::Uuid(ref b)) => b.cmp(a),
518            (&$t::PlainSymbol(ref a), &$t::PlainSymbol(ref b)) => b.cmp(a),
519            (&$t::NamespacedSymbol(ref a), &$t::NamespacedSymbol(ref b)) => b.cmp(a),
520            (&$t::Keyword(ref a), &$t::Keyword(ref b)) => b.cmp(a),
521            (&$t::Vector(ref a), &$t::Vector(ref b)) => b.cmp(a),
522            (&$t::List(ref a), &$t::List(ref b)) => b.cmp(a),
523            (&$t::Set(ref a), &$t::Set(ref b)) => b.cmp(a),
524            (&$t::Map(ref a), &$t::Map(ref b)) => b.cmp(a),
525            _ => $value.precedence().cmp(&$other.precedence()),
526        }
527    };
528}
529
530/// Converts a Value or SpannedValue to string, given a formatter.
531// TODO: Make sure float syntax is correct, handle NaN and escaping.
532// See https://github.com/mozilla/mentat/issues/232
533macro_rules! def_common_value_display {
534    ( $t:tt, $value:expr, $f:expr ) => {
535        match *$value {
536            $t::Nil => write!($f, "nil"),
537            $t::Boolean(v) => write!($f, "{}", v),
538            $t::Integer(v) => write!($f, "{}", v),
539            $t::Instant(v) => write!(
540                $f,
541                "#inst \"{}\"",
542                v.to_rfc3339_opts(SecondsFormat::AutoSi, true)
543            ),
544            $t::BigInteger(ref v) => write!($f, "{}N", v),
545            // TODO: make sure float syntax is correct.
546            $t::Float(ref v) => {
547                if *v == OrderedFloat(f64::INFINITY) {
548                    write!($f, "#f +Infinity")
549                } else if *v == OrderedFloat(f64::NEG_INFINITY) {
550                    write!($f, "#f -Infinity")
551                } else if *v == OrderedFloat(f64::NAN) {
552                    write!($f, "#f NaN")
553                } else {
554                    write!($f, "{}", v)
555                }
556            }
557            // TODO: EDN escaping.
558            $t::Text(ref v) => write!($f, "\"{}\"", v),
559            $t::Uuid(ref u) => write!($f, "#uuid \"{}\"", u.hyphenated().to_string()),
560            $t::PlainSymbol(ref v) => v.fmt($f),
561            $t::NamespacedSymbol(ref v) => v.fmt($f),
562            $t::Keyword(ref v) => v.fmt($f),
563            $t::Vector(ref v) => {
564                write!($f, "[")?;
565                for x in v {
566                    write!($f, " {}", x)?;
567                }
568                write!($f, " ]")
569            }
570            $t::List(ref v) => {
571                write!($f, "(")?;
572                for x in v {
573                    write!($f, " {}", x)?;
574                }
575                write!($f, " )")
576            }
577            $t::Set(ref v) => {
578                write!($f, "#{{")?;
579                for x in v {
580                    write!($f, " {}", x)?;
581                }
582                write!($f, " }}")
583            }
584            $t::Map(ref v) => {
585                write!($f, "{{")?;
586                for (key, val) in v {
587                    write!($f, " {} {}", key, val)?;
588                }
589                write!($f, " }}")
590            }
591        }
592    };
593}
594
595macro_rules! def_common_value_impl {
596    ( $t:tt<$tchild:tt> ) => {
597        impl $t {
598            def_common_value_methods!($t<$tchild>);
599        }
600
601        impl PartialOrd for $t {
602            fn partial_cmp(&self, other: &$t) -> Option<Ordering> {
603                Some(Ord::cmp(self, other))
604            }
605        }
606
607        impl Ord for $t {
608            fn cmp(&self, other: &$t) -> Ordering {
609                def_common_value_ord!($t, self, other)
610            }
611        }
612
613        impl Display for $t {
614            fn fmt(&self, f: &mut Formatter) -> ::std::fmt::Result {
615                def_common_value_display!($t, self, f)
616            }
617        }
618    };
619}
620
621def_common_value_impl!(Value<Value>);
622def_common_value_impl!(SpannedValue<ValueAndSpan>);
623
624impl ValueAndSpan {
625    pub fn without_spans(self) -> Value {
626        self.inner.into()
627    }
628}
629
630impl PartialOrd for ValueAndSpan {
631    fn partial_cmp(&self, other: &ValueAndSpan) -> Option<Ordering> {
632        Some(Ord::cmp(self, other))
633    }
634}
635
636impl Ord for ValueAndSpan {
637    fn cmp(&self, other: &ValueAndSpan) -> Ordering {
638        self.inner.cmp(&other.inner)
639    }
640}
641
642impl Display for ValueAndSpan {
643    fn fmt(&self, f: &mut Formatter) -> ::std::fmt::Result {
644        self.inner.fmt(f)
645    }
646}
647
648pub trait FromMicros {
649    fn from_micros(ts: i64) -> Self;
650}
651
652impl FromMicros for DateTime<Utc> {
653    fn from_micros(ts: i64) -> Self {
654        DateTime::from_timestamp(
655            ts / 1_000_000,
656            ((ts % 1_000_000).unsigned_abs() as u32) * 1_000,
657        )
658        .unwrap()
659    }
660}
661
662pub trait ToMicros {
663    fn to_micros(&self) -> i64;
664}
665
666impl ToMicros for DateTime<Utc> {
667    fn to_micros(&self) -> i64 {
668        let major: i64 = self.timestamp() * 1_000_000;
669        let minor: i64 = self.timestamp_subsec_micros() as i64;
670        major + minor
671    }
672}
673
674pub trait FromMillis {
675    fn from_millis(ts: i64) -> Self;
676}
677
678impl FromMillis for DateTime<Utc> {
679    fn from_millis(ts: i64) -> Self {
680        DateTime::from_timestamp(ts / 1_000, ((ts % 1_000).unsigned_abs() as u32) * 1_000).unwrap()
681    }
682}
683
684pub trait ToMillis {
685    fn to_millis(&self) -> i64;
686}
687
688impl ToMillis for DateTime<Utc> {
689    fn to_millis(&self) -> i64 {
690        let major: i64 = self.timestamp() * 1_000;
691        let minor: i64 = self.timestamp_subsec_millis() as i64;
692        major + minor
693    }
694}
695
696#[cfg(test)]
697mod test {
698    use super::*;
699
700    use std::cmp::Ordering;
701    use std::collections::{BTreeMap, BTreeSet, LinkedList};
702    use std::f64;
703    use std::iter::FromIterator;
704
705    use crate::parse;
706
707    use chrono::{DateTime, Utc};
708    use num::BigInt;
709    use ordered_float::OrderedFloat;
710
711    #[test]
712    fn test_micros_roundtrip() {
713        let ts_micros: i64 = 1493399581314000;
714        let dt = DateTime::<Utc>::from_micros(ts_micros);
715        assert_eq!(dt.to_micros(), ts_micros);
716    }
717
718    #[test]
719    fn test_value_from() {
720        assert_eq!(
721            Value::from_float(42f64),
722            Value::Float(OrderedFloat::from(42f64))
723        );
724        assert_eq!(
725            Value::from_ordered_float(OrderedFloat::from(42f64)),
726            Value::Float(OrderedFloat::from(42f64))
727        );
728        assert_eq!(
729            Value::from_bigint("42").unwrap(),
730            Value::BigInteger(BigInt::from(42))
731        );
732    }
733
734    #[test]
735    #[allow(clippy::approx_constant)]
736    fn test_print_edn() {
737        assert_eq!("1234N", Value::from_bigint("1234").unwrap().to_string());
738
739        let string = "[ 1 2 ( 3.14 ) #{ 4N } { foo/bar 42 :baz/boz 43 } [ ] :five :six/seven eight nine/ten true false nil #f NaN #f -Infinity #f +Infinity ]";
740
741        let data = Value::Vector(vec![
742            Value::Integer(1),
743            Value::Integer(2),
744            Value::List(LinkedList::from_iter(vec![Value::from_float(3.14)])),
745            Value::Set(BTreeSet::from_iter(vec![Value::from_bigint("4").unwrap()])),
746            Value::Map(BTreeMap::from_iter(vec![
747                (Value::from_symbol("foo", "bar"), Value::Integer(42)),
748                (Value::from_keyword("baz", "boz"), Value::Integer(43)),
749            ])),
750            Value::Vector(vec![]),
751            Value::from_keyword(None, "five"),
752            Value::from_keyword("six", "seven"),
753            Value::from_symbol(None, "eight"),
754            Value::from_symbol("nine", "ten"),
755            Value::Boolean(true),
756            Value::Boolean(false),
757            Value::Nil,
758            Value::from_float(f64::NAN),
759            Value::from_float(f64::NEG_INFINITY),
760            Value::from_float(f64::INFINITY),
761        ]);
762
763        assert_eq!(string, data.to_string());
764        assert_eq!(string, parse::value(&data.to_string()).unwrap().to_string());
765        assert_eq!(
766            string,
767            parse::value(&data.to_string())
768                .unwrap()
769                .without_spans()
770                .to_string()
771        );
772    }
773
774    #[test]
775    fn test_ord() {
776        // TODO: Check we follow the equality rules at the bottom of https://github.com/edn-format/edn
777        assert_eq!(Value::Nil.cmp(&Value::Nil), Ordering::Equal);
778        assert_eq!(
779            Value::Boolean(false).cmp(&Value::Boolean(true)),
780            Ordering::Greater
781        );
782        assert_eq!(Value::Integer(1).cmp(&Value::Integer(2)), Ordering::Greater);
783        assert_eq!(
784            Value::from_bigint("1").cmp(&Value::from_bigint("2")),
785            Ordering::Greater
786        );
787        assert_eq!(
788            Value::from_float(1f64).cmp(&Value::from_float(2f64)),
789            Ordering::Greater
790        );
791        assert_eq!(
792            Value::Text("1".to_string()).cmp(&Value::Text("2".to_string())),
793            Ordering::Greater
794        );
795        assert_eq!(
796            Value::from_symbol("a", "b").cmp(&Value::from_symbol("c", "d")),
797            Ordering::Greater
798        );
799        assert_eq!(
800            Value::from_symbol(None, "a").cmp(&Value::from_symbol(None, "b")),
801            Ordering::Greater
802        );
803        assert_eq!(
804            Value::from_keyword(":a", ":b").cmp(&Value::from_keyword(":c", ":d")),
805            Ordering::Greater
806        );
807        assert_eq!(
808            Value::from_keyword(None, ":a").cmp(&Value::from_keyword(None, ":b")),
809            Ordering::Greater
810        );
811        assert_eq!(
812            Value::Vector(vec![]).cmp(&Value::Vector(vec![])),
813            Ordering::Equal
814        );
815        assert_eq!(
816            Value::List(LinkedList::new()).cmp(&Value::List(LinkedList::new())),
817            Ordering::Equal
818        );
819        assert_eq!(
820            Value::Set(BTreeSet::new()).cmp(&Value::Set(BTreeSet::new())),
821            Ordering::Equal
822        );
823        assert_eq!(
824            Value::Map(BTreeMap::new()).cmp(&Value::Map(BTreeMap::new())),
825            Ordering::Equal
826        );
827    }
828
829    #[test]
830    fn test_keyword_as() {
831        let namespaced = symbols::Keyword::namespaced("foo", "bar");
832        let plain = symbols::Keyword::plain("bar");
833        let n_v = Value::Keyword(namespaced);
834        let p_v = Value::Keyword(plain);
835
836        assert!(n_v.as_keyword().is_some());
837        assert!(n_v.as_plain_keyword().is_none());
838        assert!(n_v.as_namespaced_keyword().is_some());
839
840        assert!(p_v.as_keyword().is_some());
841        assert!(p_v.as_plain_keyword().is_some());
842        assert!(p_v.as_namespaced_keyword().is_none());
843
844        assert!(n_v.clone().into_keyword().is_some());
845        assert!(n_v.clone().into_plain_keyword().is_none());
846        assert!(n_v.clone().into_namespaced_keyword().is_some());
847
848        assert!(p_v.clone().into_keyword().is_some());
849        assert!(p_v.clone().into_plain_keyword().is_some());
850        assert!(p_v.clone().into_namespaced_keyword().is_none());
851    }
852}