#![cfg_attr(not(test), no_std)]
#![deny(missing_docs)]
use core::fmt::{self, Display, Formatter};
#[derive(Debug, Clone, Copy)]
pub struct WriteBuffer<const N: usize> {
buffer: [u8; N],
cursor: usize,
}
impl<const N: usize> WriteBuffer<N> {
pub fn new() -> Self {
let buf = [0u8; N];
WriteBuffer {
buffer: buf,
cursor: 0,
}
}
pub fn as_slice(&self) -> &[u8] {
&self.buffer[..self.cursor]
}
fn as_slice_mut(&mut self) -> &mut [u8] {
&mut self.buffer[..self.cursor]
}
pub fn reset(&mut self) {
self.cursor = 0;
}
pub fn as_str(&self) -> &str {
unsafe { core::str::from_utf8_unchecked(self.as_slice()) }
}
pub fn as_str_mut(&mut self) -> &mut str {
unsafe { core::str::from_utf8_unchecked_mut(self.as_slice_mut()) }
}
pub fn len(&self) -> usize {
self.cursor
}
pub fn is_empty(&self) -> bool {
self.len() == 0
}
pub fn remaining(&self) -> usize {
N - self.len()
}
pub fn is_full(&self) -> bool {
self.remaining() == 0
}
}
impl<const N: usize> Default for WriteBuffer<N> {
fn default() -> Self {
Self::new()
}
}
impl<const N: usize> PartialEq for WriteBuffer<N> {
fn eq(&self, other: &Self) -> bool {
self.as_slice() == other.as_slice()
}
}
impl<const N: usize> core::hash::Hash for WriteBuffer<N> {
fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
self.as_slice().hash(state);
}
}
impl<const N: usize> Eq for WriteBuffer<N> {}
impl<const N: usize> fmt::Write for WriteBuffer<N> {
fn write_str(&mut self, s: &str) -> fmt::Result {
let bytes = s.as_bytes();
let new_cursor = self.cursor + bytes.len();
if new_cursor > N {
return Err(fmt::Error);
}
self.buffer[self.cursor..new_cursor].copy_from_slice(bytes);
self.cursor = new_cursor;
Ok(())
}
}
impl<const N: usize> Display for WriteBuffer<N> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.as_str())
}
}
#[cfg(test)]
mod test {
use super::WriteBuffer;
use core::fmt::Write;
#[test]
fn test_write_wrapper() {
let x = 123;
let mut buffer: WriteBuffer<20> = WriteBuffer::new();
write!(buffer, "{}", x).unwrap();
assert_eq!(&buffer.as_slice()[0..3], b"123");
buffer.reset();
let x = 2.242424;
write!(buffer, "{:.2}", x).unwrap();
assert_eq!(buffer.as_slice(), b"2.24");
buffer.reset();
let x = 20;
write!(buffer, "Longer than {} characters sentence", x).unwrap_err();
buffer.reset();
write!(buffer, "{}", "1").unwrap();
write!(buffer, "{}", "2").unwrap();
assert_eq!(buffer.as_slice(), b"12");
}
#[test]
fn test_display() {
let x = 123;
let mut buffer: WriteBuffer<20> = WriteBuffer::new();
write!(buffer, "{}", x).unwrap();
assert_eq!("123", format!("{}", buffer));
}
#[test]
fn test_as_str_mut() {
let mut buffer: WriteBuffer<20> = WriteBuffer::new();
write!(buffer, "hello world").unwrap();
buffer.as_str_mut().make_ascii_uppercase();
assert_eq!(buffer.as_str(), "HELLO WORLD");
}
#[test]
fn test_is_empty_is_full_and_overflow() {
let mut buffer: WriteBuffer<10> = WriteBuffer::new();
assert!(buffer.is_empty());
write!(buffer, "0123456789").unwrap();
assert!(buffer.is_full());
assert_eq!(write!(buffer, "!"), Err(core::fmt::Error));
}
}