1use std::fmt;
2
3pub struct SpaceSep<I>(pub I);
4pub struct PerLine<I>(pub I);
5pub struct StrSep<'a, I>(pub I, pub &'a str);
6
7pub struct SpaceSepUsize1<I>(pub I);
8pub struct PerLineUsize1<I>(pub I);
9pub struct StrSepUsize1<'a, I>(pub I, pub &'a str);
10
11macro_rules! impl_fmt {
12 ( $( $fmt:ident )* ) => { $(
13 #[allow(non_snake_case)]
14 fn $fmt<I, T: fmt::$fmt>(iter: I, sep: &str, f: &mut fmt::Formatter<'_>) -> fmt::Result
15 where
16 I: IntoIterator<Item = T>,
17 {
18 let mut iter = iter.into_iter();
19 if let Some(first) = iter.by_ref().next() {
20 first.fmt(f)?;
21 }
22 iter.map(|rest| { write!(f, "{}", sep)?; rest.fmt(f) }).collect()
23 }
24
25 impl<I, T: fmt::$fmt> fmt::$fmt for SpaceSep<I>
26 where
27 I: IntoIterator<Item = T> + Clone,
28 {
29 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
30 $fmt(self.0.clone(), " ", f)
31 }
32 }
33 impl<I, T: fmt::$fmt> fmt::$fmt for PerLine<I>
34 where
35 I: IntoIterator<Item = T> + Clone,
36 {
37 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
38 $fmt(self.0.clone(), "\n", f)
39 }
40 }
41 impl<I, T: fmt::$fmt> fmt::$fmt for StrSep<'_, I>
42 where
43 I: IntoIterator<Item = T> + Clone,
44 {
45 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46 $fmt(self.0.clone(), self.1, f)
47 }
48 }
49 )* }
50}
51
52macro_rules! impl_fmt_usize1 {
53 ( $( $fmt:ident )* ) => { $(
54 impl<I, T> fmt::$fmt for SpaceSepUsize1<I>
55 where
56 I: IntoIterator<Item = T> + Clone,
57 T: std::ops::Add<usize, Output = usize>,
58 {
59 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
60 $fmt(self.0.clone().into_iter().map(|u| u + 1), " ", f)
61 }
62 }
63 impl<I, T> fmt::$fmt for PerLineUsize1<I>
64 where
65 I: IntoIterator<Item = T> + Clone,
66 T: std::ops::Add<usize, Output = usize>,
67 {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 $fmt(self.0.clone().into_iter().map(|u| u + 1), "\n", f)
70 }
71 }
72 impl<I, T> fmt::$fmt for StrSepUsize1<'_, I>
73 where
74 I: IntoIterator<Item = T> + Clone,
75 T: std::ops::Add<usize, Output = usize>,
76 {
77 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
78 $fmt(self.0.clone().into_iter().map(|u| u + 1), self.1, f)
79 }
80 }
81)* }
82}
83
84impl_fmt! { Binary Debug Display LowerExp LowerHex Octal Pointer UpperExp UpperHex }
85impl_fmt_usize1! { Debug Display LowerHex Octal UpperHex }
86
87#[test]
88fn sanity_check() {
89 let a = [0, 1, 2];
90 assert_eq!(format!("{}", StrSep(&a[..0], "_")), "");
91 assert_eq!(format!("{}", StrSep(&a[..1], "_")), "0");
92 assert_eq!(format!("{}", StrSep(&a[..2], "_")), "0_1");
93 assert_eq!(format!("{}", StrSep(&a, "_")), "0_1_2");
94
95 assert_eq!(format!("{}", SpaceSep(&a[..0])), "");
96 assert_eq!(format!("{}", SpaceSep(&a[..1])), "0");
97 assert_eq!(format!("{}", SpaceSep(&a[..2])), "0 1");
98 assert_eq!(format!("{}", SpaceSep(&a)), "0 1 2");
99
100 assert_eq!(format!("{}", PerLine(&a[..0])), "");
101 assert_eq!(format!("{}", PerLine(&a[..1])), "0");
102 assert_eq!(format!("{}", PerLine(&a[..2])), "0\n1");
103 assert_eq!(format!("{}", PerLine(&a)), "0\n1\n2");
104}
105
106#[test]
107fn iter() {
108 assert_eq!(format!("{}", SpaceSep(0..5)), "0 1 2 3 4");
109 assert_eq!(
110 format!("{}", SpaceSep([0, 1, 2].iter().map(|x| x * 100))),
111 "0 100 200"
112 );
113}
114
115#[test]
116fn formatting() {
117 let int = [3, 14, 1, 59];
118 assert_eq!(format!("({})", SpaceSep(&int)), "(3 14 1 59)");
119 assert_eq!(format!("{:2}", SpaceSep(&int)), " 3 14 1 59");
120 assert_eq!(format!("{:<2}", SpaceSep(&int)), "3 14 1 59");
121 assert_eq!(format!("{:o}", SpaceSep(&int)), "3 16 1 73");
122 assert_eq!(format!("{:x}", SpaceSep(&int)), "3 e 1 3b");
123 assert_eq!(format!("{:#04x}", SpaceSep(&int)), "0x03 0x0e 0x01 0x3b");
124 assert_eq!(
125 format!("{:08b}", SpaceSep(&int)),
126 "00000011 00001110 00000001 00111011"
127 );
128
129 let ch = ['a', '\0', '\n', char::MAX];
130 assert_eq!(format!("{}", SpaceSep(&ch)), "a \0 \n \u{10ffff}");
131 assert_eq!(format!("{:?}", SpaceSep(&ch)), r"'a' '\0' '\n' '\u{10ffff}'");
132 assert_eq!(format!("{:#?}", SpaceSep(&ch)), r"'a' '\0' '\n' '\u{10ffff}'");
133
134 let nested = [[1, 2], [3, 4]];
135 assert_eq!(
136 format!("\n{:?}", PerLine(&nested)),
137 r"
138[1, 2]
139[3, 4]"
140 );
141 assert_eq!(
142 format!("\n{:#?}", PerLine(&nested)),
143 r"
144[
145 1,
146 2,
147]
148[
149 3,
150 4,
151]"
152 );
153
154 let float = [0.1, 2.34, f64::INFINITY, f64::NAN];
155 assert_eq!(format!("{:4}", SpaceSep(&float)), " 0.1 2.34 inf NaN");
156 assert_eq!(format!("{:0.2}", SpaceSep(&float)), "0.10 2.34 inf NaN");
157}
158
159#[test]
160fn usize1() {
161 assert_eq!(format!("{}", SpaceSepUsize1([0, 3, 1, 4, 2])), "1 4 2 5 3");
162 let a = vec![0, 3, 1, 4, 2];
163 assert_eq!(format!("{}", SpaceSepUsize1(&a)), "1 4 2 5 3");
164 assert_eq!(format!("{}", SpaceSepUsize1(a)), "1 4 2 5 3");
165}