Skip to main content

smart_format/iter/
mod.rs

1use core::fmt;
2
3mod concat;
4mod join;
5
6pub use concat::Concat;
7pub use join::Join;
8
9/// Extension trait for iterators of `Display` items.
10///
11/// Adds `display_concat()` and `display_join()` to any iterator whose items implement
12/// `Display`. Both methods return lazy wrappers that themselves implement `Display`,
13/// so no allocation happens until someone writes the result to a formatter or calls
14/// `.to_string()`.
15///
16/// # Design note
17///
18/// The trait requires `Iterator + Clone` (not `IntoIterator`) because `Display::fmt`
19/// takes `&self` — it cannot consume the iterator. The wrapper clones the iterator on
20/// each `fmt` call. For typical iterators (slice iterators, `std::iter::Copied`, etc.)
21/// this clone is two pointer copies — effectively free.
22pub trait DisplayIterator: Iterator + Clone
23where
24    Self::Item: fmt::Display,
25{
26    fn display_concat(self) -> Concat<Self>
27    where
28        Self: Sized,
29    {
30        Concat::new(self)
31    }
32
33    fn display_join<S>(self, sep: S) -> Join<Self, S>
34    where
35        Self: Sized,
36        S: fmt::Display,
37    {
38        Join::new(self, sep)
39    }
40}
41
42impl<I> DisplayIterator for I
43where
44    I: Iterator + Clone,
45    I::Item: fmt::Display,
46{
47}
48
49#[cfg(test)]
50mod tests {
51    use super::*;
52
53    pub const SOURCE_STR: [&str; 4] = [
54        "Sirius",
55        "Canopus",
56        "Rigil Kentaurus & Toliman",
57        "Arcturus ",
58    ];
59    pub const CONCAT_SAMPLE_STR: &str = "SiriusCanopusRigil Kentaurus & TolimanArcturus ";
60    pub const JOIN_SAMPLE_STR: &str = "Sirius, Canopus, Rigil Kentaurus & Toliman, Arcturus ";
61
62    pub const SOURCE_NUM: [u32; 3] = [1, 2, 3];
63    pub const CONCAT_SAMPLE_NUM: &str = "123";
64    pub const JOIN_SAMPLE_NUM: &str = "1, 2, 3";
65
66    #[test]
67    fn it_concats_str() {
68        assert_eq!(
69            CONCAT_SAMPLE_STR,
70            SOURCE_STR.iter().display_concat().to_string()
71        );
72    }
73
74    #[test]
75    fn it_concats_num() {
76        assert_eq!(
77            CONCAT_SAMPLE_NUM,
78            SOURCE_NUM.iter().display_concat().to_string()
79        );
80    }
81
82    #[test]
83    fn it_joins_str() {
84        assert_eq!(
85            JOIN_SAMPLE_STR,
86            SOURCE_STR.iter().display_join(", ").to_string()
87        );
88    }
89
90    #[test]
91    fn it_joins_num() {
92        assert_eq!(
93            JOIN_SAMPLE_NUM,
94            SOURCE_NUM.iter().display_join(", ").to_string()
95        );
96    }
97}