fmt_tools/
fmt_set.rs

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