char_buf/
lib.rs

1#![no_std]
2
3//! A writable, fixed-length `char` buffer usable in `no_std` environments.
4//!
5//! ```
6//! use char_buf::CharBuf;
7//! use core::fmt::Write;
8//!
9//! // `CharBuf` with capacity `8`
10//! type CharBuf8 = CharBuf<8>;
11//!
12//! let mut w = CharBuf8::new();
13//! write!(w, "x{:?}x", [1, 2]).unwrap();
14//!
15//! assert_eq!(w, "x[1, 2]x");
16//! ```
17
18use core::fmt::{self, Write};
19
20/// A writable, fixed-length `char` buffer.
21pub struct CharBuf<const N: usize> {
22    buf: [char; N],
23    len: usize,
24}
25
26impl<const N: usize> CharBuf<N> {
27    /// Constructs a new, empty `CharBuf<N>`.
28    pub const fn new() -> Self {
29        CharBuf {
30            buf: ['\0'; N],
31            len: 0,
32        }
33    }
34}
35
36impl<const N: usize> Default for CharBuf<N> {
37    fn default() -> Self {
38        CharBuf::new()
39    }
40}
41
42impl<const N: usize> fmt::Debug for CharBuf<N> {
43    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
44        f.write_char('"')?;
45        for c in self.buf.split_at(self.len).0.iter() {
46            f.write_char(*c)?;
47        }
48        f.write_char('"')
49    }
50}
51
52impl<const N: usize> fmt::Write for CharBuf<N> {
53    /// Writes a string slice into this writer, returning whether the write succeeded. [Read more]
54    ///
55    /// # Errors
56    ///
57    /// This function will return an instance of [`Error`] if the buffer length is not enough to write `s`.
58    ///
59    /// [Read more]: https://doc.rust-lang.org/core/fmt/trait.Write.html#tymethod.write_str
60    /// [`Error`]: https://doc.rust-lang.org/core/fmt/struct.Error.html
61    fn write_str(&mut self, s: &str) -> fmt::Result {
62        let mut chars = s.chars();
63        self.buf
64            .split_at_mut(self.len)
65            .1
66            .iter_mut()
67            .zip(chars.by_ref())
68            .for_each(|(x, c)| {
69                *x = c;
70                self.len += 1;
71            });
72        if chars.next().is_some() {
73            Err(fmt::Error)
74        } else {
75            Ok(())
76        }
77    }
78}
79
80impl<const N1: usize, const N2: usize> PartialEq<CharBuf<N2>> for CharBuf<N1> {
81    fn eq(&self, other: &CharBuf<N2>) -> bool {
82        self.len == other.len
83            && self
84                .buf
85                .split_at(self.len)
86                .0
87                .iter()
88                .zip(other.buf.split_at(other.len).0.iter())
89                .all(|(x, y)| x == y)
90    }
91}
92
93impl<const N: usize> Eq for CharBuf<N> {}
94
95impl<const N: usize> PartialEq<str> for CharBuf<N> {
96    fn eq(&self, other: &str) -> bool {
97        let mut buf = self.buf.split_at(self.len).0.iter();
98        let mut chars = other.chars();
99        buf.by_ref().all(|x| {
100            if let Some(c) = chars.next() {
101                *x == c
102            } else {
103                false
104            }
105        }) && chars.next().is_none()
106    }
107}
108
109impl<const N: usize> PartialEq<&str> for CharBuf<N> {
110    fn eq(&self, other: &&str) -> bool {
111        *self == **other
112    }
113}
114
115impl<const N: usize> PartialEq<CharBuf<N>> for str {
116    fn eq(&self, other: &CharBuf<N>) -> bool {
117        *other == *self
118    }
119}
120
121impl<const N: usize> PartialEq<CharBuf<N>> for &str {
122    fn eq(&self, other: &CharBuf<N>) -> bool {
123        *other == **self
124    }
125}
126
127#[cfg(test)]
128mod tests {
129    use super::*;
130    use fmt::Write;
131
132    const N1: usize = 3;
133    const N2: usize = 5;
134    type CharBufN1 = CharBuf<N1>;
135    type CharBufN2 = CharBuf<N2>;
136
137    #[test]
138    fn new() {
139        let w1 = CharBufN1::new();
140        let w2 = CharBufN2::new();
141
142        assert_eq!(w1.buf, ['\0'; N1]);
143        assert_eq!(w1.len, 0);
144
145        assert_eq!(w2.buf, ['\0'; N2]);
146        assert_eq!(w2.len, 0);
147    }
148
149    #[test]
150    fn default() {
151        let w1 = CharBufN1::default();
152        let w2 = CharBufN2::default();
153
154        assert_eq!(w1.buf, ['\0'; N1]);
155        assert_eq!(w1.len, 0);
156
157        assert_eq!(w2.buf, ['\0'; N2]);
158        assert_eq!(w2.len, 0);
159    }
160
161    #[test]
162    fn debug() {
163        let mut w1a = CharBufN1::new();
164        let mut w1b = CharBufN1::new();
165
166        let mut w2a = CharBufN2::new();
167        let mut w2b = CharBufN2::new();
168
169        write!(w1a, "a").unwrap();
170        write!(w1b, "{:?}", w1a).unwrap();
171
172        assert_eq!(w1a.buf, ['a', '\0', '\0']);
173        assert_eq!(w1b.buf, ['"', 'a', '"']);
174
175        write!(w2a, "a").unwrap();
176        write!(w2b, "{:?}", w2a).unwrap();
177
178        assert_eq!(w2a.buf, ['a', '\0', '\0', '\0', '\0']);
179        assert_eq!(w2b.buf, ['"', 'a', '"', '\0', '\0']);
180    }
181
182    #[test]
183    fn write() {
184        let mut w1 = CharBufN1::new();
185        let mut w2 = CharBufN2::new();
186
187        write!(w1, "a").unwrap();
188        write!(w2, "a").unwrap();
189
190        assert_eq!(w1.buf, ['a', '\0', '\0']);
191        assert_eq!(w1.len, 1);
192
193        assert_eq!(w2.buf, ['a', '\0', '\0', '\0', '\0']);
194        assert_eq!(w2.len, 1);
195
196        write!(w1, "{:?}", [(); 0]).unwrap();
197        write!(w2, "{:?}", [(); 0]).unwrap();
198
199        assert_eq!(w1.buf, ['a', '[', ']']);
200        assert_eq!(w1.len, 3);
201
202        assert_eq!(w2.buf, ['a', '[', ']', '\0', '\0']);
203        assert_eq!(w2.len, 3);
204
205        let mut w1 = CharBufN1::new();
206        let mut w2 = CharBufN2::new();
207
208        write!(w1, "{:?}", [0]).unwrap();
209        write!(w2, "{:?}", [0]).unwrap();
210
211        assert_eq!(w1.buf, ['[', '0', ']']);
212        assert_eq!(w1.len, 3);
213
214        assert_eq!(w2.buf, ['[', '0', ']', '\0', '\0']);
215        assert_eq!(w2.len, 3);
216
217        assert_eq!(write!(w1, "!"), Err(fmt::Error));
218        assert_eq!(write!(w2, "!"), Ok(()));
219
220        assert_eq!(w1.buf, ['[', '0', ']']);
221        assert_eq!(w1.len, 3);
222
223        assert_eq!(w2.buf, ['[', '0', ']', '!', '\0']);
224        assert_eq!(w2.len, 4);
225    }
226
227    #[test]
228    fn eq() {
229        let mut w1 = CharBufN1::new();
230        let mut w2 = CharBufN2::new();
231
232        write!(w1, "ab").unwrap();
233        write!(w2, "ab").unwrap();
234
235        assert_eq!(w1, "ab");
236        assert_eq!(w1, *"ab");
237
238        assert_eq!(w2, "ab");
239        assert_eq!(w2, *"ab");
240
241        assert_eq!(w1, w2);
242        assert_eq!(w2, w1);
243
244        write!(w2, "c").unwrap();
245
246        assert_eq!("ab", w1);
247        assert_eq!(*"ab", w1);
248
249        assert_eq!("abc", w2);
250        assert_eq!(*"abc", w2);
251
252        assert_ne!(w1, w2);
253        assert_ne!(w2, w1);
254
255        assert_ne!(w1, "a");
256        assert_ne!(w1, *"a");
257
258        assert_ne!(w1, "abc");
259        assert_ne!(w1, *"abc");
260    }
261}