fmt_tools/
fmt_list.rs

1use crate::fmt_display;
2use core::fmt::{self, Debug, Display, Formatter};
3
4/// [`Debug`] or [`Display`] a list of [`Debug`] objects as a list.
5pub struct FmtDebugList<F>
6where
7    F: ?Sized,
8{
9    values_fn: F,
10}
11
12impl<F> FmtDebugList<F> {
13    const fn new(values_fn: F) -> Self {
14        Self { values_fn }
15    }
16}
17
18impl<F, I> Debug for FmtDebugList<F>
19where
20    F: Fn() -> I + ?Sized,
21    I: IntoIterator,
22    I::Item: Debug,
23{
24    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
25        let entries = (self.values_fn)();
26
27        f.debug_list().entries(entries).finish()
28    }
29}
30
31/// [`Debug`] or [`Display`] a list of [`Display`] objects as a list.
32impl<F, I> Display for FmtDebugList<F>
33where
34    F: Fn() -> I + ?Sized,
35    I: IntoIterator,
36    I::Item: Debug,
37{
38    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
39        Debug::fmt(self, f)
40    }
41}
42
43/// [`Debug`] or [`Display`] a list of [`Display`] objects as a list.
44pub struct FmtDisplayList<F>
45where
46    F: ?Sized,
47{
48    values_fn: F,
49}
50
51impl<F> FmtDisplayList<F> {
52    const fn new(values_fn: F) -> Self {
53        Self { values_fn }
54    }
55}
56
57impl<F, I> Debug for FmtDisplayList<F>
58where
59    F: Fn() -> I + ?Sized,
60    I: IntoIterator,
61    I::Item: Display,
62{
63    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
64        let entries = (self.values_fn)().into_iter().map(fmt_display);
65
66        f.debug_list().entries(entries).finish()
67    }
68}
69
70impl<F, I> Display for FmtDisplayList<F>
71where
72    F: Fn() -> I + ?Sized,
73    I: IntoIterator,
74    I::Item: Display,
75{
76    fn fmt(&self, f: &mut Formatter) -> fmt::Result {
77        Debug::fmt(self, f)
78    }
79}
80
81/// Creates an object that [`Debug`] or [`Display`] a list of [`Debug`] objects as a list.
82///
83/// Example:
84///
85/// ```rust
86/// let fmt = fmt_tools::fmt_debug_list(|| 'a'..'g');
87///
88/// assert_eq!(format!("{fmt:?}"), "['a', 'b', 'c', 'd', 'e', 'f']");
89/// assert_eq!(format!("{fmt}"), "['a', 'b', 'c', 'd', 'e', 'f']");
90/// ```
91pub const fn fmt_debug_list<F, I>(values_fn: F) -> FmtDebugList<F>
92where
93    F: Fn() -> I,
94    I: IntoIterator,
95    I::Item: Debug,
96{
97    FmtDebugList::new(values_fn)
98}
99
100/// Creates an object that [`Debug`] or [`Display`] a list of [`Display`] objects as a list.
101///
102/// Example:
103///
104/// ```rust
105/// let fmt = fmt_tools::fmt_display_list(|| 'a'..'g');
106///
107/// assert_eq!(format!("{fmt:?}"), "[a, b, c, d, e, f]");
108/// assert_eq!(format!("{fmt}"), "[a, b, c, d, e, f]");
109/// ```
110pub const fn fmt_display_list<F, I>(values_fn: F) -> FmtDisplayList<F>
111where
112    F: Fn() -> I,
113    I: IntoIterator,
114    I::Item: Display,
115{
116    FmtDisplayList::new(values_fn)
117}
118
119#[cfg(test)]
120mod tests {
121    use super::{FmtDebugList, FmtDisplayList};
122    use core::fmt::{self, Display, Formatter};
123
124    #[test]
125    fn test_debug_fmt_list() {
126        #[derive(Debug)]
127        struct Foo;
128
129        #[allow(trivial_casts)]
130        let test_cases = [
131            (&[] as &[Foo], "[]"),
132            (&[Foo], "[Foo]"),
133            (&[Foo, Foo], "[Foo, Foo]"),
134            (&[Foo, Foo, Foo], "[Foo, Foo, Foo]"),
135        ];
136
137        for (values, expected) in test_cases {
138            let fmt = super::fmt_debug_list(|| values);
139            let unsized_fmt: &FmtDebugList<dyn Fn() -> &'static [Foo]> = &fmt;
140
141            assert_eq!(std::format!("{fmt:?}"), expected);
142            assert_eq!(std::format!("{fmt}"), expected);
143            assert_eq!(std::format!("{unsized_fmt:?}"), expected);
144            assert_eq!(std::format!("{unsized_fmt}"), expected);
145        }
146    }
147
148    #[test]
149    fn test_display_fmt_list() {
150        struct Foo;
151
152        impl Display for Foo {
153            fn fmt(&self, f: &mut Formatter) -> fmt::Result {
154                f.write_str("item")
155            }
156        }
157
158        #[allow(trivial_casts)]
159        let test_cases = [
160            (&[] as &[Foo], "[]"),
161            (&[Foo], "[item]"),
162            (&[Foo, Foo], "[item, item]"),
163            (&[Foo, Foo, Foo], "[item, item, item]"),
164        ];
165
166        for (values, expected) in test_cases {
167            let fmt = super::fmt_display_list(|| values);
168            let unsized_fmt: &FmtDisplayList<dyn Fn() -> &'static [Foo]> = &fmt;
169
170            assert_eq!(std::format!("{fmt:?}"), expected);
171            assert_eq!(std::format!("{fmt}"), expected);
172            assert_eq!(std::format!("{unsized_fmt:?}"), expected);
173            assert_eq!(std::format!("{unsized_fmt}"), expected);
174        }
175    }
176}