ufmt_utils/
lib.rs

1//! `μfmt` utilities
2//!
3//! # Minimum Supported Rust Version (MSRV)
4//!
5//! This crate is guaranteed to compile on stable Rust 1.36 and up. It *might* compile on older
6//! versions but that may change in any new patch release.
7
8#![deny(missing_docs)]
9#![deny(warnings)]
10#![no_std]
11
12use core::{convert::Infallible, fmt, str};
13
14use heapless::String;
15use ufmt_write::uWrite;
16
17macro_rules! assume_unreachable {
18    () => {
19        if cfg!(debug_assertions) {
20            panic!()
21        } else {
22            core::hint::unreachable_unchecked()
23        }
24    };
25}
26
27/// A write adapter that ignores all errors
28pub struct Ignore<W>
29where
30    W: uWrite,
31{
32    writer: W,
33}
34
35impl<W> Ignore<W>
36where
37    W: uWrite,
38{
39    /// Creates a new `Ignore` adapter
40    pub fn new(writer: W) -> Self {
41        Self { writer }
42    }
43
44    /// Destroys the adapter and returns the underlying writer
45    pub fn free(self) -> W {
46        self.writer
47    }
48}
49
50impl<W> uWrite for Ignore<W>
51where
52    W: uWrite,
53{
54    type Error = Infallible;
55
56    fn write_str(&mut self, s: &str) -> Result<(), Infallible> {
57        let _ = self.writer.write_str(s);
58        Ok(())
59    }
60}
61
62/// A write adapter that buffers writes and automatically flushes on newlines
63pub struct LineBuffered<W, const N: usize>
64where
65    W: uWrite,
66{
67    buffer: String<N>,
68    writer: W,
69}
70
71impl<W, const N: usize> LineBuffered<W, N>
72where
73    W: uWrite,
74{
75    /// Creates a new `LineBuffered` adapter
76    pub fn new(writer: W) -> Self {
77        Self {
78            buffer: String::new(),
79            writer,
80        }
81    }
82
83    /// Flushes the contents of the buffer
84    pub fn flush(&mut self) -> Result<(), W::Error> {
85        let ret = self.writer.write_str(&self.buffer);
86        self.buffer.clear();
87        ret
88    }
89
90    /// Destroys the adapter and returns the underlying writer
91    pub fn free(self) -> W {
92        self.writer
93    }
94
95    fn push_str(&mut self, s: &str) -> Result<(), W::Error> {
96        let len = s.as_bytes().len();
97        if self.buffer.len() + len > self.buffer.capacity() {
98            self.flush()?;
99        }
100
101        if len > self.buffer.capacity() {
102            self.writer.write_str(s)?;
103        } else {
104            self.buffer
105                .push_str(s)
106                .unwrap_or_else(|_| unsafe { assume_unreachable!() })
107        }
108
109        Ok(())
110    }
111}
112
113impl<W, const N: usize> uWrite for LineBuffered<W, N>
114where
115    W: uWrite,
116{
117    type Error = W::Error;
118
119    fn write_str(&mut self, mut s: &str) -> Result<(), W::Error> {
120        while let Some(pos) = s.as_bytes().iter().position(|b| *b == b'\n') {
121            let line = s
122                .get(..pos + 1)
123                .unwrap_or_else(|| unsafe { assume_unreachable!() });
124
125            self.push_str(line)?;
126            self.flush()?;
127
128            s = s
129                .get(pos + 1..)
130                .unwrap_or_else(|| unsafe { assume_unreachable!() });
131        }
132
133        self.push_str(s)
134    }
135}
136
137/// An adapter struct allowing to use `ufmt` on types which implement `core::fmt::Write`
138///
139/// For example:
140///
141/// ```
142/// use ufmt::uwrite;
143/// use ufmt_write::uWrite;
144/// use ufmt_utils::WriteAdapter;
145///
146/// let fancy_number: u8 = 42;
147///
148/// let mut s = String::new();
149/// uwrite!(WriteAdapter(&mut s), "{:?}", fancy_number);
150/// ```
151pub struct WriteAdapter<W>(pub W)
152where
153    W: fmt::Write;
154
155impl<W> uWrite for WriteAdapter<W>
156where
157    W: fmt::Write,
158{
159    type Error = fmt::Error;
160
161    fn write_char(&mut self, c: char) -> Result<(), Self::Error> {
162        self.0.write_char(c)
163    }
164
165    fn write_str(&mut self, s: &str) -> Result<(), Self::Error> {
166        self.0.write_str(s)
167    }
168}