1#![cfg_attr(not(test), no_std)]
2#![deny(rust_2018_compatibility)]
3#![deny(rust_2018_idioms)]
4#![deny(missing_docs)]
5#![deny(warnings)]
6
7#[cfg(feature = "ufmt-impl")]
10mod ufmt;
11
12use core::{fmt, hash, ops, str};
13pub use tinyvec;
14use tinyvec::SliceVec; #[repr(transparent)]
21#[derive(Default)]
22pub struct SliceString<'a>(SliceVec<'a, u8>);
23
24impl<'a> SliceString<'a> {
25 pub fn new(buf: &'a mut [u8]) -> Self {
29 unsafe { Self::from_utf8_unchecked(buf, 0) }
31 }
32
33 pub unsafe fn new_unchecked(buf: SliceVec<'a, u8>) -> Self {
38 Self(buf)
39 }
40
41 pub fn from_utf8(buf: &'a mut [u8], len: usize) -> Result<Self, str::Utf8Error> {
45 str::from_utf8(&buf[..len])?;
46 Ok(unsafe { Self::from_utf8_unchecked(buf, len) })
48 }
49
50 pub unsafe fn from_utf8_unchecked(buf: &'a mut [u8], len: usize) -> Self {
55 Self::new_unchecked(SliceVec::from_slice_len(buf, len))
56 }
57
58 pub unsafe fn as_mut_slicevec(&mut self) -> &mut SliceVec<'a, u8> {
63 &mut self.0
64 }
65
66 pub fn as_str(&self) -> &str {
68 unsafe { str::from_utf8_unchecked(&self.0) }
70 }
71
72 pub fn as_mut_str(&mut self) -> &mut str {
74 unsafe { str::from_utf8_unchecked_mut(&mut self.0) }
76 }
77
78 pub fn capacity(&self) -> usize {
80 self.0.capacity()
81 }
82
83 pub fn clear(&mut self) {
85 self.0.clear()
86 }
87
88 pub fn truncate(&mut self, new_len: usize) {
93 if new_len <= self.len() {
94 assert!(self.is_char_boundary(new_len));
95 }
96 self.0.truncate(new_len);
97 }
98
99 pub fn pop(&mut self) -> Option<char> {
101 let ch = self.chars().last()?;
102 self.0.truncate(self.len() - ch.len_utf8());
103 Some(ch)
104 }
105
106 pub fn push(&mut self, c: char) {
111 match c.len_utf8() {
112 1 => self.0.push(c as u8),
113 _ => self.push_str(c.encode_utf8(&mut [0; 4])),
114 }
115 }
116
117 pub fn push_str(&mut self, string: &str) {
122 self.0.extend_from_slice(string.as_bytes())
123 }
124
125 pub fn split_off(&mut self, at: usize) -> SliceString<'a> {
133 if at <= self.len() {
134 assert!(self.is_char_boundary(at));
135 }
136 let new = self.0.split_off(at);
137 unsafe { Self::new_unchecked(new) }
139 }
140}
141
142impl<'a> From<SliceString<'a>> for SliceVec<'a, u8> {
143 fn from(value: SliceString<'a>) -> Self {
144 value.0
145 }
146}
147
148impl<'a> From<SliceString<'a>> for (&'a mut [u8], usize) {
149 fn from(mut value: SliceString<'a>) -> Self {
150 let data = value.as_mut_ptr();
151 let len = value.capacity();
152 let data = unsafe { core::slice::from_raw_parts_mut(data, len) };
154 (data, value.len())
155 }
156}
157
158impl<'a> TryFrom<&'a mut [u8]> for SliceString<'a> {
159 type Error = str::Utf8Error;
160
161 fn try_from(value: &'a mut [u8]) -> Result<Self, Self::Error> {
162 Self::from_utf8(value, value.len())
163 }
164}
165
166impl<'a> TryFrom<SliceVec<'a, u8>> for SliceString<'a> {
167 type Error = str::Utf8Error;
168
169 fn try_from(value: SliceVec<'a, u8>) -> Result<Self, Self::Error> {
170 str::from_utf8(&value)?;
171 Ok(unsafe { Self::new_unchecked(value) })
173 }
174}
175
176impl<'a> ops::Deref for SliceString<'a> {
177 type Target = str;
178
179 fn deref(&self) -> &str {
180 self.as_str()
181 }
182}
183
184impl<'a> ops::DerefMut for SliceString<'a> {
185 fn deref_mut(&mut self) -> &mut str {
186 self.as_mut_str()
187 }
188}
189
190impl<'a> AsRef<str> for SliceString<'a> {
191 fn as_ref(&self) -> &str {
192 self
193 }
194}
195
196impl<'a> AsMut<str> for SliceString<'a> {
197 fn as_mut(&mut self) -> &mut str {
198 self
199 }
200}
201
202impl<'a> AsRef<SliceVec<'a, u8>> for SliceString<'a> {
203 fn as_ref(&self) -> &SliceVec<'a, u8> {
204 &self.0
205 }
206}
207
208impl<'a> AsRef<[u8]> for SliceString<'a> {
209 fn as_ref(&self) -> &[u8] {
210 self.0.as_slice()
211 }
212}
213
214impl<'a> fmt::Write for SliceString<'a> {
215 fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
216 if self.capacity() < self.len() + s.len() {
217 return Err(fmt::Error);
218 }
219 self.push_str(s);
220 Ok(())
221 }
222
223 fn write_char(&mut self, c: char) -> Result<(), fmt::Error> {
224 if self.capacity() < self.len() + c.len_utf8() {
225 return Err(fmt::Error);
226 }
227 self.push(c);
228 Ok(())
229 }
230}
231
232impl<'a> fmt::Debug for SliceString<'a> {
233 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
234 <str as fmt::Debug>::fmt(self, f)
235 }
236}
237
238impl<'a> fmt::Display for SliceString<'a> {
239 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
240 <str as fmt::Display>::fmt(self, f)
241 }
242}
243
244impl<'a> hash::Hash for SliceString<'a> {
245 fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
246 <str as hash::Hash>::hash(self, hasher)
247 }
248}
249
250impl<'a> PartialEq for SliceString<'a> {
251 fn eq(&self, rhs: &SliceString<'a>) -> bool {
252 str::eq(&**self, &**rhs)
253 }
254}
255
256impl<'a> PartialEq<str> for SliceString<'a> {
258 fn eq(&self, other: &str) -> bool {
259 str::eq(&self[..], other)
260 }
261}
262
263impl<'a> PartialEq<&str> for SliceString<'a> {
265 fn eq(&self, other: &&str) -> bool {
266 str::eq(&self[..], &other[..])
267 }
268}
269
270impl<'a> PartialEq<SliceString<'a>> for str {
272 fn eq(&self, other: &SliceString<'a>) -> bool {
273 str::eq(self, &other[..])
274 }
275}
276
277impl<'a> PartialEq<SliceString<'a>> for &str {
279 fn eq(&self, other: &SliceString<'a>) -> bool {
280 str::eq(&self[..], &other[..])
281 }
282}
283
284impl<'a> Eq for SliceString<'a> {}
285
286impl<'a> PartialOrd for SliceString<'a> {
287 fn partial_cmp(&self, other: &SliceString<'a>) -> Option<core::cmp::Ordering> {
288 PartialOrd::partial_cmp(&**self, &**other)
289 }
290}
291
292impl<'a> Ord for SliceString<'a> {
293 fn cmp(&self, other: &Self) -> core::cmp::Ordering {
294 Ord::cmp(&**self, &**other)
295 }
296}
297
298impl<'a> Extend<char> for SliceString<'a> {
299 fn extend<T: IntoIterator<Item = char>>(&mut self, iter: T) {
300 let iterator = iter.into_iter();
301 iterator.for_each(move |c| self.push(c));
302 }
303}
304
305impl<'a> Extend<&'a char> for SliceString<'a> {
306 fn extend<I: IntoIterator<Item = &'a char>>(&mut self, iter: I) {
307 self.extend(iter.into_iter().cloned());
308 }
309}
310
311impl<'a> Extend<&'a str> for SliceString<'a> {
312 fn extend<T: IntoIterator<Item = &'a str>>(&mut self, iter: T) {
313 iter.into_iter().for_each(move |s| self.push_str(s));
314 }
315}
316
317impl<'a> ops::Add<&'a str> for SliceString<'a> {
318 type Output = SliceString<'a>;
319 #[inline]
320 fn add(mut self, rhs: &str) -> Self::Output {
321 self.push_str(rhs);
322 self
323 }
324}
325
326impl<'a> ops::AddAssign<&'a str> for SliceString<'a> {
327 #[inline]
328 fn add_assign(&mut self, rhs: &'a str) {
329 self.push_str(rhs);
330 }
331}
332
333#[cfg(test)]
336mod tests {
337 use super::*;
338 use core::fmt::Write;
339
340 #[test]
341 fn new() {
342 let mut buf = [0u8; 16];
343 let mut s = SliceString::new(&mut buf[..]);
344 assert_eq!(0, s.len());
345 assert_eq!(s.capacity(), 16);
346
347 s.push_str("Hello world!");
348 assert_eq!(s.as_str(), "Hello world!");
349
350 assert!(!s.is_empty());
351 s.clear();
352 assert_eq!(s.len(), 0);
353
354 s.push_str("foo");
355 s.truncate(2);
356 assert_eq!(s.len(), 2);
357 assert_eq!(s.as_str(), "fo");
358
359 s.push('r');
360 assert_eq!(s.as_str(), "for");
361
362 s.write_str("oooooooooooooooooooooo").unwrap_err();
363
364 let mut a = s.split_off(2);
365 assert_eq!(s.as_str(), "fo");
366 assert_eq!(a.as_str(), "r");
367
368 a.push_str("ab");
369 s.push_str("");
370 s.write_char('o').unwrap_err();
371 assert_eq!(s.capacity(), 2);
372 assert_eq!(a.capacity(), 16 - 2);
373
374 let r = unsafe { s.as_mut_slicevec() };
375 assert_eq!(r.as_ref(), "fo".as_bytes());
376
377 assert_eq!(s.pop().unwrap(), 'o');
378 assert_eq!(s.pop().unwrap(), 'f');
379 }
380
381 #[test]
382 #[should_panic]
383 fn panic_push() {
384 let mut buf = [0u8; 1];
385 let mut s = SliceString::new(&mut buf[..]);
386 s.push('f');
387 s.push('o');
388 }
389
390 #[test]
391 #[should_panic]
392 fn panic_push_str() {
393 let mut buf = [0u8; 1];
394 let mut s = SliceString::new(&mut buf[..]);
395 s.push_str("fo");
396 }
397
398 #[test]
399 fn cmp() {
400 let mut b1 = "abcd".as_bytes().to_owned();
401 let s1 = SliceString::try_from(&mut b1[..]).unwrap();
402 let mut b2 = "zzzz".as_bytes().to_owned();
403 let s2 = SliceString::try_from(&mut b2[..]).unwrap();
404 assert!(s1 < s2);
405 }
406
407 #[test]
408 fn disp() {
409 let mut b1 = "abcd".as_bytes().to_owned();
410 let s1 = SliceString::try_from(&mut b1[..]).unwrap();
411 let mut s = String::new();
412 write!(s, "{}", s1).unwrap();
413 assert_eq!("abcd", s);
414 }
415
416 #[test]
417 fn pop_uenc() {
418 let mut b = "éé".as_bytes().to_owned();
419 assert_eq!(b.len(), 2 + 3);
420 let mut s = SliceString::try_from(&mut b[..]).unwrap();
421 assert_eq!(s.len(), 2 + 3);
422 assert_eq!(s.pop().unwrap(), '\u{0301}');
423 assert_eq!(s.len(), 2 + 1);
424 assert_eq!(s.pop().unwrap(), 'e');
425 assert_eq!(s.len(), 2);
426 assert_eq!(s.pop().unwrap(), 'é');
427 assert_eq!(s.len(), 0);
428 s.push('ö');
429 s.push_str("ü");
430 assert_eq!(s.as_str(), "öü");
431 }
432
433 #[test]
434 fn write() {
435 let mut b = [0; 8];
436 let mut s = SliceString::new(&mut b[..]);
437 s.write_str("a").unwrap();
438 s.write_char('b').unwrap();
439 write!(s, "cdefgh").unwrap();
440 assert_eq!(s.len(), 8);
441 write!(s, "").unwrap();
442 write!(s, "a").unwrap_err();
443 }
444
445 #[test]
446 fn extend() {
447 let mut b = [0; 8];
448 let q = ["foo"];
449 let mut i = q.iter().copied();
450 let ii = &mut i;
451 {
452 let mut s = SliceString::new(&mut b[..]);
453 s.extend(ii);
454 println!("{}", s + "d");
455 }
456 println!("{:?}", i.next());
457 println!("{}", q[0])
458 }
459}