//! Fixed-capacity ASCII string, allocated entirely on the stack. //! Shared by the line discipline (`tty`) and the shell. use core::fmt; /// A fixed-capacity string allocated entirely on the stack. pub struct String { buf: [u8; N], len: usize, } impl Default for String { fn default() -> Self { Self::new() } } impl String { pub const fn new() -> Self { String { buf: [0u8; N], len: 0, } } pub fn as_str(&self) -> &str { // SAFETY: we only write valid ASCII bytes. unsafe { core::str::from_utf8_unchecked(&self.buf[..self.len]) } } pub fn push(&mut self, c: char) -> Result<(), ()> { if self.len >= N { return Err(()); } self.buf[self.len] = c as u8; self.len += 1; Ok(()) } pub fn pop(&mut self) -> Option { if self.len == 0 { return None; } self.len -= 1; Some(self.buf[self.len] as char) } pub fn is_empty(&self) -> bool { self.len == 0 } pub fn clear(&mut self) { self.len = 0; } pub fn trim(&self) -> &str { self.as_str().trim() } } impl fmt::Display for String { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}", self.as_str()) } } impl fmt::Debug for String { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{:?}", self.as_str()) } } /// Small `fmt::Write` over a byte slice — no allocation, bounded. /// Shared by the panic handler (task-panic message) and the scheduler /// (page-fault abort message) so they don't each reinvent it. pub struct FmtBuf<'a> { b: &'a mut [u8], n: usize, } impl<'a> FmtBuf<'a> { pub fn new(b: &'a mut [u8]) -> Self { FmtBuf { b, n: 0 } } /// Bytes written so far (clamped at the buffer length). pub fn len(&self) -> usize { self.n } } impl fmt::Write for FmtBuf<'_> { fn write_str(&mut self, s: &str) -> fmt::Result { let m = s.len().min(self.b.len() - self.n); self.b[self.n..self.n + m].copy_from_slice(&s.as_bytes()[..m]); self.n += m; Ok(()) } }