stack_buf/str.rs
1use crate::StackVec;
2#[cfg(feature = "std")]
3use std::borrow::Cow;
4use std::borrow::{Borrow, BorrowMut};
5use std::cmp::Ordering;
6use std::hash::{Hash, Hasher};
7use std::iter::FromIterator;
8use std::ops::{Add, AddAssign, Deref, DerefMut};
9use std::str::{FromStr, Utf8Error};
10use std::{fmt, ptr, str};
11
12/// A possible error value when converting a `StackStr` from a UTF-8 byte vector.
13///
14/// This type is the error type for the [`from_utf8`] method on [`StackStr`]. It
15/// is designed in such a way to carefully avoid reallocations: the
16/// [`into_bytes`] method will give back the byte vector that was used in the
17/// conversion attempt.
18///
19/// [`from_utf8`]: StackStr::from_utf8
20/// [`into_bytes`]: FromUtf8Error::into_bytes
21///
22/// # Examples
23///
24/// ```
25/// use stack_buf::{StackStr, stack_vec};
26///
27/// // some invalid bytes, in a vector
28/// let bytes = stack_vec![0, 159];
29///
30/// let value = StackStr::<2>::from_utf8(bytes);
31///
32/// assert!(value.is_err());
33/// assert_eq!(stack_vec![0, 159], value.unwrap_err().into_bytes());
34/// ```
35#[cfg_attr(docsrs, doc(cfg(feature = "str")))]
36#[derive(Debug, Clone, PartialEq, Eq)]
37pub struct FromUtf8Error<const N: usize> {
38 bytes: StackVec<u8, N>,
39 error: Utf8Error,
40}
41
42#[cfg(feature = "std")]
43#[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "str"))))]
44impl<const N: usize> std::error::Error for FromUtf8Error<N> {}
45
46impl<const N: usize> fmt::Display for FromUtf8Error<N> {
47 #[inline]
48 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
49 fmt::Display::fmt(&self.error, f)
50 }
51}
52
53impl<const N: usize> FromUtf8Error<N> {
54 /// Returns a slice of [`u8`]s bytes that were attempted to convert to a `StackStr`.
55 ///
56 /// # Examples
57 ///
58 /// ```
59 /// use stack_buf::{StackStr, stack_vec};
60 ///
61 /// // some invalid bytes, in a vector
62 /// let bytes = stack_vec![0, 159];
63 ///
64 /// let value = StackStr::<2>::from_utf8(bytes);
65 ///
66 /// assert_eq!(&[0, 159], value.unwrap_err().as_bytes());
67 /// ```
68 #[inline]
69 pub const fn as_bytes(&self) -> &[u8] {
70 self.bytes.as_slice()
71 }
72
73 /// Returns the bytes that were attempted to convert to a `StackStr`.
74 ///
75 /// # Examples
76 ///
77 /// ```
78 /// use stack_buf::{stack_vec, StackStr};
79 ///
80 /// // some invalid bytes, in a vector
81 /// let bytes = stack_vec![0, 159];
82 ///
83 /// let value = StackStr::<2>::from_utf8(bytes);
84 ///
85 /// assert_eq!(stack_vec![0, 159], value.unwrap_err().into_bytes());
86 /// ```
87 #[inline]
88 pub fn into_bytes(self) -> StackVec<u8, N> {
89 self.bytes
90 }
91
92 /// Fetch a `Utf8Error` to get more details about the conversion failure.
93 ///
94 /// # Examples
95 ///
96 /// ```
97 /// use stack_buf::{StackStr, stack_vec};
98 ///
99 /// // some invalid bytes, in a vector
100 /// let bytes = stack_vec![0, 159];
101 ///
102 /// let error = StackStr::<2>::from_utf8(bytes).unwrap_err().utf8_error();
103 ///
104 /// // the first byte is invalid here
105 /// assert_eq!(1, error.valid_up_to());
106 /// ```
107 #[inline]
108 pub const fn utf8_error(&self) -> Utf8Error {
109 self.error
110 }
111}
112
113/// A string with a fixed capacity and stored on the stack.
114///
115/// The `StackStr` is a string backed by a fixed size `StackVec`. It keeps track
116/// of its length, and is parameterized by `N` for the maximum capacity.
117///
118/// `N` is of type `usize` but is range limited to `u32::MAX`; attempting to create
119/// string with larger size will panic.
120#[cfg_attr(docsrs, doc(cfg(feature = "str")))]
121pub struct StackStr<const N: usize> {
122 vec: StackVec<u8, N>,
123}
124
125// Keeps StackStr valid if the retain predicate panics after moving bytes.
126struct RetainGuard<'a, const N: usize> {
127 vec: &'a mut StackVec<u8, N>,
128 len: usize,
129}
130
131impl<const N: usize> Drop for RetainGuard<'_, N> {
132 fn drop(&mut self) {
133 unsafe { self.vec.set_len(self.len) };
134 }
135}
136
137impl<const N: usize> StackStr<N> {
138 /// Creates a new empty `StackStr`.
139 ///
140 /// The maximum capacity is given by the generic parameter `N`.
141 ///
142 /// # Examples
143 ///
144 /// ```
145 /// use stack_buf::StackStr;
146 ///
147 /// let s: StackStr<3> = StackStr::new();
148 /// ```
149 #[inline]
150 pub const fn new() -> Self {
151 StackStr {
152 vec: StackVec::new(),
153 }
154 }
155
156 /// Converts a vector of bytes to a `StackStr`.
157 ///
158 /// If you are sure that the byte slice is valid UTF-8, and you don't want
159 /// to incur the overhead of the validity check, there is an unsafe version
160 /// of this function, [`from_utf8_unchecked`], which has the same behavior
161 /// but skips the check.
162 ///
163 /// The inverse of this method is [`into_bytes`].
164 ///
165 /// # Errors
166 ///
167 /// Returns [`Err`] if the slice is not UTF-8 with a description as to why the
168 /// provided bytes are not UTF-8. The vector you moved in is also included.
169 ///
170 /// # Examples
171 ///
172 /// ```
173 /// use stack_buf::{StackStr, stack_vec};
174 ///
175 /// // some bytes, in a vector
176 /// let sparkle_heart = stack_vec![240, 159, 146, 150];
177 ///
178 /// // We know these bytes are valid, so we'll use `unwrap()`.
179 /// let sparkle_heart = StackStr::from_utf8(sparkle_heart).unwrap();
180 ///
181 /// assert_eq!("💖", sparkle_heart);
182 /// ```
183 ///
184 /// Incorrect bytes:
185 ///
186 /// ```
187 /// use stack_buf::{StackStr, stack_vec};
188 ///
189 /// // some invalid bytes, in a vector
190 /// let sparkle_heart = stack_vec![0, 159, 146, 150];
191 ///
192 /// assert!(StackStr::from_utf8(sparkle_heart).is_err());
193 /// ```
194 ///
195 /// See the docs for [`FromUtf8Error`] for more details on what you can do
196 /// with this error.
197 ///
198 /// [`from_utf8_unchecked`]: StackStr::from_utf8_unchecked
199 /// [`into_bytes`]: StackStr::into_bytes
200 #[inline]
201 pub fn from_utf8(vec: StackVec<u8, N>) -> Result<Self, FromUtf8Error<N>> {
202 match str::from_utf8(&vec) {
203 Ok(..) => Ok(StackStr { vec }),
204 Err(e) => Err(FromUtf8Error {
205 bytes: vec,
206 error: e,
207 }),
208 }
209 }
210
211 /// Converts a vector of bytes to a `StackStr` without checking that the
212 /// string contains valid UTF-8.
213 ///
214 /// See the safe version, [`from_utf8`], for more details.
215 ///
216 /// [`from_utf8`]: StackStr::from_utf8
217 ///
218 /// # Safety
219 ///
220 /// This function is unsafe because it does not check that the bytes passed
221 /// to it are valid UTF-8. If this constraint is violated, it may cause
222 /// memory unsafety issues with future users of the `StackStr`, as the rest of
223 /// the library assumes that `StackStr`s are valid UTF-8.
224 ///
225 /// # Examples
226 ///
227 /// ```
228 /// use stack_buf::{StackStr, stack_vec};
229 ///
230 /// // some bytes, in a vector
231 /// let sparkle_heart = stack_vec![240, 159, 146, 150];
232 ///
233 /// let sparkle_heart = unsafe {
234 /// StackStr::from_utf8_unchecked(sparkle_heart)
235 /// };
236 ///
237 /// assert_eq!("💖", sparkle_heart);
238 /// ```
239 #[inline]
240 pub const unsafe fn from_utf8_unchecked(bytes: StackVec<u8, N>) -> Self {
241 StackStr { vec: bytes }
242 }
243
244 /// Converts a `StackStr` into a byte vector.
245 ///
246 /// This consumes the `StackStr`, so we do not need to copy its contents.
247 ///
248 /// # Examples
249 ///
250 /// ```
251 /// use stack_buf::StackStr;
252 ///
253 /// let s = StackStr::<5>::from("hello");
254 /// let bytes = s.into_bytes();
255 ///
256 /// assert_eq!(&[104, 101, 108, 108, 111][..], &bytes[..]);
257 /// ```
258 #[inline]
259 pub fn into_bytes(self) -> StackVec<u8, N> {
260 self.vec
261 }
262
263 /// Returns the length of this `StackStr`, in bytes, not [`char`]s or
264 /// graphemes. In other words, it may not be what a human considers the
265 /// length of the string.
266 #[inline]
267 pub const fn len(&self) -> usize {
268 self.vec.len()
269 }
270
271 /// Returns whether the string is empty.
272 #[inline]
273 pub const fn is_empty(&self) -> bool {
274 self.len() == 0
275 }
276
277 /// Returns `true` if the `StackStr` is completely filled to its capacity, false otherwise.
278 ///
279 /// # Examples
280 ///
281 /// ```
282 /// use stack_buf::StackStr;
283 ///
284 /// let mut s = StackStr::<1>::new();
285 /// assert!(!s.is_full());
286 /// s.push('a');
287 /// assert!(s.is_full());
288 /// ```
289 #[inline]
290 pub const fn is_full(&self) -> bool {
291 self.len() == self.capacity()
292 }
293
294 /// Returns this `StackStr`'s capacity, in bytes.
295 ///
296 /// # Examples
297 ///
298 /// ```
299 /// use stack_buf::StackStr;
300 ///
301 /// let s = StackStr::<10>::new();
302 ///
303 /// assert_eq!(s.capacity(), 10);
304 /// ```
305 #[inline]
306 pub const fn capacity(&self) -> usize {
307 self.vec.capacity()
308 }
309
310 /// Returns the capacity left in the `StackStr`.
311 ///
312 /// # Examples
313 ///
314 /// ```
315 /// use stack_buf::StackStr;
316 ///
317 /// let mut s = StackStr::<3>::from("123");
318 /// s.pop();
319 /// assert_eq!(s.remaining_capacity(), 1);
320 /// ```
321 #[inline]
322 pub const fn remaining_capacity(&self) -> usize {
323 self.capacity() - self.len()
324 }
325
326 /// Sets the `StackStr`’s length without dropping or moving out elements
327 ///
328 /// # Safety
329 /// This method is `unsafe` because it changes the notion of the
330 /// number of “valid” elements in the vector.
331 ///
332 /// This method uses *debug assertions* to check that `length` is
333 /// not greater than the capacity.
334 #[inline]
335 pub const unsafe fn set_len(&mut self, length: usize) {
336 unsafe { self.vec.set_len(length) };
337 }
338
339 /// Extracts a string slice containing the entire `StackStr`.
340 ///
341 /// # Examples
342 ///
343 /// ```
344 /// use stack_buf::StackStr;
345 ///
346 /// let s = StackStr::<5>::from("foo");
347 ///
348 /// assert_eq!("foo", s.as_str());
349 /// ```
350 #[inline]
351 pub const fn as_str(&self) -> &str {
352 unsafe { str::from_utf8_unchecked(self.vec.as_slice()) }
353 }
354
355 /// Converts a `StackStr` into a mutable string slice.
356 ///
357 /// # Examples
358 ///
359 /// ```
360 /// use stack_buf::StackStr;
361 ///
362 /// let mut s = StackStr::<10>::from("foobar");
363 /// let s_mut_str = s.as_mut_str();
364 ///
365 /// s_mut_str.make_ascii_uppercase();
366 ///
367 /// assert_eq!("FOOBAR", s_mut_str);
368 /// ```
369 #[inline]
370 pub const fn as_mut_str(&mut self) -> &mut str {
371 unsafe { str::from_utf8_unchecked_mut(self.vec.as_mut_slice()) }
372 }
373
374 /// Returns a raw pointer to the `StackStr`'s buffer.
375 #[inline(always)]
376 pub const fn as_ptr(&self) -> *const u8 {
377 self.vec.as_ptr() as _
378 }
379
380 /// Returns a raw mutable pointer to the `StackStr`'s buffer.
381 #[inline(always)]
382 pub const fn as_mut_ptr(&mut self) -> *mut u8 {
383 self.vec.as_mut_ptr() as _
384 }
385
386 /// Returns a byte slice of this `StackStr`'s contents.
387 ///
388 /// The inverse of this method is [`from_utf8`].
389 ///
390 /// [`from_utf8`]: StackStr::from_utf8
391 ///
392 /// # Examples
393 ///
394 /// ```
395 /// use stack_buf::StackStr;
396 ///
397 /// let s = StackStr::<5>::from("hello");
398 ///
399 /// assert_eq!(&[104, 101, 108, 108, 111], s.as_bytes());
400 /// ```
401 #[inline]
402 pub const fn as_bytes(&self) -> &[u8] {
403 self.vec.as_slice()
404 }
405
406 /// Returns a mutable reference to the contents of this `StackStr`.
407 ///
408 /// # Safety
409 ///
410 /// This function is unsafe because it does not check that the bytes passed
411 /// to it are valid UTF-8. If this constraint is violated, it may cause
412 /// memory unsafety issues with future users of the `StackStr`, as the rest of
413 /// the standard library assumes that `StackStr`s are valid UTF-8.
414 ///
415 /// # Examples
416 ///
417 /// ```
418 /// use stack_buf::StackStr;
419 ///
420 /// let mut s = StackStr::<5>::from("hello");
421 ///
422 /// unsafe {
423 /// let vec = s.as_mut_vec();
424 /// assert_eq!(&[104, 101, 108, 108, 111][..], &vec[..]);
425 ///
426 /// vec.reverse();
427 /// }
428 /// assert_eq!(s, "olleh");
429 /// ```
430 #[inline]
431 pub const unsafe fn as_mut_vec(&mut self) -> &mut StackVec<u8, N> {
432 &mut self.vec
433 }
434
435 /// Appends a given string slice onto the end of this `StackStr`.
436 ///
437 /// # Examples
438 ///
439 /// ```
440 /// use stack_buf::StackStr;
441 ///
442 /// let mut s = StackStr::<10>::from("foo");
443 ///
444 /// s.push_str("bar");
445 ///
446 /// assert_eq!("foobar", s);
447 /// ```
448 #[inline]
449 pub fn push_str(&mut self, string: &str) {
450 self.vec.copy_from_slice(string.as_bytes())
451 }
452
453 /// Appends the given [`char`] to the end of this `StackStr`.
454 ///
455 /// # Examples
456 ///
457 /// ```
458 /// use stack_buf::StackStr;
459 ///
460 /// let mut s = StackStr::<6>::from("abc");
461 ///
462 /// s.push('1');
463 /// s.push('2');
464 /// s.push('3');
465 ///
466 /// assert_eq!("abc123", s);
467 /// ```
468 #[inline]
469 pub fn push(&mut self, ch: char) {
470 match ch.len_utf8() {
471 1 => self.vec.push(ch as u8),
472 _ => self
473 .vec
474 .copy_from_slice(ch.encode_utf8(&mut [0; 4]).as_bytes()),
475 }
476 }
477
478 /// Removes the last character from the string buffer and returns it.
479 ///
480 /// Returns [`None`] if this `StackStr` is empty.
481 ///
482 /// # Examples
483 ///
484 /// ```
485 /// use stack_buf::StackStr;
486 ///
487 /// let mut s = StackStr::<3>::from("foo");
488 ///
489 /// assert_eq!(s.pop(), Some('o'));
490 /// assert_eq!(s.pop(), Some('o'));
491 /// assert_eq!(s.pop(), Some('f'));
492 ///
493 /// assert_eq!(s.pop(), None);
494 /// ```
495 #[inline]
496 pub fn pop(&mut self) -> Option<char> {
497 let ch = self.chars().next_back()?;
498 let new_len = self.len() - ch.len_utf8();
499 unsafe {
500 self.vec.set_len(new_len);
501 }
502 Some(ch)
503 }
504
505 /// Shortens this `StackStr` to the specified length.
506 ///
507 /// If `new_len` is greater than the string's current length, this has no
508 /// effect.
509 ///
510 /// # Panics
511 ///
512 /// Panics if `new_len` does not lie on a [`char`] boundary.
513 ///
514 /// # Examples
515 ///
516 /// ```
517 /// use stack_buf::StackStr;
518 ///
519 /// let mut s = StackStr::<5>::from("hello");
520 ///
521 /// s.truncate(2);
522 ///
523 /// assert_eq!("he", s);
524 /// ```
525 #[inline]
526 pub fn truncate(&mut self, new_len: usize) {
527 if new_len <= self.len() {
528 assert!(self.is_char_boundary(new_len));
529 unsafe { self.set_len(new_len) }
530 }
531 }
532
533 /// Truncates this `StackStr`, removing all contents.
534 ///
535 /// While this means the `StackStr` will have a length of zero, it does not
536 /// touch its capacity.
537 ///
538 /// # Examples
539 ///
540 /// ```
541 /// use stack_buf::StackStr;
542 ///
543 /// let mut s = StackStr::<3>::from("foo");
544 ///
545 /// s.clear();
546 ///
547 /// assert!(s.is_empty());
548 /// assert_eq!(0, s.len());
549 /// assert_eq!(3, s.capacity());
550 /// ```
551 #[inline]
552 pub fn clear(&mut self) {
553 unsafe {
554 self.set_len(0);
555 }
556 }
557
558 /// Retains only the characters specified by the predicate.
559 ///
560 /// In other words, remove all characters `c` such that `f(c)` returns `false`.
561 /// This method operates in place, visiting each character exactly once in the
562 /// original order, and preserves the order of the retained characters.
563 ///
564 /// # Examples
565 ///
566 /// ```
567 /// use stack_buf::StackStr;
568 ///
569 /// let mut s = StackStr::<10>::from("f_o_ob_ar");
570 ///
571 /// s.retain(|c| c != '_');
572 ///
573 /// assert_eq!(s, "foobar");
574 /// ```
575 ///
576 /// The exact order may be useful for tracking external state, like an index.
577 ///
578 /// ```
579 /// use stack_buf::StackStr;
580 ///
581 /// let mut s = StackStr::<5>::from("abcde");
582 /// let keep = [false, true, true, false, true];
583 /// let mut i = 0;
584 /// s.retain(|_| (keep[i], i += 1).0);
585 /// assert_eq!(s, "bce");
586 /// ```
587 #[inline]
588 pub fn retain<F>(&mut self, mut f: F)
589 where
590 F: FnMut(char) -> bool,
591 {
592 let len = self.len();
593 let mut del_bytes = 0;
594 let mut idx = 0;
595 let mut guard = RetainGuard {
596 vec: &mut self.vec,
597 len: 0,
598 };
599
600 while idx < len {
601 // The guard has shortened vec, so read the original initialized bytes directly.
602 let bytes =
603 unsafe { std::slice::from_raw_parts(guard.vec.as_ptr().add(idx), len - idx) };
604 let ch = unsafe { str::from_utf8_unchecked(bytes) }
605 .chars()
606 .next()
607 .unwrap();
608 let ch_len = ch.len_utf8();
609
610 if !f(ch) {
611 del_bytes += ch_len;
612 } else if del_bytes > 0 {
613 unsafe {
614 ptr::copy(
615 guard.vec.as_ptr().add(idx),
616 guard.vec.as_mut_ptr().add(idx - del_bytes),
617 ch_len,
618 );
619 }
620 }
621
622 guard.len = idx + ch_len - del_bytes;
623
624 // Point idx to the next char
625 idx += ch_len;
626 }
627 }
628
629 /// Inserts a character into this `StackStr` at a byte position.
630 ///
631 /// This is an *O*(*n*) operation as it requires copying every element in the
632 /// buffer.
633 ///
634 /// # Panics
635 ///
636 /// Panics if `idx` is larger than the `StackStr`'s length, or if it does not
637 /// lie on a [`char`] boundary.
638 ///
639 /// # Examples
640 ///
641 /// ```
642 /// use stack_buf::StackStr;
643 ///
644 /// let mut s = StackStr::<3>::new();
645 ///
646 /// s.insert(0, 'f');
647 /// s.insert(1, 'o');
648 /// s.insert(2, 'o');
649 ///
650 /// assert_eq!("foo", s);
651 /// ```
652 #[inline]
653 pub fn insert(&mut self, idx: usize, ch: char) {
654 assert!(self.is_char_boundary(idx));
655 let mut bits = [0; 4];
656 let bits = ch.encode_utf8(&mut bits).as_bytes();
657
658 unsafe {
659 self.insert_bytes(idx, bits);
660 }
661 }
662
663 unsafe fn insert_bytes(&mut self, idx: usize, bytes: &[u8]) {
664 let len = self.len();
665 let amt = bytes.len();
666 assert!(self.vec.remaining_capacity() >= amt);
667
668 unsafe {
669 ptr::copy(
670 self.vec.as_ptr().add(idx),
671 self.vec.as_mut_ptr().add(idx + amt),
672 len - idx,
673 );
674 ptr::copy(bytes.as_ptr(), self.vec.as_mut_ptr().add(idx), amt);
675 self.vec.set_len(len + amt);
676 }
677 }
678
679 /// Inserts a string slice into this `StackStr` at a byte position.
680 ///
681 /// This is an *O*(*n*) operation as it requires copying every element in the
682 /// buffer.
683 ///
684 /// # Panics
685 ///
686 /// Panics if `idx` is larger than the `StackStr`'s length, or if it does not
687 /// lie on a [`char`] boundary.
688 ///
689 /// # Examples
690 ///
691 /// ```
692 /// use stack_buf::StackStr;
693 ///
694 /// let mut s = StackStr::<6>::from("bar");
695 ///
696 /// s.insert_str(0, "foo");
697 ///
698 /// assert_eq!("foobar", s);
699 /// ```
700 #[inline]
701 pub fn insert_str(&mut self, idx: usize, string: &str) {
702 assert!(self.is_char_boundary(idx));
703
704 unsafe {
705 self.insert_bytes(idx, string.as_bytes());
706 }
707 }
708
709 /// Removes a [`char`] from this `StackStr` at a byte position and returns it.
710 ///
711 /// This is an *O*(*n*) operation, as it requires copying every element in the
712 /// buffer.
713 ///
714 /// # Panics
715 ///
716 /// Panics if `idx` is larger than or equal to the `StackStr`'s length,
717 /// or if it does not lie on a [`char`] boundary.
718 ///
719 /// # Examples
720 ///
721 /// ```
722 /// use stack_buf::StackStr;
723 ///
724 /// let mut s = StackStr::<3>::from("foo");
725 ///
726 /// assert_eq!(s.remove(0), 'f');
727 /// assert_eq!(s.remove(1), 'o');
728 /// assert_eq!(s.remove(0), 'o');
729 /// ```
730 #[inline]
731 pub fn remove(&mut self, idx: usize) -> char {
732 let ch = match self[idx..].chars().next() {
733 Some(ch) => ch,
734 None => panic!("cannot remove a char from the end of a StackStr"),
735 };
736
737 let next = idx + ch.len_utf8();
738 let len = self.len();
739 unsafe {
740 ptr::copy(
741 self.vec.as_ptr().add(next),
742 self.vec.as_mut_ptr().add(idx),
743 len - next,
744 );
745 self.vec.set_len(len - (next - idx));
746 }
747 ch
748 }
749}
750
751impl<const N: usize> Clone for StackStr<N> {
752 #[inline]
753 fn clone(&self) -> Self {
754 let mut vec = StackVec::new();
755 vec.copy_from_slice(&self.vec);
756 StackStr { vec }
757 }
758
759 #[inline]
760 fn clone_from(&mut self, source: &Self) {
761 self.clear();
762 self.vec.copy_from_slice(&source.vec);
763 }
764}
765
766impl<const N: usize> Deref for StackStr<N> {
767 type Target = str;
768
769 #[inline(always)]
770 fn deref(&self) -> &str {
771 unsafe { std::str::from_utf8_unchecked(self.vec.as_slice()) }
772 }
773}
774
775impl<const N: usize> DerefMut for StackStr<N> {
776 #[inline(always)]
777 fn deref_mut(&mut self) -> &mut str {
778 unsafe { std::str::from_utf8_unchecked_mut(self.vec.as_mut_slice()) }
779 }
780}
781
782impl<const N: usize> AsRef<str> for StackStr<N> {
783 #[inline(always)]
784 fn as_ref(&self) -> &str {
785 self
786 }
787}
788
789impl<const N: usize> AsMut<str> for StackStr<N> {
790 #[inline(always)]
791 fn as_mut(&mut self) -> &mut str {
792 self
793 }
794}
795
796impl<const N: usize> AsRef<[u8]> for StackStr<N> {
797 #[inline(always)]
798 fn as_ref(&self) -> &[u8] {
799 self.as_bytes()
800 }
801}
802
803impl<const N: usize> Borrow<str> for StackStr<N> {
804 #[inline(always)]
805 fn borrow(&self) -> &str {
806 self
807 }
808}
809
810impl<const N: usize> BorrowMut<str> for StackStr<N> {
811 #[inline(always)]
812 fn borrow_mut(&mut self) -> &mut str {
813 self
814 }
815}
816
817impl<const N: usize> Default for StackStr<N> {
818 /// Creates an empty `StackStr<N>`.
819 #[inline(always)]
820 fn default() -> StackStr<N> {
821 StackStr::new()
822 }
823}
824
825impl<const N: usize> fmt::Debug for StackStr<N> {
826 #[inline]
827 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
828 (**self).fmt(f)
829 }
830}
831
832impl<const N: usize> fmt::Display for StackStr<N> {
833 #[inline]
834 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
835 (**self).fmt(f)
836 }
837}
838
839impl<const N: usize> fmt::Write for StackStr<N> {
840 #[inline]
841 fn write_str(&mut self, s: &str) -> fmt::Result {
842 self.push_str(s);
843 Ok(())
844 }
845}
846
847impl<const N1: usize, const N2: usize> PartialEq<StackStr<N2>> for StackStr<N1> {
848 #[inline]
849 fn eq(&self, other: &StackStr<N2>) -> bool {
850 **self == **other
851 }
852}
853
854impl<const N: usize> PartialEq<str> for StackStr<N> {
855 #[inline]
856 fn eq(&self, other: &str) -> bool {
857 &**self == other
858 }
859}
860
861impl<const N: usize> PartialEq<StackStr<N>> for str {
862 #[inline]
863 fn eq(&self, other: &StackStr<N>) -> bool {
864 self == &**other
865 }
866}
867
868impl<const N: usize> PartialEq<&str> for StackStr<N> {
869 #[inline]
870 fn eq(&self, other: &&str) -> bool {
871 &**self == *other
872 }
873}
874
875impl<const N: usize> PartialEq<StackStr<N>> for &str {
876 #[inline]
877 fn eq(&self, other: &StackStr<N>) -> bool {
878 *self == &**other
879 }
880}
881
882impl<const N: usize> Eq for StackStr<N> {}
883
884impl<const N1: usize, const N2: usize> PartialOrd<StackStr<N2>> for StackStr<N1> {
885 #[inline]
886 fn partial_cmp(&self, other: &StackStr<N2>) -> Option<Ordering> {
887 (**self).partial_cmp(&**other)
888 }
889}
890
891impl<const N: usize> PartialOrd<str> for StackStr<N> {
892 #[inline]
893 fn partial_cmp(&self, other: &str) -> Option<Ordering> {
894 (**self).partial_cmp(other)
895 }
896}
897
898impl<const N: usize> PartialOrd<StackStr<N>> for str {
899 #[inline]
900 fn partial_cmp(&self, other: &StackStr<N>) -> Option<Ordering> {
901 self.partial_cmp(&**other)
902 }
903}
904
905impl<const N: usize> PartialOrd<&str> for StackStr<N> {
906 #[inline]
907 fn partial_cmp(&self, other: &&str) -> Option<Ordering> {
908 (**self).partial_cmp(*other)
909 }
910}
911
912impl<const N: usize> PartialOrd<StackStr<N>> for &str {
913 #[inline]
914 fn partial_cmp(&self, other: &StackStr<N>) -> Option<Ordering> {
915 (*self).partial_cmp(&**other)
916 }
917}
918
919impl<const N: usize> Ord for StackStr<N> {
920 #[inline]
921 fn cmp(&self, other: &Self) -> Ordering {
922 (**self).cmp(&**other)
923 }
924}
925
926impl<const N: usize> Extend<char> for StackStr<N> {
927 #[inline]
928 fn extend<I: IntoIterator<Item = char>>(&mut self, iter: I) {
929 let iterator = iter.into_iter();
930 iterator.for_each(move |c| self.push(c));
931 }
932}
933
934impl<'a, const N: usize> Extend<&'a char> for StackStr<N> {
935 #[inline]
936 fn extend<I: IntoIterator<Item = &'a char>>(&mut self, iter: I) {
937 self.extend(iter.into_iter().cloned());
938 }
939}
940
941impl<'a, const N: usize> Extend<&'a str> for StackStr<N> {
942 #[inline]
943 fn extend<I: IntoIterator<Item = &'a str>>(&mut self, iter: I) {
944 iter.into_iter().for_each(move |s| self.push_str(s));
945 }
946}
947
948#[cfg(feature = "std")]
949#[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "str"))))]
950impl<const N: usize> Extend<Box<str>> for StackStr<N> {
951 #[inline]
952 fn extend<I: IntoIterator<Item = Box<str>>>(&mut self, iter: I) {
953 iter.into_iter().for_each(move |s| self.push_str(&s));
954 }
955}
956
957#[cfg(feature = "std")]
958#[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "str"))))]
959impl<const N: usize> Extend<String> for StackStr<N> {
960 #[inline]
961 fn extend<I: IntoIterator<Item = String>>(&mut self, iter: I) {
962 iter.into_iter().for_each(move |s| self.push_str(&s));
963 }
964}
965
966#[cfg(feature = "std")]
967#[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "str"))))]
968impl<'a, const N: usize> Extend<Cow<'a, str>> for StackStr<N> {
969 #[inline]
970 fn extend<I: IntoIterator<Item = Cow<'a, str>>>(&mut self, iter: I) {
971 iter.into_iter().for_each(move |s| self.push_str(&s));
972 }
973}
974
975impl<const N: usize> FromIterator<char> for StackStr<N> {
976 #[inline]
977 fn from_iter<I: IntoIterator<Item = char>>(iter: I) -> Self {
978 let mut buf = StackStr::new();
979 buf.extend(iter);
980 buf
981 }
982}
983
984impl<'a, const N: usize> FromIterator<&'a char> for StackStr<N> {
985 #[inline]
986 fn from_iter<I: IntoIterator<Item = &'a char>>(iter: I) -> Self {
987 let mut buf = StackStr::new();
988 buf.extend(iter);
989 buf
990 }
991}
992
993impl<'a, const N: usize> FromIterator<&'a str> for StackStr<N> {
994 #[inline]
995 fn from_iter<I: IntoIterator<Item = &'a str>>(iter: I) -> Self {
996 let mut buf = StackStr::new();
997 buf.extend(iter);
998 buf
999 }
1000}
1001
1002#[cfg(feature = "std")]
1003#[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "str"))))]
1004impl<const N: usize> FromIterator<String> for StackStr<N> {
1005 #[inline]
1006 fn from_iter<I: IntoIterator<Item = String>>(iter: I) -> Self {
1007 let mut buf = StackStr::new();
1008 buf.extend(iter);
1009 buf
1010 }
1011}
1012
1013#[cfg(feature = "std")]
1014#[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "str"))))]
1015impl<const N: usize> FromIterator<Box<str>> for StackStr<N> {
1016 #[inline]
1017 fn from_iter<I: IntoIterator<Item = Box<str>>>(iter: I) -> Self {
1018 let mut buf = StackStr::new();
1019 buf.extend(iter);
1020 buf
1021 }
1022}
1023
1024#[cfg(feature = "std")]
1025#[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "str"))))]
1026impl<'a, const N: usize> FromIterator<Cow<'a, str>> for StackStr<N> {
1027 #[inline]
1028 fn from_iter<I: IntoIterator<Item = Cow<'a, str>>>(iter: I) -> Self {
1029 let mut buf = StackStr::new();
1030 buf.extend(iter);
1031 buf
1032 }
1033}
1034
1035impl<const N: usize> From<&str> for StackStr<N> {
1036 #[inline]
1037 fn from(s: &str) -> Self {
1038 let mut buf = StackStr::new();
1039 buf.push_str(s);
1040 buf
1041 }
1042}
1043
1044impl<const N: usize> From<&mut str> for StackStr<N> {
1045 #[inline]
1046 fn from(s: &mut str) -> Self {
1047 let mut buf = StackStr::new();
1048 buf.push_str(s);
1049 buf
1050 }
1051}
1052
1053impl<const N1: usize, const N2: usize> From<&StackStr<N2>> for StackStr<N1> {
1054 #[inline]
1055 fn from(s: &StackStr<N2>) -> Self {
1056 let mut buf = StackStr::new();
1057 buf.push_str(s);
1058 buf
1059 }
1060}
1061
1062#[cfg(feature = "std")]
1063#[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "str"))))]
1064impl<const N: usize> From<Box<str>> for StackStr<N> {
1065 /// Converts the given boxed `str` slice to a `StrackStr`.
1066 /// It is notable that the `str` slice is owned.
1067 ///
1068 /// # Examples
1069 ///
1070 /// ```
1071 /// use stack_buf::StackStr;
1072 ///
1073 /// let s1 = String::from("hello world");
1074 /// let s2 = s1.into_boxed_str();
1075 /// let s3 = StackStr::<16>::from(s2);
1076 ///
1077 /// assert_eq!("hello world", s3)
1078 /// ```
1079 #[inline]
1080 fn from(s: Box<str>) -> Self {
1081 let mut buf = StackStr::new();
1082 buf.push_str(&s);
1083 buf
1084 }
1085}
1086
1087#[cfg(feature = "std")]
1088#[cfg_attr(docsrs, doc(cfg(all(feature = "std", feature = "str"))))]
1089impl<const N: usize> From<Cow<'_, str>> for StackStr<N> {
1090 #[inline]
1091 fn from(s: Cow<'_, str>) -> Self {
1092 let mut buf = StackStr::new();
1093 buf.push_str(&s);
1094 buf
1095 }
1096}
1097
1098impl<const N: usize> Hash for StackStr<N> {
1099 #[inline]
1100 fn hash<H: Hasher>(&self, hasher: &mut H) {
1101 (**self).hash(hasher)
1102 }
1103}
1104
1105/// Implements the `+` operator for concatenating two strings.
1106///
1107/// This consumes the `StackStr` on the left-hand side and re-uses its buffer.
1108/// This is done to avoid allocating a new `StackStr` and copying the entire contents on
1109/// every operation, which would lead to *O*(*n*^2) running time when building an *n*-byte string by
1110/// repeated concatenation.
1111///
1112/// The string on the right-hand side is only borrowed; its contents are copied into the returned
1113/// `StackStr`.
1114///
1115/// # Examples
1116///
1117/// Concatenating two `StackStr`s takes the first by value and borrows the second:
1118///
1119/// ```
1120/// use stack_buf::StackStr;
1121///
1122/// let a = StackStr::<16>::from("hello");
1123/// let b = StackStr::<6>::from(" world");
1124/// let c = a + &b;
1125/// // `a` is moved and can no longer be used here.
1126///
1127/// assert_eq!(c, "hello world");
1128/// ```
1129///
1130/// If you want to keep using the first `StackStr`, you can clone it and append to the clone instead:
1131///
1132/// ```
1133/// use stack_buf::StackStr;
1134///
1135/// let a = StackStr::<16>::from("hello");
1136/// let b = StackStr::<6>::from(" world");
1137/// let c = a.clone() + &b;
1138/// // `a` is still valid here.
1139///
1140/// assert_eq!(c, "hello world");
1141/// ```
1142impl<const N: usize> Add<&str> for StackStr<N> {
1143 type Output = StackStr<N>;
1144
1145 #[inline]
1146 fn add(mut self, other: &str) -> Self {
1147 self.push_str(other);
1148 self
1149 }
1150}
1151
1152/// Implements the `+=` operator for appending to a `StackStr`.
1153///
1154/// This has the same behavior as the [`push_str`][StackStr::push_str] method.
1155impl<const N: usize> AddAssign<&str> for StackStr<N> {
1156 #[inline]
1157 fn add_assign(&mut self, other: &str) {
1158 self.push_str(other);
1159 }
1160}
1161
1162impl<const N: usize> FromStr for StackStr<N> {
1163 type Err = std::convert::Infallible;
1164
1165 #[inline]
1166 fn from_str(s: &str) -> Result<Self, Self::Err> {
1167 Ok(StackStr::from(s))
1168 }
1169}
1170
1171impl<const N: usize> From<StackStr<N>> for StackVec<u8, N> {
1172 #[inline]
1173 fn from(s: StackStr<N>) -> Self {
1174 s.into_bytes()
1175 }
1176}
1177
1178#[cfg(all(test, feature = "std"))]
1179mod tests {
1180 use super::StackStr;
1181
1182 #[test]
1183 fn retain_keeps_a_valid_prefix_when_predicate_panics() {
1184 let mut value = StackStr::<4>::from("aéz");
1185 let result = std::panic::catch_unwind(std::panic::AssertUnwindSafe(|| {
1186 value.retain(|ch| match ch {
1187 'a' => false,
1188 'é' => true,
1189 _ => panic!("predicate failed"),
1190 });
1191 }));
1192
1193 assert!(result.is_err());
1194 assert_eq!(value, "é");
1195 }
1196}
1197
1198#[cfg(feature = "serde")]
1199mod impl_serde {
1200 use super::*;
1201 use serde::de::{Error, Unexpected, Visitor};
1202 use serde::{Deserialize, Deserializer, Serialize, Serializer};
1203 use std::marker::PhantomData;
1204
1205 #[cfg_attr(docsrs, doc(cfg(all(feature = "str", feature = "serde"))))]
1206 impl<const N: usize> Serialize for StackStr<N> {
1207 #[inline]
1208 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
1209 where
1210 S: Serializer,
1211 {
1212 serializer.serialize_str(self)
1213 }
1214 }
1215
1216 #[cfg_attr(docsrs, doc(cfg(all(feature = "str", feature = "serde"))))]
1217 impl<'de, const N: usize> Deserialize<'de> for StackStr<N> {
1218 #[inline]
1219 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
1220 where
1221 D: Deserializer<'de>,
1222 {
1223 struct StackStrVisitor<const N: usize>(PhantomData<[u8; N]>);
1224
1225 impl<const N: usize> Visitor<'_> for StackStrVisitor<N> {
1226 type Value = StackStr<N>;
1227
1228 #[inline]
1229 fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
1230 write!(formatter, "a string with no more than {} bytes", N)
1231 }
1232
1233 #[inline]
1234 fn visit_str<E>(self, v: &str) -> Result<Self::Value, E>
1235 where
1236 E: Error,
1237 {
1238 Ok(StackStr::from(v))
1239 }
1240
1241 #[inline]
1242 fn visit_bytes<E>(self, v: &[u8]) -> Result<Self::Value, E>
1243 where
1244 E: Error,
1245 {
1246 let s = str::from_utf8(v)
1247 .map_err(|_| E::invalid_value(Unexpected::Bytes(v), &self))?;
1248 Ok(StackStr::from(s))
1249 }
1250 }
1251
1252 deserializer.deserialize_str(StackStrVisitor::<N>(PhantomData))
1253 }
1254 }
1255}