postgres_range/
lib.rs

1//! Types dealing with ranges of values
2#![doc(html_root_url = "https://sfackler.github.io/rust-postgres-range/doc/v0.11")]
3#![warn(clippy::all, rust_2018_idioms, missing_docs)]
4
5#[macro_use(to_sql_checked)]
6extern crate postgres_types;
7
8#[cfg(feature = "with-chrono-0_4")]
9mod chrono_04;
10
11use std::cmp::Ordering;
12use std::fmt;
13use std::i32;
14use std::i64;
15use std::marker::PhantomData;
16
17use BoundSide::{Lower, Upper};
18use BoundType::{Exclusive, Inclusive};
19use InnerRange::{Empty, Normal};
20
21/// The `range!` macro can make it easier to create ranges. It roughly mirrors
22/// traditional mathematic range syntax.
23///
24/// ## Example
25///
26/// ```rust
27///
28/// #[macro_use]
29/// extern crate postgres_range;
30///
31/// use postgres_range::Range;
32///
33/// fn main() {
34///     let mut r: Range<i32>;
35///     // a closed interval
36///     r = range!('[' 5i32, 10i32; ']');
37///     // an open interval
38///     r = range!('(' 5i32, 10i32; ')');
39///     // half-open intervals
40///     r = range!('(' 5i32, 10i32; ']');
41///     r = range!('[' 5i32, 10i32; ')');
42///     // a closed lower-bounded interval
43///     r = range!('[' 5i32,; ')');
44///     // an open lower-bounded interval
45///     r = range!('(' 5i32,; ')');
46///     // a closed upper-bounded interval
47///     r = range!('(', 10i32; ']');
48///     // an open upper-bounded interval
49///     r = range!('(', 10i32; ')');
50///     // an unbounded interval
51///     r = range!('(',; ')');
52///     // an empty interval
53///     r = range!(empty);
54/// }
55#[macro_export]
56macro_rules! range {
57    (empty) => ($crate::Range::empty());
58    ('(',; ')') => ($crate::Range::new(None, None));
59    ('(', $h:expr; ')') => (
60        $crate::Range::new(None,
61            Some($crate::RangeBound::new($h,
62                $crate::BoundType::Exclusive)))
63    );
64    ('(', $h:expr; ']') => (
65        $crate::Range::new(None,
66            Some($crate::RangeBound::new($h,
67                $crate::BoundType::Inclusive)))
68    );
69    ('(' $l:expr,; ')') => (
70        $crate::Range::new(
71            Some($crate::RangeBound::new($l,
72                $crate::BoundType::Exclusive)), None)
73    );
74    ('[' $l:expr,; ')') => (
75        $crate::Range::new(
76            Some($crate::RangeBound::new($l,
77                $crate::BoundType::Inclusive)), None)
78    );
79    ('(' $l:expr, $h:expr; ')') => (
80        $crate::Range::new(
81            Some($crate::RangeBound::new($l,
82                $crate::BoundType::Exclusive)),
83            Some($crate::RangeBound::new($h,
84                $crate::BoundType::Exclusive)))
85    );
86    ('(' $l:expr, $h:expr; ']') => (
87        $crate::Range::new(
88            Some($crate::RangeBound::new($l,
89                $crate::BoundType::Exclusive)),
90            Some($crate::RangeBound::new($h,
91                $crate::BoundType::Inclusive)))
92    );
93    ('[' $l:expr, $h:expr; ')') => (
94        $crate::Range::new(
95            Some($crate::RangeBound::new($l,
96                $crate::BoundType::Inclusive)),
97            Some($crate::RangeBound::new($h,
98                $crate::BoundType::Exclusive)))
99    );
100    ('[' $l:expr, $h:expr; ']') => (
101        $crate::Range::new(
102            Some($crate::RangeBound::new($l,
103                $crate::BoundType::Inclusive)),
104            Some($crate::RangeBound::new($h,
105                $crate::BoundType::Inclusive)))
106    )
107}
108
109mod impls;
110
111/// A trait that normalizes a range bound for a type
112pub trait Normalizable: Sized {
113    /// Given a range bound, returns the normalized version of that bound. For
114    /// discrete types such as i32, the normalized lower bound is always
115    /// inclusive and the normalized upper bound is always exclusive. Other
116    /// types, such as Timespec, have no normalization process so their
117    /// implementation is a no-op.
118    ///
119    /// The logic here should match the logic performed by the equivalent
120    /// Postgres type.
121    fn normalize<S>(bound: RangeBound<S, Self>) -> RangeBound<S, Self>
122    where
123        S: BoundSided;
124}
125
126macro_rules! bounded_normalizable {
127    ($t:ident) => (
128        impl Normalizable for $t {
129            fn normalize<S>(bound: RangeBound<S, $t>) -> RangeBound<S, $t> where S: BoundSided {
130                match (<S as BoundSided>::side(), bound.type_) {
131                    (Upper, Inclusive) => {
132                        assert!(bound.value != $t::MAX);
133                        RangeBound::new(bound.value + 1, Exclusive)
134                    }
135                    (Lower, Exclusive) => {
136                        assert!(bound.value != $t::MAX);
137                        RangeBound::new(bound.value + 1, Inclusive)
138                    }
139                    _ => bound
140                }
141            }
142        }
143    )
144}
145
146bounded_normalizable!(i32);
147bounded_normalizable!(i64);
148
149/// The possible sides of a bound.
150#[derive(Debug, PartialEq, Eq, Clone, Copy)]
151pub enum BoundSide {
152    /// An upper bound.
153    Upper,
154    /// A lower bound.
155    Lower,
156}
157
158/// A trait implemented by phantom types indicating the type of the bound.
159pub trait BoundSided {
160    /// Returns the bound side this type corresponds to.
161    fn side() -> BoundSide;
162}
163
164/// A tag type representing an upper bound
165pub enum UpperBound {}
166
167/// A tag type representing a lower bound
168pub enum LowerBound {}
169
170impl BoundSided for UpperBound {
171    fn side() -> BoundSide {
172        Upper
173    }
174}
175
176impl BoundSided for LowerBound {
177    fn side() -> BoundSide {
178        Lower
179    }
180}
181
182/// The type of a range bound.
183#[derive(Debug, PartialEq, Eq, Clone, Copy)]
184pub enum BoundType {
185    /// The bound includes its value.
186    Inclusive,
187    /// The bound excludes its value.
188    Exclusive,
189}
190
191/// Represents a one-sided bound.
192///
193/// The side is determined by the `S` phantom parameter.
194pub struct RangeBound<S: BoundSided, T> {
195    /// The value of the bound.
196    pub value: T,
197    /// The type of the bound.
198    pub type_: BoundType,
199    _m: PhantomData<S>,
200}
201
202fn _is_send_sync() {
203    fn is_send_sync<T: Send + Sync>() {}
204    is_send_sync::<RangeBound<LowerBound, i32>>();
205}
206
207impl<S, T> Copy for RangeBound<S, T>
208where
209    S: BoundSided,
210    T: Copy,
211{
212}
213
214impl<S, T> Clone for RangeBound<S, T>
215where
216    S: BoundSided,
217    T: Clone,
218{
219    fn clone(&self) -> RangeBound<S, T> {
220        RangeBound {
221            value: self.value.clone(),
222            type_: self.type_,
223            _m: PhantomData,
224        }
225    }
226}
227
228impl<S, T> fmt::Debug for RangeBound<S, T>
229where
230    S: BoundSided,
231    T: fmt::Debug,
232{
233    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
234        fmt.debug_struct("RangeBound")
235            .field("value", &self.value)
236            .field("type_", &self.type_)
237            .finish()
238    }
239}
240
241impl<S, T> fmt::Display for RangeBound<S, T>
242where
243    S: BoundSided,
244    T: fmt::Display,
245{
246    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
247        let (lower, upper) = match self.type_ {
248            Inclusive => ('[', ']'),
249            Exclusive => ('(', ')'),
250        };
251
252        match <S as BoundSided>::side() {
253            Lower => write!(fmt, "{}{}", lower, self.value),
254            Upper => write!(fmt, "{}{}", self.value, upper),
255        }
256    }
257}
258
259impl<S, T> PartialEq for RangeBound<S, T>
260where
261    S: BoundSided,
262    T: PartialEq,
263{
264    fn eq(&self, other: &RangeBound<S, T>) -> bool {
265        self.value == other.value && self.type_ == other.type_
266    }
267
268    /*fn ne(&self, other: &RangeBound<S, T>) -> bool {
269        self.value != other.value || self.type_ != other.type_
270    }*/
271}
272
273impl<S, T> Eq for RangeBound<S, T>
274where
275    S: BoundSided,
276    T: Eq,
277{
278}
279
280impl<S, T> PartialOrd for RangeBound<S, T>
281where
282    S: BoundSided,
283    T: PartialOrd,
284{
285    fn partial_cmp(&self, other: &RangeBound<S, T>) -> Option<Ordering> {
286        match (
287            <S as BoundSided>::side(),
288            self.type_,
289            other.type_,
290            self.value.partial_cmp(&other.value),
291        ) {
292            (Upper, Exclusive, Inclusive, Some(Ordering::Equal)) | (Lower, Inclusive, Exclusive, Some(Ordering::Equal)) => Some(Ordering::Less),
293            (Upper, Inclusive, Exclusive, Some(Ordering::Equal)) | (Lower, Exclusive, Inclusive, Some(Ordering::Equal)) => Some(Ordering::Greater),
294            (_, _, _, cmp) => cmp,
295        }
296    }
297}
298
299impl<S, T> Ord for RangeBound<S, T>
300where
301    S: BoundSided,
302    T: Ord,
303{
304    fn cmp(&self, other: &RangeBound<S, T>) -> Ordering {
305        match (
306            <S as BoundSided>::side(),
307            self.type_,
308            other.type_,
309            self.value.cmp(&other.value),
310        ) {
311            (Upper, Exclusive, Inclusive, Ordering::Equal) | (Lower, Inclusive, Exclusive, Ordering::Equal) => Ordering::Less,
312            (Upper, Inclusive, Exclusive, Ordering::Equal) | (Lower, Exclusive, Inclusive, Ordering::Equal) => Ordering::Greater,
313            (_, _, _, ord) => ord,
314        }
315    }
316}
317
318impl<S, T> RangeBound<S, T>
319where
320    S: BoundSided,
321    T: PartialOrd,
322{
323    /// Constructs a new range bound
324    pub fn new(value: T, type_: BoundType) -> RangeBound<S, T> {
325        RangeBound {
326            value,
327            type_,
328            _m: PhantomData,
329        }
330    }
331
332    /// Determines if a value lies within the range specified by this bound.
333    pub fn in_bounds(&self, value: &T) -> bool {
334        match (self.type_, <S as BoundSided>::side()) {
335            (Inclusive, Upper) => value <= &self.value,
336            (Exclusive, Upper) => value < &self.value,
337            (Inclusive, Lower) => value >= &self.value,
338            (Exclusive, Lower) => value > &self.value,
339        }
340    }
341}
342
343struct OptBound<'a, S: BoundSided, T>(Option<&'a RangeBound<S, T>>);
344
345impl<'a, S, T> PartialEq for OptBound<'a, S, T>
346where
347    S: BoundSided,
348    T: PartialEq,
349{
350    fn eq(&self, &OptBound(ref other): &OptBound<'a, S, T>) -> bool {
351        let &OptBound(ref self_) = self;
352        self_ == other
353    }
354
355    /*fn ne(&self, &OptBound(ref other): &OptBound<'a, S, T>) -> bool {
356        let &OptBound(ref self_) = self;
357        self_ != other
358    }*/
359}
360
361impl<'a, S, T> PartialOrd for OptBound<'a, S, T>
362where
363    S: BoundSided,
364    T: PartialOrd,
365{
366    fn partial_cmp(&self, other: &OptBound<'a, S, T>) -> Option<Ordering> {
367        match (self, other, <S as BoundSided>::side()) {
368            (&OptBound(None), &OptBound(None), _) => Some(Ordering::Equal),
369            (&OptBound(None), _, Lower) | (_, &OptBound(None), Upper) => Some(Ordering::Less),
370            (&OptBound(None), _, Upper) | (_, &OptBound(None), Lower) => Some(Ordering::Greater),
371            (&OptBound(Some(a)), &OptBound(Some(b)), _) => a.partial_cmp(b),
372        }
373    }
374}
375
376/// Represents a range of values.
377#[derive(Debug, PartialEq, Eq, Clone, Copy)]
378pub struct Range<T> {
379    inner: InnerRange<T>,
380}
381
382#[derive(Debug, PartialEq, Eq, Clone, Copy)]
383enum InnerRange<T> {
384    Empty,
385    Normal(
386        Option<RangeBound<LowerBound, T>>,
387        Option<RangeBound<UpperBound, T>>,
388    ),
389}
390
391impl<T> fmt::Display for Range<T>
392where
393    T: fmt::Display,
394{
395    fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
396        match self.inner {
397            Empty => write!(fmt, "empty"),
398            Normal(ref lower, ref upper) => {
399                match *lower {
400                    Some(ref bound) => write!(fmt, "{}", bound)?,
401                    None => write!(fmt, "(")?,
402                }
403                write!(fmt, ",")?;
404                match *upper {
405                    Some(ref bound) => write!(fmt, "{}", bound),
406                    None => write!(fmt, ")"),
407                }
408            }
409        }
410    }
411}
412
413impl<T> Range<T>
414where
415    T: PartialOrd + Normalizable,
416{
417    /// Creates a new range.
418    ///
419    /// If a bound is `None`, the range is unbounded in that direction.
420    pub fn new(lower: Option<RangeBound<LowerBound, T>>, upper: Option<RangeBound<UpperBound, T>>) -> Range<T> {
421        let lower = lower.map(Normalizable::normalize);
422        let upper = upper.map(Normalizable::normalize);
423
424        if let (&Some(ref lower), &Some(ref upper)) = (&lower, &upper) {
425            let empty = match (lower.type_, upper.type_) {
426                (Inclusive, Inclusive) => lower.value > upper.value,
427                _ => lower.value >= upper.value,
428            };
429            if empty {
430                return Range { inner: Empty };
431            }
432        }
433
434        Range {
435            inner: Normal(lower, upper),
436        }
437    }
438
439    /// Creates a new empty range.
440    pub fn empty() -> Range<T> {
441        Range { inner: Empty }
442    }
443
444    /// Determines if this range is the empty range.
445    pub fn is_empty(&self) -> bool {
446        match self.inner {
447            Empty => true,
448            Normal(..) => false,
449        }
450    }
451
452    /// Returns the lower bound if it exists.
453    pub fn lower(&self) -> Option<&RangeBound<LowerBound, T>> {
454        match self.inner {
455            Normal(Some(ref lower), _) => Some(lower),
456            _ => None,
457        }
458    }
459
460    /// Returns the upper bound if it exists.
461    pub fn upper(&self) -> Option<&RangeBound<UpperBound, T>> {
462        match self.inner {
463            Normal(_, Some(ref upper)) => Some(upper),
464            _ => None,
465        }
466    }
467
468    /// Determines if a value lies within this range.
469    pub fn contains(&self, value: &T) -> bool {
470        match self.inner {
471            Empty => false,
472            Normal(ref lower, ref upper) => {
473                lower.as_ref().map_or(true, |b| {
474                    b.in_bounds(value)
475                }) && upper.as_ref().map_or(true, |b| {
476                    b.in_bounds(value)
477                })
478            }
479        }
480    }
481
482    /// Determines if a range lies completely within this range.
483    pub fn contains_range(&self, other: &Range<T>) -> bool {
484        if other.is_empty() {
485            return true;
486        }
487
488        if self.is_empty() {
489            return false;
490        }
491
492        OptBound(self.lower()) <= OptBound(other.lower()) && OptBound(self.upper()) >= OptBound(other.upper())
493    }
494}
495
496fn order<T>(a: T, b: T) -> (T, T)
497where
498    T: PartialOrd,
499{
500    if a < b {
501        (a, b)
502    } else {
503        (b, a)
504    }
505}
506
507impl<T> Range<T>
508where
509    T: PartialOrd + Normalizable + Clone,
510{
511    /// Returns the intersection of this range with another.
512    pub fn intersect(&self, other: &Range<T>) -> Range<T> {
513        if self.is_empty() || other.is_empty() {
514            return Range::empty();
515        }
516
517        let (_, OptBound(lower)) = order(OptBound(self.lower()), OptBound(other.lower()));
518        let (OptBound(upper), _) = order(OptBound(self.upper()), OptBound(other.upper()));
519
520        Range::new(lower.cloned(), upper.cloned())
521    }
522
523    /// Returns the union of this range with another if it is contiguous.
524    pub fn union(&self, other: &Range<T>) -> Option<Range<T>> {
525        if self.is_empty() {
526            return Some(other.clone());
527        }
528
529        if other.is_empty() {
530            return Some(self.clone());
531        }
532
533        let (OptBound(l_lower), OptBound(u_lower)) = order(OptBound(self.lower()), OptBound(other.lower()));
534        let (OptBound(l_upper), OptBound(u_upper)) = order(OptBound(self.upper()), OptBound(other.upper()));
535
536        let discontiguous = match (u_lower, l_upper) {
537            (
538                Some(&RangeBound {
539                    value: ref l,
540                    type_: Exclusive,
541                    ..
542                }),
543                Some(&RangeBound {
544                    value: ref u,
545                    type_: Exclusive,
546                    ..
547                }),
548            ) => l >= u,
549            (Some(&RangeBound { value: ref l, .. }), Some(&RangeBound { value: ref u, .. })) => l > u,
550            _ => false,
551        };
552
553        if discontiguous {
554            None
555        } else {
556            Some(Range::new(
557                l_lower.cloned(),
558                u_upper.cloned(),
559            ))
560        }
561    }
562}
563
564#[cfg(test)]
565mod test {
566    use std::i32;
567
568    use super::{BoundType, LowerBound, Normalizable, Range, RangeBound, UpperBound};
569    use super::BoundType::{Exclusive, Inclusive};
570
571    #[test]
572    fn test_range_bound_lower_lt() {
573        fn check(val1: isize, inc1: BoundType, val2: isize, inc2: BoundType, expected: bool) {
574            let a: RangeBound<LowerBound, isize> = RangeBound::new(val1, inc1);
575            let b: RangeBound<LowerBound, isize> = RangeBound::new(val2, inc2);
576            assert_eq!(expected, a < b);
577        }
578
579        check(1, Inclusive, 2, Exclusive, true);
580        check(1, Exclusive, 2, Inclusive, true);
581        check(1, Inclusive, 1, Exclusive, true);
582        check(2, Inclusive, 1, Inclusive, false);
583        check(2, Exclusive, 1, Exclusive, false);
584        check(1, Exclusive, 1, Inclusive, false);
585        check(1, Exclusive, 1, Exclusive, false);
586        check(1, Inclusive, 1, Inclusive, false);
587    }
588
589    #[test]
590    fn test_range_bound_upper_lt() {
591        fn check(val1: isize, inc1: BoundType, val2: isize, inc2: BoundType, expected: bool) {
592            let a: RangeBound<UpperBound, isize> = RangeBound::new(val1, inc1);
593            let b: RangeBound<UpperBound, isize> = RangeBound::new(val2, inc2);
594            assert_eq!(expected, a < b);
595        }
596
597        check(1, Inclusive, 2, Exclusive, true);
598        check(1, Exclusive, 2, Exclusive, true);
599        check(1, Exclusive, 1, Inclusive, true);
600        check(2, Inclusive, 1, Inclusive, false);
601        check(2, Exclusive, 1, Exclusive, false);
602        check(1, Inclusive, 1, Exclusive, false);
603        check(1, Inclusive, 1, Inclusive, false);
604        check(1, Exclusive, 1, Exclusive, false);
605    }
606
607    #[test]
608    fn test_range_bound_lower_in_bounds() {
609        fn check(bound: isize, inc: BoundType, val: isize, expected: bool) {
610            let b: RangeBound<LowerBound, isize> = RangeBound::new(bound, inc);
611            assert_eq!(expected, b.in_bounds(&val));
612        }
613
614        check(1, Inclusive, 1, true);
615        check(1, Exclusive, 1, false);
616        check(1, Inclusive, 2, true);
617        check(1, Inclusive, 0, false);
618    }
619
620    #[test]
621    fn test_range_bound_upper_in_bounds() {
622        fn check(bound: isize, inc: BoundType, val: isize, expected: bool) {
623            let b: RangeBound<UpperBound, isize> = RangeBound::new(bound, inc);
624            assert_eq!(expected, b.in_bounds(&val));
625        }
626
627        check(1, Inclusive, 1, true);
628        check(1, Exclusive, 1, false);
629        check(1, Inclusive, 2, false);
630        check(1, Inclusive, 0, true);
631    }
632
633    #[test]
634    fn test_range_contains() {
635        let r = range!('[' 1i32, 3i32; ']');
636        assert!(!r.contains(&4));
637        assert!(r.contains(&3));
638        assert!(r.contains(&2));
639        assert!(r.contains(&1));
640        assert!(!r.contains(&0));
641
642        let r = range!('(' 1i32, 3i32; ')');
643        assert!(!r.contains(&4));
644        assert!(!r.contains(&3));
645        assert!(r.contains(&2));
646        assert!(!r.contains(&1));
647        assert!(!r.contains(&0));
648
649        let r = range!('(', 3i32; ']');
650        assert!(!r.contains(&4));
651        assert!(r.contains(&2));
652        assert!(r.contains(&i32::MIN));
653
654        let r = range!('[' 1i32,; ')');
655        assert!(r.contains(&i32::MAX));
656        assert!(r.contains(&4));
657        assert!(!r.contains(&0));
658
659        let r = range!('(',; ')');
660        assert!(r.contains(&i32::MAX));
661        assert!(r.contains(&0i32));
662        assert!(r.contains(&i32::MIN));
663    }
664
665    #[test]
666    fn test_normalize_lower() {
667        let r: RangeBound<LowerBound, i32> = RangeBound::new(10i32, Inclusive);
668        assert_eq!(
669            RangeBound::new(10i32, Inclusive),
670            Normalizable::normalize(r)
671        );
672
673        let r: RangeBound<LowerBound, i32> = RangeBound::new(10i32, Exclusive);
674        assert_eq!(
675            RangeBound::new(11i32, Inclusive),
676            Normalizable::normalize(r)
677        );
678    }
679
680    #[test]
681    fn test_normalize_upper() {
682        let r: RangeBound<UpperBound, i32> = RangeBound::new(10i32, Inclusive);
683        assert_eq!(
684            RangeBound::new(11i32, Exclusive),
685            Normalizable::normalize(r)
686        );
687
688        let r: RangeBound<UpperBound, i32> = RangeBound::new(10i32, Exclusive);
689        assert_eq!(
690            RangeBound::new(10i32, Exclusive),
691            Normalizable::normalize(r)
692        );
693    }
694
695    #[test]
696    fn test_range_normalizes() {
697        let r1 = range!('(' 10i32, 15i32; ']');
698        let r2 = range!('[' 11i32, 16i32; ')');
699        assert_eq!(r1, r2);
700    }
701
702    #[test]
703    fn test_range_empty() {
704        assert!((range!('(' 9i32, 10i32; ')')).is_empty());
705        assert!((range!('[' 10i32, 10i32; ')')).is_empty());
706        assert!((range!('(' 10i32, 10i32; ']')).is_empty());
707        assert!((range!('[' 10i32, 9i32; ']')).is_empty());
708    }
709
710    #[test]
711    fn test_intersection() {
712        let r1 = range!('[' 10i32, 15i32; ')');
713        let r2 = range!('(' 20i32, 25i32; ']');
714        assert!(r1.intersect(&r2).is_empty());
715        assert!(r2.intersect(&r1).is_empty());
716        assert_eq!(r1, r1.intersect(&range!('(',; ')')));
717        assert_eq!(r1, (range!('(',; ')')).intersect(&r1));
718
719        let r2 = range!('(' 10i32,; ')');
720        let exp = Range::new(r2.lower().copied(), r1.upper().copied());
721        assert_eq!(exp, r1.intersect(&r2));
722        assert_eq!(exp, r2.intersect(&r1));
723
724        let r2 = range!('(', 15i32; ']');
725        assert_eq!(r1, r1.intersect(&r2));
726        assert_eq!(r1, r2.intersect(&r1));
727
728        let r2 = range!('[' 11i32, 14i32; ')');
729        assert_eq!(r2, r1.intersect(&r2));
730        assert_eq!(r2, r2.intersect(&r1));
731    }
732
733    #[test]
734    fn test_union() {
735        let r1 = range!('[' 10i32, 15i32; ')');
736        let r2 = range!('(' 20i32, 25i32; ']');
737        assert_eq!(None, r1.union(&r2));
738        assert_eq!(None, r2.union(&r1));
739
740        let r2 = range!('(',; ')');
741        assert_eq!(Some(r2), r1.union(&r2));
742        assert_eq!(Some(r2), r2.union(&r1));
743
744        let r2 = range!('[' 13i32, 50i32; ')');
745        assert_eq!(Some(range!('[' 10i32, 50i32; ')')), r1.union(&r2));
746        assert_eq!(Some(range!('[' 10i32, 50i32; ')')), r2.union(&r1));
747
748        let r2 = range!('[' 3i32, 50i32; ')');
749        assert_eq!(Some(range!('[' 3i32, 50i32; ')')), r1.union(&r2));
750        assert_eq!(Some(range!('[' 3i32, 50i32; ')')), r2.union(&r1));
751
752        let r2 = range!('(', 11i32; ')');
753        assert_eq!(Some(range!('(', 15i32; ')')), r1.union(&r2));
754        assert_eq!(Some(range!('(', 15i32; ')')), r2.union(&r1));
755
756        let r2 = range!('(' 11i32,; ')');
757        assert_eq!(Some(range!('[' 10i32,; ')')), r1.union(&r2));
758        assert_eq!(Some(range!('[' 10i32,; ')')), r2.union(&r1));
759
760        let r2 = range!('(' 15i32, 20i32; ')');
761        assert_eq!(None, r1.union(&r2));
762        assert_eq!(None, r2.union(&r1));
763
764        let r2 = range!('[' 15i32, 20i32; ']');
765        assert_eq!(Some(range!('[' 10i32, 20i32; ']')), r1.union(&r2));
766        assert_eq!(Some(range!('[' 10i32, 20i32; ']')), r2.union(&r1));
767    }
768
769    #[test]
770    fn test_contains_range() {
771        assert!(Range::<i32>::empty().contains_range(&Range::empty()));
772
773        let r1 = range!('[' 10i32, 15i32; ')');
774        assert!(r1.contains_range(&r1));
775
776        let r2 = range!('(' 10i32,; ')');
777        assert!(!r1.contains_range(&r2));
778        assert!(!r2.contains_range(&r1));
779
780        let r2 = range!('(', 15i32; ']');
781        assert!(!r1.contains_range(&r2));
782        assert!(r2.contains_range(&r1));
783    }
784}