1use core::fmt::{self, Debug, Display, Formatter};
2
3struct Inner<F, S>
4where
5 F: ?Sized,
6{
7 separator: S,
8 values_fn: F,
9}
10
11impl<F, S> Inner<F, S>
12where
13 F: ?Sized,
14{
15 const fn new(values_fn: F, separator: S) -> Self
16 where
17 F: Sized,
18 {
19 Self { separator, values_fn }
20 }
21
22 fn fmt_with<I>(
23 &self,
24 f: &mut Formatter,
25 value_writer: impl FnOnce(&I::Item, &mut Formatter) -> fmt::Result + Copy,
26 separator_writer: impl FnOnce(&S, &mut Formatter) -> fmt::Result + Copy,
27 ) -> fmt::Result
28 where
29 F: Fn() -> I,
30 I: IntoIterator,
31 {
32 let mut iter = (self.values_fn)().into_iter();
33
34 if let Some(first) = iter.next() {
35 value_writer(&first, f)?;
36
37 for item in iter {
38 separator_writer(&self.separator, f)?;
39 value_writer(&item, f)?;
40 }
41 }
42
43 Ok(())
44 }
45}
46
47pub struct FmtSeparatedDebugList<F, S>
49where
50 F: ?Sized,
51{
52 inner: Inner<F, S>,
53}
54
55impl<F, S> FmtSeparatedDebugList<F, S> {
56 const fn new(values_fn: F, separator: S) -> Self
57 where
58 F: Sized,
59 {
60 Self {
61 inner: Inner::new(values_fn, separator),
62 }
63 }
64}
65
66impl<F, S, I> Debug for FmtSeparatedDebugList<F, S>
67where
68 F: Fn() -> I + ?Sized,
69 I: IntoIterator,
70 I::Item: Debug,
71 S: Debug,
72{
73 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
74 self.inner.fmt_with(f, I::Item::fmt, S::fmt)
75 }
76}
77
78impl<F, S, I> Display for FmtSeparatedDebugList<F, S>
79where
80 F: Fn() -> I + ?Sized,
81 I: IntoIterator,
82 I::Item: Debug,
83 S: Debug,
84{
85 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
86 Debug::fmt(self, f)
87 }
88}
89
90pub struct FmtSeparatedDisplayList<F, S>
92where
93 F: ?Sized,
94{
95 inner: Inner<F, S>,
96}
97
98impl<F, S> FmtSeparatedDisplayList<F, S> {
99 const fn new(values_fn: F, separator: S) -> Self
100 where
101 F: Sized,
102 {
103 Self {
104 inner: Inner::new(values_fn, separator),
105 }
106 }
107}
108
109impl<F, S, I> Debug for FmtSeparatedDisplayList<F, S>
110where
111 F: Fn() -> I + ?Sized,
112 I: IntoIterator,
113 I::Item: Display,
114 S: Display,
115{
116 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
117 self.inner.fmt_with(f, I::Item::fmt, S::fmt)
118 }
119}
120
121impl<F, S, I> Display for FmtSeparatedDisplayList<F, S>
122where
123 F: Fn() -> I + ?Sized,
124 I: IntoIterator,
125 I::Item: Display,
126 S: Display,
127{
128 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
129 Debug::fmt(self, f)
130 }
131}
132
133pub const fn fmt_separated_debug_list<F, S, I>(values_fn: F, separator: S) -> FmtSeparatedDebugList<F, S>
145where
146 F: Fn() -> I,
147 I: IntoIterator,
148 I::Item: Debug,
149 S: Debug,
150{
151 FmtSeparatedDebugList::new(values_fn, separator)
152}
153
154pub const fn fmt_separated_display_list<F, S, I>(values_fn: F, separator: S) -> FmtSeparatedDisplayList<F, S>
166where
167 F: Fn() -> I,
168 I: IntoIterator,
169 I::Item: Display,
170 S: Display,
171{
172 FmtSeparatedDisplayList::new(values_fn, separator)
173}
174
175#[cfg(test)]
176mod tests {
177 use super::{FmtSeparatedDebugList, FmtSeparatedDisplayList};
178 use core::fmt::{self, Display, Formatter};
179
180 #[test]
181 fn test_debug_separated_list() {
182 #[derive(Debug)]
183 struct Foo;
184
185 #[derive(Debug)]
186 struct Bar;
187
188 #[allow(trivial_casts)]
189 let test_cases = [
190 (&[] as &[Foo], ""),
191 (&[Foo], "Foo"),
192 (&[Foo, Foo], "FooBarFoo"),
193 (&[Foo, Foo, Foo], "FooBarFooBarFoo"),
194 ];
195
196 for (values, expected) in test_cases {
197 let fmt = super::fmt_separated_debug_list(|| values, Bar);
198 let unsized_fmt: &FmtSeparatedDebugList<dyn Fn() -> &'static [Foo], Bar> = &fmt;
199
200 assert_eq!(std::format!("{fmt:?}"), expected);
201 assert_eq!(std::format!("{fmt}"), expected);
202 assert_eq!(std::format!("{unsized_fmt:?}"), expected);
203 assert_eq!(std::format!("{unsized_fmt}"), expected);
204 }
205 }
206
207 #[test]
208 fn test_display_separated_list() {
209 struct Foo;
210
211 impl Display for Foo {
212 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
213 f.write_str("item")
214 }
215 }
216
217 struct Bar;
218
219 impl Display for Bar {
220 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
221 f.write_str(", ")
222 }
223 }
224
225 #[allow(trivial_casts)]
226 let test_cases = [
227 (&[] as &[Foo], ""),
228 (&[Foo], "item"),
229 (&[Foo, Foo], "item, item"),
230 (&[Foo, Foo, Foo], "item, item, item"),
231 ];
232
233 for (values, expected) in test_cases {
234 let fmt = super::fmt_separated_display_list(|| values, Bar);
235 let unsized_fmt: &FmtSeparatedDisplayList<dyn Fn() -> &'static [Foo], Bar> = &fmt;
236
237 assert_eq!(std::format!("{fmt:?}"), expected);
238 assert_eq!(std::format!("{fmt}"), expected);
239 assert_eq!(std::format!("{unsized_fmt:?}"), expected);
240 assert_eq!(std::format!("{unsized_fmt}"), expected);
241 }
242 }
243}