intervalsets/
display.rs

1use itertools::Itertools;
2
3use crate::bound::BoundType;
4use crate::numeric::Domain;
5use crate::{Bound, Bounding, Interval, Side};
6
7use crate::detail::{BoundCase, Finite, HalfBounded};
8use crate::IntervalSet;
9
10use core::fmt;
11
12fn bound_symbol(side: Side, bound_type: BoundType) -> char {
13    match bound_type {
14        BoundType::Open => match side {
15            Side::Left => '(',
16            Side::Right => ')',
17        },
18        BoundType::Closed => match side {
19            Side::Left => '[',
20            Side::Right => ']',
21        },
22    }
23}
24
25fn format_bound<T: fmt::Display>(side: Side, bound: Option<&Bound<T>>) -> String {
26    match bound {
27        None => match side {
28            Side::Left => "(<-".to_string(),
29            Side::Right => "->)".to_string(),
30        },
31        Some(bound) => match side {
32            Side::Left => format!(
33                "{}{}",
34                bound_symbol(side, bound.bound_type()),
35                bound.value()
36            ),
37            Side::Right => format!(
38                "{}{}",
39                bound.value(),
40                bound_symbol(side, bound.bound_type())
41            ),
42        },
43    }
44}
45
46impl<T: fmt::Display + Clone> fmt::Display for Finite<T> {
47    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
48        match self {
49            Self::Empty => write!(f, "{{}}"),
50            Self::FullyBounded(left, right) => {
51                write!(
52                    f,
53                    "{}, {}",
54                    format_bound(Side::Left, Some(left)),
55                    format_bound(Side::Right, Some(right)),
56                )
57            }
58        }
59    }
60}
61
62impl<T: fmt::Display + Domain> fmt::Display for HalfBounded<T> {
63    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
64        write!(
65            f,
66            "{}, {}",
67            format_bound(Side::Left, self.left()),
68            format_bound(Side::Right, self.right())
69        )
70    }
71}
72
73impl<T: fmt::Display + Domain> fmt::Display for BoundCase<T> {
74    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
75        match self {
76            Self::Unbounded => write!(f, "(<-, ->)"),
77            Self::Finite(inner) => inner.fmt(f),
78            Self::Half(inner) => inner.fmt(f),
79        }
80    }
81}
82
83impl<T: fmt::Display + Domain> fmt::Display for Interval<T> {
84    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
85        self.0.fmt(f)
86    }
87}
88
89impl<T: fmt::Display + Domain> fmt::Display for IntervalSet<T> {
90    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
91        if self.intervals().is_empty() {
92            Finite::<i32>::Empty.fmt(f)
93        } else {
94            write!(f, "{{{}}}", self.intervals().iter().join(", "))
95        }
96    }
97}
98
99#[cfg(test)]
100mod tests {
101    use crate::ops::Union;
102
103    use super::*;
104
105    #[test]
106    fn test_display_finite() {
107        assert_eq!(format!("{}", Interval::<i8>::empty()), "{}");
108
109        assert_eq!(format!("{}", Interval::closed(0, 5)), "[0, 5]");
110
111        assert_eq!(format!("{}", Interval::open(0.1, 5.1)), "(0.1, 5.1)");
112
113        assert_eq!(format!("{}", Interval::open_closed(0.1, 5.1)), "(0.1, 5.1]");
114
115        assert_eq!(format!("{}", Interval::closed_open(0.1, 5.1)), "[0.1, 5.1)");
116    }
117
118    #[test]
119    fn test_display_half() {
120        assert_eq!(format!("{}", Interval::unbound_closed(0.5)), "(<-, 0.5]");
121
122        assert_eq!(format!("{}", Interval::unbound_open(0.5)), "(<-, 0.5)");
123
124        assert_eq!(format!("{}", Interval::closed_unbound(0.5)), "[0.5, ->)");
125
126        assert_eq!(format!("{}", Interval::open_unbound(0.5)), "(0.5, ->)")
127    }
128
129    #[test]
130    fn test_display_interval() {
131        assert_eq!(format!("{}", Interval::<i8>::empty()), "{}");
132
133        assert_eq!(format!("{}", Interval::<i8>::unbounded()), "(<-, ->)");
134    }
135
136    #[test]
137    fn test_display_set() {
138        assert_eq!(
139            format!(
140                "{}",
141                Interval::unbound_closed(-9.9)
142                    .union(&Interval::open(5.5, 9.9))
143                    .union(&Interval::closed_open(11.1, 22.2))
144                    .union(&Interval::open_unbound(33.3))
145            ),
146            "{(<-, -9.9], (5.5, 9.9), [11.1, 22.2), (33.3, ->)}"
147        )
148    }
149}