smart_string/display_ext/
mod.rs1use 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}