1use std::fmt;
65use std::fmt::Display;
66use std::fmt::Write;
67
68use either::Either;
69
70const INDENT: &str = " ";
71
72fn subwriter<T: Display>(indent: &'static str, f: &mut fmt::Formatter, v: T) -> fmt::Result {
74 if f.alternate() {
75 write!(indenter::indented(f).with_str(indent), "{:#}", &v)
76 } else {
77 Display::fmt(&v, f)
78 }
79}
80
81enum Len {
83 Zero,
84 One,
85 Many, }
87
88pub fn display_pair<'a, K: Display + 'a, V: Display + 'a>(
92 key: K,
93 separator: &'a str,
94 value: V,
95) -> impl Display + 'a {
96 DisplayPair(key, separator, value)
97}
98
99struct DisplayPair<'a, K: Display, V: Display>(pub K, pub &'a str, pub V);
100
101impl<K: Display, V: Display> Display for DisplayPair<'_, K, V> {
102 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
103 Display::fmt(&self.0, f)?;
104 f.write_str(self.1)?;
105 Display::fmt(&self.2, f)
106 }
107}
108
109struct ContainerDisplayHelper<'a, 'b> {
111 f: &'a mut fmt::Formatter<'b>,
112 separator: &'static str,
114 outer: &'static str,
116 indent: &'static str,
118 seen_items: usize,
120}
121
122impl<'a, 'b> ContainerDisplayHelper<'a, 'b> {
123 fn begin_inner(
125 f: &'a mut fmt::Formatter<'b>,
126 prefix: &str,
127 num_items: Len,
128 ) -> Result<Self, fmt::Error> {
129 let (separator, outer, indent) = match (f.alternate(), num_items) {
130 (false, _) => (", ", "", ""),
132 (true, Len::Zero) => ("", "", ""),
134 (true, Len::One) => ("", " ", ""),
136 _ => (",\n", "\n", INDENT),
144 };
145 f.write_str(prefix)?;
146 f.write_str(outer)?;
147
148 Ok(Self {
149 f,
150 separator,
151 outer,
152 indent,
153 seen_items: 0,
154 })
155 }
156
157 pub fn item<T: Display>(&mut self, v: T) -> fmt::Result {
159 if self.seen_items != 0 {
160 self.f.write_str(self.separator)?;
161 }
162 self.seen_items += 1;
163 subwriter(self.indent, self.f, &v)
164 }
165
166 pub fn end(self, suffix: &str) -> fmt::Result {
168 self.f.write_str(self.outer)?;
169 self.f.write_str(suffix)
170 }
171}
172
173pub fn fmt_container<T: Display, Iter: IntoIterator<Item = T>>(
175 f: &mut fmt::Formatter,
176 prefix: &str,
177 suffix: &str,
178 items: Iter,
179) -> fmt::Result {
180 let mut items = items.into_iter();
181 let helper = match items.next() {
182 None => ContainerDisplayHelper::begin_inner(f, prefix, Len::Zero)?,
183 Some(first) => match items.next() {
184 None => {
185 let mut helper = ContainerDisplayHelper::begin_inner(f, prefix, Len::One)?;
186 helper.item(first)?;
187 helper
188 }
189 Some(second) => {
190 let mut helper = ContainerDisplayHelper::begin_inner(f, prefix, Len::Many)?;
191 helper.item(first)?;
192 helper.item(second)?;
193 for v in items {
194 helper.item(v)?;
195 }
196 helper
197 }
198 },
199 };
200 helper.end(suffix)
201}
202
203pub fn display_container<'a, C>(prefix: &'a str, suffix: &'a str, items: C) -> impl Display + 'a
205where
206 C: Copy + IntoIterator + 'a,
207 <C as IntoIterator>::Item: Display,
208{
209 struct Impl<'a, C> {
210 prefix: &'a str,
211 suffix: &'a str,
212 items: C,
213 }
214 impl<C> Display for Impl<'_, C>
215 where
216 C: Copy + IntoIterator,
217 <C as IntoIterator>::Item: Display,
218 {
219 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
220 fmt_container(f, self.prefix, self.suffix, self.items)
221 }
222 }
223 Impl {
224 prefix,
225 suffix,
226 items,
227 }
228}
229
230pub fn fmt_keyed_container<K: Display, V: Display, Iter: IntoIterator<Item = (K, V)>>(
234 f: &mut fmt::Formatter,
235 prefix: &str,
236 suffix: &str,
237 separator: &str,
238 items: Iter,
239) -> fmt::Result {
240 fmt_container(
241 f,
242 prefix,
243 suffix,
244 items
245 .into_iter()
246 .map(|(k, v)| display_pair(k, separator, v)),
247 )
248}
249
250pub fn iter_display_chain<A, B>(first: A, second: B) -> impl Iterator<Item = impl Display>
252where
253 A: IntoIterator,
254 A::Item: Display,
255 B: IntoIterator,
256 B::Item: Display,
257{
258 first
259 .into_iter()
260 .map(Either::Left)
261 .chain(second.into_iter().map(Either::Right))
262}
263
264#[cfg(test)]
265mod tests {
266 use super::*;
267
268 #[test]
269 fn test_container() {
270 struct Wrapped(Vec<u32>);
271 impl fmt::Display for Wrapped {
272 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
273 fmt_container(f, "prefix[", "]", self.0.iter())
274 }
275 }
276
277 assert_eq!("prefix[]", format!("{:}", Wrapped(vec![])));
278 assert_eq!("prefix[1]", format!("{:}", Wrapped(vec![1])));
279 assert_eq!("prefix[1, 2]", format!("{:}", Wrapped(vec![1, 2])));
280 assert_eq!("prefix[1, 2, 3]", format!("{:}", Wrapped(vec![1, 2, 3])));
281
282 assert_eq!("prefix[]", format!("{:#}", Wrapped(vec![])));
283 assert_eq!("prefix[ 1 ]", format!("{:#}", Wrapped(vec![1])));
284 assert_eq!(
285 "prefix[\n 1,\n 2\n]",
286 format!("{:#}", Wrapped(vec![1, 2])),
287 );
288 assert_eq!(
289 "prefix[\n 1,\n 2,\n 3\n]",
290 format!("{:#}", Wrapped(vec![1, 2, 3])),
291 );
292 }
293
294 #[test]
295 fn test_keyed_container() {
296 struct Wrapped(Vec<(u32, &'static str)>);
297 impl fmt::Display for Wrapped {
298 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
299 fmt_keyed_container(
300 f,
301 "prefix[",
302 "]",
303 ": ",
304 self.0.iter().map(|(k, v)| (k, format!("\"{v}\""))),
306 )
307 }
308 }
309
310 assert_eq!("prefix[]", format!("{:}", Wrapped(vec![])));
311 assert_eq!("prefix[1: \"1\"]", format!("{:}", Wrapped(vec![(1, "1")])));
312 assert_eq!(
313 "prefix[1: \"1\", 2: \"2\"]",
314 format!("{:}", Wrapped(vec![(1, "1"), (2, "2")])),
315 );
316 assert_eq!(
317 "prefix[1: \"1\", 2: \"2\", 3: \"3\"]",
318 format!("{:}", Wrapped(vec![(1, "1"), (2, "2"), (3, "3")])),
319 );
320
321 assert_eq!("prefix[]", format!("{:#}", Wrapped(vec![])));
322 assert_eq!(
323 "prefix[ 1: \"1\" ]",
324 format!("{:#}", Wrapped(vec![(1, "1")]))
325 );
326 assert_eq!(
327 "prefix[\n 1: \"1\",\n 2: \"2\"\n]",
328 format!("{:#}", Wrapped(vec![(1, "1"), (2, "2")])),
329 );
330 assert_eq!(
331 "prefix[\n 1: \"1\",\n 2: \"2\",\n 3: \"3\"\n]",
332 format!("{:#}", Wrapped(vec![(1, "1"), (2, "2"), (3, "3")])),
333 );
334 }
335
336 #[test]
337 fn test_combinators() {
338 struct MyItems(Vec<(String, i32)>);
339 impl fmt::Display for MyItems {
340 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
341 fmt_container(
342 f,
343 "{",
344 "}",
345 iter_display_chain(
346 &["magic"],
347 self.0.iter().map(|(k, v)| display_pair(k, "=", v)),
348 ),
349 )
350 }
351 }
352 assert_eq!(
353 MyItems(vec![("hello".to_owned(), 1), ("world".to_owned(), 2)]).to_string(),
354 "{magic, hello=1, world=2}"
355 );
356 }
357
358 #[test]
359 fn test_display_container() {
360 assert_eq!("[1]", display_container("[", "]", &vec![1]).to_string());
361 }
362}