A custom OS for the xteink x4 ebook reader
1// no-alloc fmt::Write buffers; silently truncate on overflow
2
3pub struct StackFmt<const N: usize> {
4 buf: [u8; N],
5 len: usize,
6}
7
8impl<const N: usize> Default for StackFmt<N> {
9 fn default() -> Self {
10 Self::new()
11 }
12}
13
14impl<const N: usize> StackFmt<N> {
15 pub const fn new() -> Self {
16 Self {
17 buf: [0u8; N],
18 len: 0,
19 }
20 }
21
22 #[inline]
23 pub fn as_str(&self) -> &str {
24 core::str::from_utf8(&self.buf[..self.len]).unwrap_or("")
25 }
26
27 #[inline]
28 pub fn is_empty(&self) -> bool {
29 self.len == 0
30 }
31
32 #[inline]
33 pub fn clear(&mut self) {
34 self.len = 0;
35 }
36}
37
38impl<const N: usize> core::fmt::Write for StackFmt<N> {
39 fn write_str(&mut self, s: &str) -> core::fmt::Result {
40 let bytes = s.as_bytes();
41 let n = bytes.len().min(N - self.len);
42 self.buf[self.len..self.len + n].copy_from_slice(&bytes[..n]);
43 self.len += n;
44 Ok(())
45 }
46}
47
48pub struct BorrowedFmt<'a> {
49 buf: &'a mut [u8],
50 pos: usize,
51}
52
53impl<'a> BorrowedFmt<'a> {
54 #[inline]
55 pub fn new(buf: &'a mut [u8]) -> Self {
56 Self { buf, pos: 0 }
57 }
58
59 #[inline]
60 pub fn as_str(&self) -> &str {
61 core::str::from_utf8(&self.buf[..self.pos]).unwrap_or("")
62 }
63
64 #[inline]
65 pub fn len(&self) -> usize {
66 self.pos
67 }
68
69 #[inline]
70 pub fn is_empty(&self) -> bool {
71 self.pos == 0
72 }
73}
74
75impl core::fmt::Write for BorrowedFmt<'_> {
76 fn write_str(&mut self, s: &str) -> core::fmt::Result {
77 let bytes = s.as_bytes();
78 let room = self.buf.len() - self.pos;
79 let n = bytes.len().min(room);
80 self.buf[self.pos..self.pos + n].copy_from_slice(&bytes[..n]);
81 self.pos += n;
82 Ok(())
83 }
84}
85
86#[inline]
87pub fn stack_fmt(buf: &mut [u8], f: impl FnOnce(&mut BorrowedFmt<'_>)) -> usize {
88 let mut w = BorrowedFmt::new(buf);
89 f(&mut w);
90 w.pos
91}