smart_string/display_ext/
mod.rs

1use std::fmt;
2use std::io;
3
4use crate::PascalString;
5
6pub trait DisplayExt {
7    fn is_empty(&self) -> bool;
8
9    fn write_to_fmt<W: fmt::Write>(&self, writer: W) -> fmt::Result;
10
11    fn write_to_bytes<W: io::Write>(&self, writer: W) -> fmt::Result;
12
13    fn try_to_fmt<T: fmt::Write + Default>(&self) -> Result<T, T> {
14        let mut writer = T::default();
15        match self.write_to_fmt(&mut writer) {
16            Ok(_) => Ok(writer),
17            Err(_err) => Err(writer),
18        }
19    }
20
21    fn try_to_bytes<T: io::Write + Default>(&self) -> Result<T, T> {
22        let mut writer = T::default();
23        match self.write_to_bytes(&mut writer) {
24            Ok(_) => Ok(writer),
25            Err(_err) => Err(writer),
26        }
27    }
28
29    fn to_fmt<T: fmt::Write + Default>(&self) -> T {
30        self.try_to_fmt()
31            .unwrap_or_else(|_writer| panic!("Failed to write to target"))
32    }
33
34    fn to_bytes<T: io::Write + Default>(&self) -> T {
35        self.try_to_bytes()
36            .unwrap_or_else(|_writer| panic!("Failed to write to target"))
37    }
38
39    fn format_with<F>(&self, f: F) -> fmt::Result
40    where
41        F: FnMut(Option<&str>) -> fmt::Result;
42}
43
44impl<T> DisplayExt for T
45where
46    T: fmt::Display + ?Sized,
47{
48    fn is_empty(&self) -> bool {
49        self.write_to_fmt(PascalString::<0>::new()).is_ok()
50    }
51
52    fn write_to_fmt<W: fmt::Write>(&self, mut writer: W) -> fmt::Result {
53        write!(writer, "{}", self)
54    }
55
56    fn write_to_bytes<W: io::Write>(&self, mut writer: W) -> fmt::Result {
57        writer
58            .write_fmt(format_args!("{}", self))
59            .map_err(|_| fmt::Error)
60    }
61
62    #[inline]
63    fn format_with<F>(&self, mut cb: F) -> fmt::Result
64    where
65        F: FnMut(Option<&str>) -> fmt::Result,
66    {
67        use fmt::Write;
68
69        struct CallbackWrapper<F>(F);
70
71        impl<F> Write for CallbackWrapper<F>
72        where
73            F: FnMut(Option<&str>) -> fmt::Result,
74        {
75            #[inline]
76            fn write_str(&mut self, s: &str) -> fmt::Result {
77                (self.0)(Some(s))
78            }
79        }
80
81        CallbackWrapper(&mut cb).write_fmt(format_args!("{}", self))?;
82        (cb)(None)
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89
90    struct Maybe<T>(Option<T>);
91
92    impl<T: fmt::Display> fmt::Display for Maybe<T> {
93        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
94            if let Some(t) = &self.0 {
95                t.fmt(f)?
96            }
97            Ok(())
98        }
99    }
100
101    fn is_empty(display: impl fmt::Display) -> bool {
102        display.is_empty()
103    }
104
105    #[test]
106    fn test_is_empty() {
107        assert!(is_empty(""));
108        assert!(!is_empty("Hello"));
109
110        assert!(is_empty("".to_string()));
111        assert!(!is_empty("Hello".to_string()));
112
113        assert!(is_empty(&"" as &dyn fmt::Display));
114        assert!(!is_empty(&"Hello" as &dyn fmt::Display));
115
116        assert!(is_empty(&"".to_string() as &dyn fmt::Display));
117        assert!(!is_empty(&"Hello".to_string() as &dyn fmt::Display));
118
119        assert!(is_empty(Maybe(None::<&str>)));
120        assert!(is_empty(Maybe(Some(""))));
121        assert!(!is_empty(Maybe(Some("Hello"))));
122    }
123
124    #[test]
125    fn test_to_fmt() {
126        assert_eq!("".to_fmt::<PascalString<0>>(), "");
127        assert_eq!("", "".to_fmt::<PascalString<0>>());
128        assert_eq!("Hello", "Hello".to_fmt::<PascalString<255>>());
129        assert_eq!("Hello", "Hello".try_to_fmt::<PascalString<255>>().unwrap());
130        assert!("".try_to_fmt::<PascalString<4>>().is_ok());
131        assert!("Hello".try_to_fmt::<PascalString<4>>().is_err());
132    }
133
134    #[test]
135    #[should_panic]
136    fn test_to_fmt_panic() {
137        "Hello".to_fmt::<PascalString<4>>();
138    }
139}