1use core::{convert::Infallible, fmt::Debug};
2
3use embedded_io::{Error, ErrorType, Write};
4use ufmt::uWrite;
5
6use crate::codes;
7
8pub struct Writer<'a, W: Write<Error = E>, E: Error> {
9 last_bytes: [u8; 2],
10 dirty: bool,
11 writer: &'a mut W,
12}
13
14impl<'a, W: Write<Error = E>, E: Error> Debug for Writer<'a, W, E> {
15 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
16 f.debug_struct("Writer")
17 .field("last_bytes", &self.last_bytes)
18 .field("dirty", &self.dirty)
19 .finish()
20 }
21}
22
23impl<'a, W: Write<Error = E>, E: Error> Writer<'a, W, E> {
24 pub fn new(writer: &'a mut W) -> Self {
25 Self {
26 last_bytes: [0; 2],
27 dirty: false,
28 writer,
29 }
30 }
31
32 pub(crate) fn is_dirty(&self) -> bool {
33 self.dirty
34 && (self.last_bytes[0] != codes::CARRIAGE_RETURN
35 || self.last_bytes[1] != codes::LINE_FEED)
36 }
37
38 pub fn write_str(&mut self, mut text: &str) -> Result<(), E> {
39 while !text.is_empty() {
40 if let Some(pos) = text.as_bytes().iter().position(|&b| b == codes::LINE_FEED) {
41 let line = unsafe { text.get_unchecked(..pos) };
43
44 self.writer.write_str(line)?;
45 self.writer.write_str(codes::CRLF)?;
46 text = unsafe { text.get_unchecked(pos + 1..) };
49 self.dirty = false;
50 self.last_bytes = [0; 2];
51 } else {
52 self.writer.write_str(text)?;
53 self.dirty = true;
54
55 if text.len() > 1 {
56 self.last_bytes[0] = text.as_bytes()[text.len() - 2];
57 self.last_bytes[1] = text.as_bytes()[text.len() - 1];
58 } else {
59 self.last_bytes[0] = self.last_bytes[1];
60 self.last_bytes[1] = text.as_bytes()[text.len() - 1];
61 }
62 break;
63 }
64 }
65 Ok(())
66 }
67
68 pub fn writeln_str(&mut self, text: &str) -> Result<(), E> {
69 self.writer.write_str(text)?;
70 self.writer.write_str(codes::CRLF)?;
71 self.dirty = false;
72 Ok(())
73 }
74
75 pub fn write_list_element(
76 &mut self,
77 name: &str,
78 description: &str,
79 longest_name: usize,
80 ) -> Result<(), E> {
81 self.write_str(" ")?;
82 self.write_str(name)?;
83 if name.len() < longest_name {
84 for _ in 0..longest_name - name.len() {
85 self.write_str(" ")?;
86 }
87 }
88 self.write_str(" ")?;
89 self.writeln_str(description)?;
90
91 Ok(())
92 }
93
94 pub fn write_title(&mut self, title: &str) -> Result<(), E> {
95 self.write_str(title)?;
97 Ok(())
98 }
99}
100
101impl<'a, W: Write<Error = E>, E: Error> uWrite for Writer<'a, W, E> {
102 type Error = E;
103
104 fn write_str(&mut self, s: &str) -> Result<(), E> {
105 self.write_str(s)
106 }
107}
108
109impl<'a, W: Write<Error = E>, E: Error> core::fmt::Write for Writer<'a, W, E> {
110 fn write_str(&mut self, s: &str) -> core::fmt::Result {
111 self.write_str(s).map_err(|_| core::fmt::Error)?;
112 Ok(())
113 }
114}
115
116pub(crate) trait WriteExt: ErrorType {
117 fn flush_bytes(&mut self, bytes: &[u8]) -> Result<(), Self::Error>;
119
120 fn flush_str(&mut self, text: &str) -> Result<(), Self::Error>;
121
122 fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), Self::Error>;
123
124 fn write_str(&mut self, text: &str) -> Result<(), Self::Error>;
125}
126
127impl<W: Write> WriteExt for W {
128 fn flush_bytes(&mut self, bytes: &[u8]) -> Result<(), Self::Error> {
129 self.write_bytes(bytes)?;
130 self.flush()
131 }
132
133 fn flush_str(&mut self, text: &str) -> Result<(), Self::Error> {
134 self.flush_bytes(text.as_bytes())
135 }
136
137 fn write_bytes(&mut self, bytes: &[u8]) -> Result<(), Self::Error> {
138 self.write_all(bytes)
139 }
140
141 fn write_str(&mut self, text: &str) -> Result<(), Self::Error> {
142 self.write_bytes(text.as_bytes())
143 }
144}
145
146#[derive(Debug)]
147pub struct EmptyWriter;
148
149impl ErrorType for EmptyWriter {
150 type Error = Infallible;
151}
152
153impl Write for EmptyWriter {
154 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
155 Ok(buf.len())
156 }
157
158 fn flush(&mut self) -> Result<(), Self::Error> {
159 Ok(())
160 }
161}
162
163#[cfg(test)]
164mod tests {
165 use crate::writer::{EmptyWriter, Writer};
166
167 #[test]
168 fn detect_dirty() {
169 let mut writer = EmptyWriter;
170 let mut writer = Writer::new(&mut writer);
171
172 assert!(!writer.is_dirty());
173
174 writer.write_str("abc").unwrap();
175 assert!(writer.is_dirty());
176
177 writer.write_str("\r").unwrap();
178 assert!(writer.is_dirty());
179
180 writer.write_str("\n").unwrap();
181 assert!(!writer.is_dirty());
182
183 writer.write_str("abc\r\n").unwrap();
184 assert!(!writer.is_dirty());
185 }
186}