Skip to main content

edn/
types.rs

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