1use crate::{fmt_display, FmtDisplay};
2use core::fmt::{self, Debug, Display, Formatter};
3
4pub struct FmtDebugMap<F>
6where
7 F: ?Sized,
8{
9 values_fn: F,
10}
11
12impl<F> FmtDebugMap<F> {
13 const fn new(values_fn: F) -> Self {
14 Self { values_fn }
15 }
16}
17
18impl<F, I, K, V> Debug for FmtDebugMap<F>
19where
20 F: Fn() -> I + ?Sized,
21 I: IntoIterator<Item = (K, V)>,
22 K: Debug,
23 V: Debug,
24{
25 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
26 let entries = (self.values_fn)();
27
28 f.debug_map().entries(entries).finish()
29 }
30}
31
32impl<F, I, K, V> Display for FmtDebugMap<F>
33where
34 F: Fn() -> I + ?Sized,
35 I: IntoIterator<Item = (K, V)>,
36 K: Debug,
37 V: Debug,
38{
39 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
40 Debug::fmt(self, f)
41 }
42}
43
44pub struct FmtDisplayMap<F>
46where
47 F: ?Sized,
48{
49 values_fn: F,
50}
51
52impl<F> FmtDisplayMap<F> {
53 const fn new(values_fn: F) -> Self {
54 Self { values_fn }
55 }
56}
57
58impl<F, I, K, V> Debug for FmtDisplayMap<F>
59where
60 F: Fn() -> I + ?Sized,
61 I: IntoIterator<Item = (K, V)>,
62 K: Display,
63 V: Display,
64{
65 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
66 fn display_as_debug<K, V>((key, value): (K, V)) -> (FmtDisplay<K>, FmtDisplay<V>)
67 where
68 K: Display,
69 V: Display,
70 {
71 (fmt_display(key), fmt_display(value))
72 }
73
74 let entries = (self.values_fn)().into_iter().map(display_as_debug);
75
76 f.debug_map().entries(entries).finish()
77 }
78}
79
80impl<F, I, K, V> Display for FmtDisplayMap<F>
81where
82 F: Fn() -> I + ?Sized,
83 I: IntoIterator<Item = (K, V)>,
84 K: Display,
85 V: Display,
86{
87 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
88 Debug::fmt(self, f)
89 }
90}
91
92pub const fn fmt_debug_map<F, I, K, V>(values_fn: F) -> FmtDebugMap<F>
103where
104 F: Fn() -> I,
105 I: IntoIterator<Item = (K, V)>,
106 K: Debug,
107 V: Debug,
108{
109 FmtDebugMap::new(values_fn)
110}
111
112pub const fn fmt_display_map<F, I, K, V>(values_fn: F) -> FmtDisplayMap<F>
123where
124 F: Fn() -> I,
125 I: IntoIterator<Item = (K, V)>,
126 K: Display,
127 V: Display,
128{
129 FmtDisplayMap::new(values_fn)
130}
131
132#[cfg(test)]
133mod tests {
134 use super::{FmtDebugMap, FmtDisplayMap};
135 use core::fmt::{self, Display, Formatter};
136
137 #[test]
138 fn test_debug_fmt_map() {
139 #[derive(Debug)]
140 struct Foo;
141
142 #[derive(Debug)]
143 struct Bar;
144
145 #[allow(trivial_casts)]
146 let test_cases = [
147 (&[] as &[(Foo, Bar)], "{}"),
148 (&[(Foo, Bar)], "{Foo: Bar}"),
149 (&[(Foo, Bar), (Foo, Bar)], "{Foo: Bar, Foo: Bar}"),
150 (&[(Foo, Bar), (Foo, Bar), (Foo, Bar)], "{Foo: Bar, Foo: Bar, Foo: Bar}"),
151 ];
152
153 for (values, expected) in test_cases {
154 let fmt_map = super::fmt_debug_map(|| values.iter().map(|(key, value)| (key, value)));
155 let unsized_fmt_map: &FmtDebugMap<dyn Fn() -> _> = &fmt_map;
156
157 assert_eq!(std::format!("{fmt_map:?}"), expected);
158 assert_eq!(std::format!("{fmt_map}"), expected);
159 assert_eq!(std::format!("{unsized_fmt_map:?}"), expected);
160 assert_eq!(std::format!("{unsized_fmt_map}"), expected);
161 }
162 }
163
164 #[test]
165 fn test_display_fmt_map() {
166 struct Foo;
167
168 impl Display for Foo {
169 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
170 f.write_str("foo")
171 }
172 }
173
174 struct Bar;
175
176 impl Display for Bar {
177 fn fmt(&self, f: &mut Formatter) -> fmt::Result {
178 f.write_str("bar")
179 }
180 }
181
182 #[allow(trivial_casts)]
183 let test_cases = [
184 (&[] as &[(Foo, Bar)], "{}"),
185 (&[(Foo, Bar)], "{foo: bar}"),
186 (&[(Foo, Bar), (Foo, Bar)], "{foo: bar, foo: bar}"),
187 (&[(Foo, Bar), (Foo, Bar), (Foo, Bar)], "{foo: bar, foo: bar, foo: bar}"),
188 ];
189
190 for (values, expected) in test_cases {
191 let fmt_map = super::fmt_display_map(|| values.iter().map(|(key, value)| (key, value)));
192 let unsized_fmt_map: &FmtDisplayMap<dyn Fn() -> _> = &fmt_map;
193
194 assert_eq!(std::format!("{fmt_map:?}"), expected);
195 assert_eq!(std::format!("{fmt_map}"), expected);
196 assert_eq!(std::format!("{unsized_fmt_map:?}"), expected);
197 assert_eq!(std::format!("{unsized_fmt_map}"), expected);
198 }
199 }
200}