ts_io/
item_formatter.rs

1//! Formatting wrappers for a collection.
2
3use core::{
4    fmt::{Display, Formatter, Result},
5    marker::PhantomData,
6    slice::Iter,
7};
8
9/// Trait to mark a struct as iterable over `Item`.
10pub trait Iterable<Item> {
11    /// Get the iterator.
12    fn iter<'i>(&'i self) -> Iter<'i, Item>;
13}
14
15/// Trait to interpret a collection as an item formatter.
16pub trait AsItemFormatter<'c, I>: AsRef<[I]> + Sized
17where
18    I: 'c,
19{
20    /// Create an item formatter from self.
21    fn as_item_formatter<S, F>(&'c self, separator: S, fmt: F) -> ItemFormatter<'c, Self, I, F>
22    where
23        S: ToString,
24        F: Fn(&mut Formatter<'_>, &'c I) -> Result,
25    {
26        ItemFormatter::new(self, separator, fmt)
27    }
28}
29
30impl<Item, Collection> Iterable<Item> for Collection
31where
32    Collection: AsRef<[Item]>,
33{
34    fn iter<'i>(&'i self) -> Iter<'i, Item> {
35        self.as_ref().iter()
36    }
37}
38
39impl<'c, I, C> AsItemFormatter<'c, I> for C
40where
41    I: 'c,
42    C: AsRef<[I]> + Sized,
43{
44}
45
46/// A wrapper struct to display a collections items.
47pub struct ItemFormatter<'c, C, I, F>
48where
49    C: Iterable<I>,
50    I: 'c,
51    F: Fn(&mut Formatter<'_>, &'c I) -> Result,
52{
53    /// The formatter closure.
54    fmt: F,
55    /// The collection.
56    items: &'c C,
57    /// The separator for the items.
58    separator: String,
59    /// The item.
60    item: PhantomData<I>,
61}
62impl<'c, C, I, F> ItemFormatter<'c, C, I, F>
63where
64    C: Iterable<I>,
65    I: 'c,
66    F: Fn(&mut Formatter<'_>, &'c I) -> Result,
67{
68    /// Create a new item formatter.
69    pub fn new<S: ToString>(collection: &'c C, separator: S, fmt: F) -> Self {
70        Self {
71            fmt,
72            items: collection,
73            separator: separator.to_string(),
74            item: PhantomData,
75        }
76    }
77}
78
79impl<'c, C, I, F> Display for ItemFormatter<'c, C, I, F>
80where
81    C: Iterable<I>,
82    I: 'c,
83    F: Fn(&mut Formatter<'_>, &'c I) -> Result,
84{
85    fn fmt(&self, f: &mut Formatter<'_>) -> Result {
86        write!(f, "[")?;
87
88        let iter = self.items.iter();
89        let length = iter.len();
90        for (index, item) in iter.enumerate() {
91            (self.fmt)(f, item)?;
92            if !self.separator.is_empty() && index < length - 1 {
93                write!(f, "{}", self.separator)?;
94            }
95        }
96
97        write!(f, "]")?;
98        Ok(())
99    }
100}
101
102#[cfg(test)]
103mod test {
104    use crate::item_formatter::AsItemFormatter;
105
106    #[test]
107    fn test() {
108        let items = (0..128).collect::<Vec<_>>();
109
110        println!(
111            "{}",
112            items.as_item_formatter(", ", |f, item| write!(f, "0x{item:02x}"))
113        );
114    }
115}