#![no_std]
use core::fmt::{self, Write};
pub struct CharBuf<const N: usize> {
buf: [char; N],
len: usize,
}
impl<const N: usize> CharBuf<N> {
pub const fn new() -> Self {
CharBuf {
buf: ['\0'; N],
len: 0,
}
}
}
impl<const N: usize> Default for CharBuf<N> {
fn default() -> Self {
CharBuf::new()
}
}
impl<const N: usize> fmt::Debug for CharBuf<N> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.write_char('"')?;
for c in self.buf.split_at(self.len).0.iter() {
f.write_char(*c)?;
}
f.write_char('"')
}
}
impl<const N: usize> fmt::Write for CharBuf<N> {
fn write_str(&mut self, s: &str) -> fmt::Result {
let mut chars = s.chars();
self.buf
.split_at_mut(self.len)
.1
.iter_mut()
.zip(chars.by_ref())
.for_each(|(x, c)| {
*x = c;
self.len += 1;
});
if chars.next().is_some() {
Err(fmt::Error)
} else {
Ok(())
}
}
}
impl<const N1: usize, const N2: usize> PartialEq<CharBuf<N2>> for CharBuf<N1> {
fn eq(&self, other: &CharBuf<N2>) -> bool {
self.len == other.len
&& self
.buf
.split_at(self.len)
.0
.iter()
.zip(other.buf.split_at(other.len).0.iter())
.all(|(x, y)| x == y)
}
}
impl<const N: usize> Eq for CharBuf<N> {}
impl<const N: usize> PartialEq<str> for CharBuf<N> {
fn eq(&self, other: &str) -> bool {
let mut buf = self.buf.split_at(self.len).0.iter();
let mut chars = other.chars();
buf.by_ref().zip(chars.by_ref()).all(|(x, c)| *x == c)
&& buf.next().is_none()
&& chars.next().is_none()
}
}
impl<const N: usize> PartialEq<&str> for CharBuf<N> {
fn eq(&self, other: &&str) -> bool {
*self == **other
}
}
impl<const N: usize> PartialEq<CharBuf<N>> for str {
fn eq(&self, other: &CharBuf<N>) -> bool {
*other == *self
}
}
impl<const N: usize> PartialEq<CharBuf<N>> for &str {
fn eq(&self, other: &CharBuf<N>) -> bool {
*other == **self
}
}
#[cfg(test)]
mod tests {
use super::*;
use fmt::Write;
const N1: usize = 3;
const N2: usize = 5;
type CharBufN1 = CharBuf<N1>;
type CharBufN2 = CharBuf<N2>;
#[test]
fn new() {
let w1 = CharBufN1::new();
let w2 = CharBufN2::new();
assert_eq!(w1.buf, ['\0'; N1]);
assert_eq!(w1.len, 0);
assert_eq!(w2.buf, ['\0'; N2]);
assert_eq!(w2.len, 0);
}
#[test]
fn default() {
let w1 = CharBufN1::default();
let w2 = CharBufN2::default();
assert_eq!(w1.buf, ['\0'; N1]);
assert_eq!(w1.len, 0);
assert_eq!(w2.buf, ['\0'; N2]);
assert_eq!(w2.len, 0);
}
#[test]
fn debug() {
let mut w1a = CharBufN1::new();
let mut w1b = CharBufN1::new();
let mut w2a = CharBufN2::new();
let mut w2b = CharBufN2::new();
write!(w1a, "a").unwrap();
write!(w1b, "{:?}", w1a).unwrap();
assert_eq!(w1a.buf, ['a', '\0', '\0']);
assert_eq!(w1b.buf, ['"', 'a', '"']);
write!(w2a, "a").unwrap();
write!(w2b, "{:?}", w2a).unwrap();
assert_eq!(w2a.buf, ['a', '\0', '\0', '\0', '\0']);
assert_eq!(w2b.buf, ['"', 'a', '"', '\0', '\0']);
}
#[test]
fn write() {
let mut w1 = CharBufN1::new();
let mut w2 = CharBufN2::new();
write!(w1, "a").unwrap();
write!(w2, "a").unwrap();
assert_eq!(w1.buf, ['a', '\0', '\0']);
assert_eq!(w1.len, 1);
assert_eq!(w2.buf, ['a', '\0', '\0', '\0', '\0']);
assert_eq!(w2.len, 1);
write!(w1, "{:?}", [(); 0]).unwrap();
write!(w2, "{:?}", [(); 0]).unwrap();
assert_eq!(w1.buf, ['a', '[', ']']);
assert_eq!(w1.len, 3);
assert_eq!(w2.buf, ['a', '[', ']', '\0', '\0']);
assert_eq!(w2.len, 3);
let mut w1 = CharBufN1::new();
let mut w2 = CharBufN2::new();
write!(w1, "{:?}", [0]).unwrap();
write!(w2, "{:?}", [0]).unwrap();
assert_eq!(w1.buf, ['[', '0', ']']);
assert_eq!(w1.len, 3);
assert_eq!(w2.buf, ['[', '0', ']', '\0', '\0']);
assert_eq!(w2.len, 3);
assert_eq!(write!(w1, "!"), Err(fmt::Error));
assert_eq!(write!(w2, "!"), Ok(()));
assert_eq!(w1.buf, ['[', '0', ']']);
assert_eq!(w1.len, 3);
assert_eq!(w2.buf, ['[', '0', ']', '!', '\0']);
assert_eq!(w2.len, 4);
}
#[test]
fn eq() {
let mut w1 = CharBufN1::new();
let mut w2 = CharBufN2::new();
write!(w1, "ab").unwrap();
write!(w2, "ab").unwrap();
assert_eq!(w1, "ab");
assert_eq!(w1, *"ab");
assert_eq!(w2, "ab");
assert_eq!(w2, *"ab");
assert_eq!(w1, w2);
assert_eq!(w2, w1);
write!(w2, "c").unwrap();
assert_eq!("ab", w1);
assert_eq!(*"ab", w1);
assert_eq!("abc", w2);
assert_eq!(*"abc", w2);
assert_ne!(w1, w2);
assert_ne!(w2, w1);
}
}