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}