smart_format/
str_buffer.rs1#[derive(Clone, PartialEq, Eq)]
14pub struct StrBuffer<const N: usize> {
15 buf: [u8; N],
16 len: usize,
17}
18
19impl<const N: usize> Default for StrBuffer<N> {
20 fn default() -> Self {
21 Self::new()
22 }
23}
24
25impl<const N: usize> StrBuffer<N> {
26 pub fn new() -> Self {
27 StrBuffer {
28 buf: [0; N],
29 len: 0,
30 }
31 }
32
33 pub fn push_str<'s>(&mut self, s: &'s str) -> Result<(), &'s str> {
34 let rem_len = self.buf.len() - self.len;
35 if rem_len < s.len() {
36 Err(s)
37 } else {
38 let start = self.len;
39 let end = start + s.len();
40 self.buf[start..end].copy_from_slice(s.as_bytes());
41 self.len += s.len();
42 Ok(())
43 }
44 }
45
46 pub fn as_str(&self) -> &str {
47 unsafe { core::str::from_utf8_unchecked(&self.buf[..self.len]) }
50 }
51
52 pub fn clear(&mut self) {
53 self.len = 0;
54 }
55
56 pub fn len(&self) -> usize {
57 self.len
58 }
59
60 pub fn is_empty(&self) -> bool {
61 self.len == 0
62 }
63
64 pub fn first(&self) -> Option<&str> {
65 if self.is_empty() {
66 None
67 } else {
68 self.as_str().split("").find(|c| !c.is_empty())
69 }
70 }
71
72 pub fn strip_first(&mut self) -> Option<()> {
73 let first_len = self.first()?.len();
74 self.buf.copy_within(first_len..self.len, 0);
75 self.len -= first_len;
76 Some(())
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83
84 const EXHAUSTED: &str = "Buffer has been exhausted";
85
86 #[test]
87 fn test_push_str() {
88 let mut buf = StrBuffer::<5>::new();
89 buf.push_str("&").expect(EXHAUSTED);
90 buf.push_str("amp").expect(EXHAUSTED);
91 buf.push_str(";").expect(EXHAUSTED);
92 assert_eq!("&", buf.as_str());
93 }
94
95 #[test]
96 fn test_exhaustion() {
97 let mut buf = StrBuffer::<5>::new();
98 buf.push_str("&").expect(EXHAUSTED);
99 assert_eq!(Err(" "), buf.push_str(" "));
100 }
101
102 #[test]
103 fn test_clear() {
104 let mut buf = StrBuffer::<5>::new();
105 buf.push_str("&").expect(EXHAUSTED);
106 assert_eq!("&", buf.as_str());
107 buf.clear();
108 assert_eq!("", buf.as_str());
109 }
110
111 #[test]
112 fn test_length() {
113 let mut buf = StrBuffer::<5>::new();
114 assert_eq!(buf.len(), 0);
115 buf.push_str("&").expect(EXHAUSTED);
116 assert_eq!(buf.len(), 1);
117 buf.push_str("amp").expect(EXHAUSTED);
118 assert_eq!(buf.len(), 4);
119 buf.push_str(";").expect(EXHAUSTED);
120 assert_eq!(buf.len(), 5);
121 buf.clear();
122 assert_eq!(buf.len(), 0);
123 }
124
125 #[test]
126 fn test_is_empty() {
127 let mut buf = StrBuffer::<5>::new();
128 assert!(buf.is_empty());
129 buf.push_str("&").expect(EXHAUSTED);
130 assert!(!buf.is_empty());
131 buf.push_str("amp").expect(EXHAUSTED);
132 assert!(!buf.is_empty());
133 buf.push_str(";").expect(EXHAUSTED);
134 assert!(!buf.is_empty());
135 buf.clear();
136 assert!(buf.is_empty());
137 }
138
139 #[test]
140 fn test_first() {
141 let mut buf = StrBuffer::<5>::new();
142 assert_eq!(None, buf.first());
143 buf.push_str("&").expect(EXHAUSTED);
144 assert_eq!(Some("&"), buf.first());
145 buf.push_str("amp").expect(EXHAUSTED);
146 assert_eq!(Some("&"), buf.first());
147 buf.push_str(";").expect(EXHAUSTED);
148 assert_eq!(Some("&"), buf.first());
149 buf.clear();
150 assert_eq!(None, buf.first());
151 }
152
153 #[test]
154 fn test_strip_first() {
155 let mut buf = StrBuffer::<8>::new();
156 assert_eq!(None, buf.strip_first());
157 buf.push_str("&&").expect(EXHAUSTED);
158 assert_eq!(Some("&"), buf.first());
159 assert_eq!(Some(()), buf.strip_first());
160 assert_eq!("&", buf.as_str());
161 }
162
163 #[test]
164 fn test_strip_first_wide() {
165 let mut buf = StrBuffer::<8>::new();
166 assert_eq!(None, buf.strip_first());
167 buf.push_str("АБВ").expect(EXHAUSTED);
168 assert_eq!(Some("А"), buf.first());
169 assert_eq!(Some(()), buf.strip_first());
170 assert_eq!("БВ", buf.as_str());
171 }
172}