summaryrefslogtreecommitdiffstats
path: root/rsnix/src/strbuf.rs
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--rsnix/src/strbuf.rs71
1 files changed, 71 insertions, 0 deletions
diff --git a/rsnix/src/strbuf.rs b/rsnix/src/strbuf.rs
new file mode 100644
index 0000000..262720d
--- /dev/null
+++ b/rsnix/src/strbuf.rs
@@ -0,0 +1,71 @@
1//! Fixed-capacity ASCII string, allocated entirely on the stack.
2//! Shared by the line discipline (`tty`) and the shell.
3
4use core::fmt;
5
6/// A fixed-capacity string allocated entirely on the stack.
7pub struct String<const N: usize> {
8 buf: [u8; N],
9 len: usize,
10}
11
12impl<const N: usize> Default for String<N> {
13 fn default() -> Self {
14 Self::new()
15 }
16}
17
18impl<const N: usize> String<N> {
19 pub const fn new() -> Self {
20 String {
21 buf: [0u8; N],
22 len: 0,
23 }
24 }
25
26 pub fn as_str(&self) -> &str {
27 // SAFETY: we only write valid ASCII bytes.
28 unsafe { core::str::from_utf8_unchecked(&self.buf[..self.len]) }
29 }
30
31 pub fn push(&mut self, c: char) -> Result<(), ()> {
32 if self.len >= N {
33 return Err(());
34 }
35 self.buf[self.len] = c as u8;
36 self.len += 1;
37 Ok(())
38 }
39
40 pub fn pop(&mut self) -> Option<char> {
41 if self.len == 0 {
42 return None;
43 }
44 self.len -= 1;
45 Some(self.buf[self.len] as char)
46 }
47
48 pub fn is_empty(&self) -> bool {
49 self.len == 0
50 }
51
52 pub fn clear(&mut self) {
53 self.len = 0;
54 }
55
56 pub fn trim(&self) -> &str {
57 self.as_str().trim()
58 }
59}
60
61impl<const N: usize> fmt::Display for String<N> {
62 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
63 write!(f, "{}", self.as_str())
64 }
65}
66
67impl<const N: usize> fmt::Debug for String<N> {
68 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
69 write!(f, "{:?}", self.as_str())
70 }
71}