heapless/string/
mod.rs

1//! A fixed capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html).
2
3use core::{
4    borrow,
5    char::DecodeUtf16Error,
6    cmp::Ordering,
7    fmt,
8    fmt::{Arguments, Write},
9    hash, iter,
10    ops::{self, Range, RangeBounds},
11    str::{self, Utf8Error},
12};
13
14#[cfg(feature = "zeroize")]
15use zeroize::Zeroize;
16
17use crate::{
18    len_type::LenType,
19    vec::{OwnedVecStorage, Vec, VecInner, ViewVecStorage},
20    CapacityError,
21};
22
23mod drain;
24pub use drain::Drain;
25
26/// A possible error value when converting a [`String`] from a UTF-16 byte slice.
27///
28/// This type is the error type for the [`from_utf16`] method on [`String`].
29///
30/// [`from_utf16`]: String::from_utf16
31#[derive(Debug)]
32pub enum FromUtf16Error {
33    /// The capacity of the `String` is too small for the given operation.
34    Capacity(CapacityError),
35    /// Error decoding UTF-16.
36    DecodeUtf16(DecodeUtf16Error),
37}
38
39impl fmt::Display for FromUtf16Error {
40    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
41        match self {
42            Self::Capacity(err) => write!(f, "{err}"),
43            Self::DecodeUtf16(err) => write!(f, "invalid UTF-16: {err}"),
44        }
45    }
46}
47
48impl core::error::Error for FromUtf16Error {}
49
50impl From<CapacityError> for FromUtf16Error {
51    fn from(e: CapacityError) -> Self {
52        Self::Capacity(e)
53    }
54}
55
56mod storage {
57    use super::{StringInner, StringView};
58    use crate::{
59        vec::{OwnedVecStorage, VecStorage, ViewVecStorage},
60        LenType,
61    };
62
63    /// Trait defining how data for a String is stored.
64    ///
65    /// There's two implementations available:
66    ///
67    /// - [`OwnedStorage`]: stores the data in an array whose size is known at compile time.
68    /// - [`ViewStorage`]: stores the data in an unsized slice
69    ///
70    /// This allows [`String`] to be generic over either sized or unsized storage. The
71    /// [`string`](super) module contains a [`StringInner`] struct that's generic on
72    /// [`StringStorage`], and two type aliases for convenience:
73    ///
74    /// - [`String<N>`](crate::string::String) = `StringInner<OwnedStorage<u8, N>>`
75    /// - [`StringView<T>`](crate::string::StringView) = `StringInner<ViewStorage<u8>>`
76    ///
77    /// `String` can be unsized into `StrinsgView`, either by unsizing coercions such as `&mut
78    /// String -> &mut StringView` or `Box<String> -> Box<StringView>`, or explicitly with
79    /// [`.as_view()`](crate::string::String::as_view) or
80    /// [`.as_mut_view()`](crate::string::String::as_mut_view).
81    ///
82    /// This trait is sealed, so you cannot implement it for your own types. You can only use
83    /// the implementations provided by this crate.
84    ///
85    /// [`StringInner`]: super::StringInner
86    /// [`String`]: super::String
87    /// [`OwnedStorage`]: super::OwnedStorage
88    /// [`ViewStorage`]: super::ViewStorage
89    pub trait StringStorage: StringStorageSealed {}
90    pub trait StringStorageSealed: VecStorage<u8> {
91        fn as_string_view<LenT: LenType>(this: &StringInner<LenT, Self>) -> &StringView<LenT>
92        where
93            Self: StringStorage;
94        fn as_string_mut_view<LenT: LenType>(
95            this: &mut StringInner<LenT, Self>,
96        ) -> &mut StringView<LenT>
97        where
98            Self: StringStorage;
99    }
100
101    impl<const N: usize> StringStorage for OwnedVecStorage<u8, N> {}
102    impl<const N: usize> StringStorageSealed for OwnedVecStorage<u8, N> {
103        fn as_string_view<LenT: LenType>(this: &StringInner<LenT, Self>) -> &StringView<LenT>
104        where
105            Self: StringStorage,
106        {
107            this
108        }
109        fn as_string_mut_view<LenT: LenType>(
110            this: &mut StringInner<LenT, Self>,
111        ) -> &mut StringView<LenT>
112        where
113            Self: StringStorage,
114        {
115            this
116        }
117    }
118
119    impl StringStorage for ViewVecStorage<u8> {}
120
121    impl StringStorageSealed for ViewVecStorage<u8> {
122        fn as_string_view<LenT: LenType>(this: &StringInner<LenT, Self>) -> &StringView<LenT>
123        where
124            Self: StringStorage,
125        {
126            this
127        }
128        fn as_string_mut_view<LenT: LenType>(
129            this: &mut StringInner<LenT, Self>,
130        ) -> &mut StringView<LenT>
131        where
132            Self: StringStorage,
133        {
134            this
135        }
136    }
137}
138
139pub use storage::StringStorage;
140
141/// Implementation of [`StringStorage`] that stores the data in an array whose size is known at
142/// compile time.
143pub type OwnedStorage<const N: usize> = OwnedVecStorage<u8, N>;
144/// Implementation of [`StringStorage`] that stores the data in an unsized slice.
145pub type ViewStorage = ViewVecStorage<u8>;
146
147/// Base struct for [`String`] and [`StringView`], generic over the [`StringStorage`].
148///
149/// In most cases you should use [`String`] or [`StringView`] directly. Only use this
150/// struct if you want to write code that's generic over both.
151#[cfg_attr(feature = "zeroize", derive(Zeroize), zeroize(bound = "S: Zeroize"))]
152pub struct StringInner<LenT: LenType, S: StringStorage + ?Sized> {
153    vec: VecInner<u8, LenT, S>,
154}
155
156/// A fixed capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html).
157pub type String<const N: usize, LenT = usize> = StringInner<LenT, OwnedStorage<N>>;
158
159/// A dynamic capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html).
160pub type StringView<LenT = usize> = StringInner<LenT, ViewStorage>;
161
162impl<LenT: LenType, const N: usize> String<N, LenT> {
163    /// Constructs a new, empty `String` with a fixed capacity of `N` bytes.
164    ///
165    /// # Examples
166    ///
167    /// Basic usage:
168    ///
169    /// ```
170    /// use heapless::String;
171    ///
172    /// // allocate the string on the stack
173    /// let mut s: String<4> = String::new();
174    ///
175    /// // allocate the string in a static variable
176    /// static mut S: String<4> = String::new();
177    /// ```
178    #[inline]
179    pub const fn new() -> Self {
180        Self { vec: Vec::new() }
181    }
182
183    /// Decodes a UTF-16–encoded slice `v` into a `String`, returning [`Err`]
184    /// if `v` contains any invalid data.
185    ///
186    /// # Examples
187    ///
188    /// Basic usage:
189    ///
190    /// ```
191    /// use heapless::String;
192    ///
193    /// // 𝄞music
194    /// let v = &[0xD834, 0xDD1E, 0x006d, 0x0075, 0x0073, 0x0069, 0x0063];
195    /// let s: String<10> = String::from_utf16(v).unwrap();
196    /// assert_eq!(s, "𝄞music");
197    ///
198    /// // 𝄞mu<invalid>ic
199    /// let v = &[0xD834, 0xDD1E, 0x006d, 0x0075, 0xD800, 0x0069, 0x0063];
200    /// assert!(String::<10>::from_utf16(v).is_err());
201    /// ```
202    #[inline]
203    pub fn from_utf16(v: &[u16]) -> Result<Self, FromUtf16Error> {
204        let mut s = Self::new();
205
206        for c in char::decode_utf16(v.iter().cloned()) {
207            match c {
208                Ok(c) => {
209                    s.push(c).map_err(|_| CapacityError)?;
210                }
211                Err(err) => {
212                    return Err(FromUtf16Error::DecodeUtf16(err));
213                }
214            }
215        }
216
217        Ok(s)
218    }
219
220    /// Convert UTF-8 bytes into a `String`.
221    ///
222    /// # Examples
223    ///
224    /// Basic usage:
225    ///
226    /// ```
227    /// use heapless::{String, Vec};
228    ///
229    /// let mut sparkle_heart = Vec::<u8, 4>::new();
230    /// sparkle_heart.extend_from_slice(&[240, 159, 146, 150]);
231    ///
232    /// let sparkle_heart: String<4> = String::from_utf8(sparkle_heart)?;
233    /// assert_eq!("💖", sparkle_heart);
234    /// # Ok::<(), core::str::Utf8Error>(())
235    /// ```
236    ///
237    /// Invalid UTF-8:
238    ///
239    /// ```
240    /// use core::str::Utf8Error;
241    /// use heapless::{String, Vec};
242    ///
243    /// let mut vec = Vec::<u8, 4>::new();
244    /// vec.extend_from_slice(&[0, 159, 146, 150]);
245    ///
246    /// let e: Utf8Error = String::from_utf8(vec).unwrap_err();
247    /// assert_eq!(e.valid_up_to(), 1);
248    /// # Ok::<(), core::str::Utf8Error>(())
249    /// ```
250    #[inline]
251    pub fn from_utf8(vec: Vec<u8, N, LenT>) -> Result<Self, Utf8Error> {
252        core::str::from_utf8(&vec)?;
253
254        // SAFETY: UTF-8 invariant has just been checked by `str::from_utf8`.
255        Ok(unsafe { Self::from_utf8_unchecked(vec) })
256    }
257
258    /// Convert UTF-8 bytes into a `String`, without checking that the string
259    /// contains valid UTF-8.
260    ///
261    /// # Safety
262    ///
263    /// The bytes passed in must be valid UTF-8.
264    ///
265    /// # Examples
266    ///
267    /// Basic usage:
268    ///
269    /// ```
270    /// use heapless::{String, Vec};
271    ///
272    /// let mut sparkle_heart = Vec::<u8, 4>::new();
273    /// sparkle_heart.extend_from_slice(&[240, 159, 146, 150]);
274    ///
275    /// // Safety: `sparkle_heart` Vec is known to contain valid UTF-8
276    /// let sparkle_heart: String<4> = unsafe { String::from_utf8_unchecked(sparkle_heart) };
277    /// assert_eq!("💖", sparkle_heart);
278    /// ```
279    #[inline]
280    pub unsafe fn from_utf8_unchecked(vec: Vec<u8, N, LenT>) -> Self {
281        Self { vec }
282    }
283
284    /// Converts a `String` into a byte vector.
285    ///
286    /// This consumes the `String`, so we do not need to copy its contents.
287    ///
288    /// # Examples
289    ///
290    /// Basic usage:
291    ///
292    /// ```
293    /// use heapless::String;
294    ///
295    /// let s: String<4> = String::try_from("ab")?;
296    /// let b = s.into_bytes();
297    /// assert!(b.len() == 2);
298    ///
299    /// assert_eq!(&[b'a', b'b'], &b[..]);
300    /// # Ok::<(), heapless::CapacityError>(())
301    /// ```
302    #[inline]
303    pub fn into_bytes(self) -> Vec<u8, N, LenT> {
304        self.vec
305    }
306}
307
308impl<LenT: LenType, S: StringStorage + ?Sized> StringInner<LenT, S> {
309    /// Removes the specified range from the string in bulk, returning all
310    /// removed characters as an iterator.
311    ///
312    /// The returned iterator keeps a mutable borrow on the string to optimize
313    /// its implementation.
314    ///
315    /// # Panics
316    ///
317    /// Panics if the starting point or end point do not lie on a [`char`]
318    /// boundary, or if they're out of bounds.
319    ///
320    /// # Leaking
321    ///
322    /// If the returned iterator goes out of scope without being dropped (due to
323    /// [`core::mem::forget`], for example), the string may still contain a copy
324    /// of any drained characters, or may have lost characters arbitrarily,
325    /// including characters outside the range.
326    ///
327    /// # Examples
328    ///
329    /// ```
330    /// use heapless::String;
331    ///
332    /// let mut s = String::<32>::try_from("α is alpha, β is beta").unwrap();
333    /// let beta_offset = s.find('β').unwrap_or(s.len());
334    ///
335    /// // Remove the range up until the β from the string
336    /// let t: String<32> = s.drain(..beta_offset).collect();
337    /// assert_eq!(t, "α is alpha, ");
338    /// assert_eq!(s, "β is beta");
339    ///
340    /// // A full range clears the string, like `clear()` does
341    /// s.drain(..);
342    /// assert_eq!(s, "");
343    /// ```
344    pub fn drain<R>(&mut self, range: R) -> Drain<'_, LenT>
345    where
346        R: RangeBounds<usize>,
347    {
348        // Memory safety
349        //
350        // The `String` version of `Drain` does not have the memory safety issues
351        // of the `Vec` version. The data is just plain bytes.
352        // Because the range removal happens in `Drop`, if the `Drain` iterator is leaked,
353        // the removal will not happen.
354        let Range { start, end } = crate::slice::range(range, ..self.len());
355        assert!(self.is_char_boundary(start));
356        assert!(self.is_char_boundary(end));
357
358        // Take out two simultaneous borrows. The &mut String won't be accessed
359        // until iteration is over, in Drop.
360        let self_ptr = self.as_mut_view() as *mut _;
361        // SAFETY: `slice::range` and `is_char_boundary` do the appropriate bounds checks.
362        let chars_iter = unsafe { self.get_unchecked(start..end) }.chars();
363
364        Drain {
365            start: LenT::from_usize(start),
366            end: LenT::from_usize(end),
367            iter: chars_iter,
368            string: self_ptr,
369        }
370    }
371
372    /// Get a reference to the `String`, erasing the `N` const-generic.
373    ///
374    ///
375    /// ```rust
376    /// # use heapless::string::{String, StringView};
377    /// let s: String<10, _> = String::try_from("hello").unwrap();
378    /// let view: &StringView = s.as_view();
379    /// ```
380    ///
381    /// It is often preferable to do the same through type coerction, since `String<N>` implements
382    /// `Unsize<StringView>`:
383    ///
384    /// ```rust
385    /// # use heapless::string::{String, StringView};
386    /// let s: String<10, _> = String::try_from("hello").unwrap();
387    /// let view: &StringView = &s;
388    /// ```
389    #[inline]
390    pub fn as_view(&self) -> &StringView<LenT> {
391        S::as_string_view(self)
392    }
393
394    /// Get a mutable reference to the `String`, erasing the `N` const-generic.
395    ///
396    ///
397    /// ```rust
398    /// # use heapless::string::{String, StringView};
399    /// let mut s: String<10> = String::try_from("hello").unwrap();
400    /// let view: &mut StringView = s.as_mut_view();
401    /// ```
402    ///
403    /// It is often preferable to do the same through type coerction, since `String<N>` implements
404    /// `Unsize<StringView>`:
405    ///
406    /// ```rust
407    /// # use heapless::string::{String, StringView};
408    /// let mut s: String<10> = String::try_from("hello").unwrap();
409    /// let view: &mut StringView = &mut s;
410    /// ```
411    #[inline]
412    pub fn as_mut_view(&mut self) -> &mut StringView<LenT> {
413        S::as_string_mut_view(self)
414    }
415
416    /// Extracts a string slice containing the entire string.
417    ///
418    /// # Examples
419    ///
420    /// Basic usage:
421    ///
422    /// ```
423    /// use heapless::String;
424    ///
425    /// let mut s: String<4> = String::try_from("ab")?;
426    /// assert!(s.as_str() == "ab");
427    ///
428    /// let _s = s.as_str();
429    /// // s.push('c'); // <- cannot borrow `s` as mutable because it is also borrowed as immutable
430    /// # Ok::<(), heapless::CapacityError>(())
431    /// ```
432    #[inline]
433    pub fn as_str(&self) -> &str {
434        unsafe { str::from_utf8_unchecked(self.vec.as_slice()) }
435    }
436
437    /// Converts a `String` into a mutable string slice.
438    ///
439    /// # Examples
440    ///
441    /// Basic usage:
442    ///
443    /// ```
444    /// use heapless::String;
445    ///
446    /// let mut s: String<4> = String::try_from("ab")?;
447    /// let s = s.as_mut_str();
448    /// s.make_ascii_uppercase();
449    /// # Ok::<(), heapless::CapacityError>(())
450    /// ```
451    #[inline]
452    pub fn as_mut_str(&mut self) -> &mut str {
453        unsafe { str::from_utf8_unchecked_mut(self.vec.as_mut_slice()) }
454    }
455
456    /// Returns a mutable reference to the contents of this `String`.
457    ///
458    /// # Safety
459    ///
460    /// This function is unsafe because it does not check that the bytes passed
461    /// to it are valid UTF-8. If this constraint is violated, it may cause
462    /// memory unsafety issues with future users of the `String`, as the rest of
463    /// the library assumes that `String`s are valid UTF-8.
464    ///
465    /// # Examples
466    ///
467    /// Basic usage:
468    ///
469    /// ```
470    /// use heapless::String;
471    ///
472    /// let mut s: String<8> = String::try_from("hello")?;
473    ///
474    /// unsafe {
475    ///     let vec = s.as_mut_vec();
476    ///     assert_eq!(&[104, 101, 108, 108, 111][..], &vec[..]);
477    ///
478    ///     vec.reverse();
479    /// }
480    /// assert_eq!(s, "olleh");
481    /// # Ok::<(), heapless::CapacityError>(())
482    /// ```
483    pub unsafe fn as_mut_vec(&mut self) -> &mut VecInner<u8, LenT, S> {
484        &mut self.vec
485    }
486
487    /// Appends a given string slice onto the end of this `String`.
488    ///
489    /// # Examples
490    ///
491    /// Basic usage:
492    ///
493    /// ```
494    /// use heapless::String;
495    ///
496    /// let mut s: String<8> = String::try_from("foo")?;
497    ///
498    /// assert!(s.push_str("bar").is_ok());
499    ///
500    /// assert_eq!("foobar", s);
501    ///
502    /// assert!(s.push_str("tender").is_err());
503    /// # Ok::<(), heapless::CapacityError>(())
504    /// ```
505    #[inline]
506    pub fn push_str(&mut self, string: &str) -> Result<(), CapacityError> {
507        self.vec.extend_from_slice(string.as_bytes())
508    }
509
510    /// Returns the maximum number of elements the String can hold.
511    ///
512    /// # Examples
513    ///
514    /// Basic usage:
515    ///
516    /// ```
517    /// use heapless::String;
518    ///
519    /// let mut s: String<4> = String::new();
520    /// assert!(s.capacity() == 4);
521    /// ```
522    #[inline]
523    pub fn capacity(&self) -> usize {
524        self.vec.capacity()
525    }
526
527    /// Appends the given [`char`] to the end of this `String`.
528    ///
529    /// # Examples
530    ///
531    /// Basic usage:
532    ///
533    /// ```
534    /// use heapless::String;
535    ///
536    /// let mut s: String<8> = String::try_from("abc")?;
537    ///
538    /// s.push('1').unwrap();
539    /// s.push('2').unwrap();
540    /// s.push('3').unwrap();
541    ///
542    /// assert!("abc123" == s.as_str());
543    ///
544    /// assert_eq!("abc123", s);
545    /// # Ok::<(), heapless::CapacityError>(())
546    /// ```
547    #[inline]
548    pub fn push(&mut self, c: char) -> Result<(), CapacityError> {
549        match c.len_utf8() {
550            1 => self.vec.push(c as u8).map_err(|_| CapacityError),
551            _ => self
552                .vec
553                .extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()),
554        }
555    }
556
557    /// Shortens this `String` to the specified length.
558    ///
559    /// If `new_len` is greater than the string's current length, this has no
560    /// effect.
561    ///
562    /// Note that this method has no effect on the allocated capacity
563    /// of the string
564    ///
565    /// # Panics
566    ///
567    /// Panics if `new_len` does not lie on a [`char`] boundary.
568    ///
569    /// # Examples
570    ///
571    /// Basic usage:
572    ///
573    /// ```
574    /// use heapless::String;
575    ///
576    /// let mut s: String<8> = String::try_from("hello")?;
577    ///
578    /// s.truncate(2);
579    ///
580    /// assert_eq!("he", s);
581    /// # Ok::<(), heapless::CapacityError>(())
582    /// ```
583    #[inline]
584    pub fn truncate(&mut self, new_len: usize) {
585        if new_len <= self.len() {
586            assert!(self.is_char_boundary(new_len));
587            self.vec.truncate(new_len);
588        }
589    }
590
591    /// Removes the last character from the string buffer and returns it.
592    ///
593    /// Returns [`None`] if this `String` is empty.
594    ///
595    /// # Examples
596    ///
597    /// Basic usage:
598    ///
599    /// ```
600    /// use heapless::String;
601    ///
602    /// let mut s: String<8> = String::try_from("foo")?;
603    ///
604    /// assert_eq!(s.pop(), Some('o'));
605    /// assert_eq!(s.pop(), Some('o'));
606    /// assert_eq!(s.pop(), Some('f'));
607    ///
608    /// assert_eq!(s.pop(), None);
609    /// Ok::<(), heapless::CapacityError>(())
610    /// ```
611    pub fn pop(&mut self) -> Option<char> {
612        let ch = self.chars().next_back()?;
613
614        // pop bytes that correspond to `ch`
615        for _ in 0..ch.len_utf8() {
616            unsafe {
617                self.vec.pop_unchecked();
618            }
619        }
620
621        Some(ch)
622    }
623
624    /// Removes a [`char`] from this `String` at a byte position and returns it.
625    ///
626    /// Note: Because this shifts over the remaining elements, it has a
627    /// worst-case performance of *O*(n).
628    ///
629    /// # Panics
630    ///
631    /// Panics if `idx` is larger than or equal to the `String`'s length,
632    /// or if it does not lie on a [`char`] boundary.
633    ///
634    /// # Examples
635    ///
636    /// Basic usage:
637    ///
638    /// ```
639    /// use heapless::String;
640    ///
641    /// let mut s: String<8> = String::try_from("foo").unwrap();
642    ///
643    /// assert_eq!(s.remove(0), 'f');
644    /// assert_eq!(s.remove(1), 'o');
645    /// assert_eq!(s.remove(0), 'o');
646    /// ```
647    #[inline]
648    pub fn remove(&mut self, index: usize) -> char {
649        let ch = self[index..]
650            .chars()
651            .next()
652            .unwrap_or_else(|| panic!("cannot remove a char from the end of a string"));
653
654        let next = index + ch.len_utf8();
655        let len = self.len();
656        let ptr = self.vec.as_mut_ptr();
657        unsafe {
658            core::ptr::copy(ptr.add(next), ptr.add(index), len - next);
659            self.vec.set_len(len - (next - index));
660        }
661        ch
662    }
663
664    /// Truncates this `String`, removing all contents.
665    ///
666    /// While this means the `String` will have a length of zero, it does not
667    /// touch its capacity.
668    ///
669    /// # Examples
670    ///
671    /// Basic usage:
672    ///
673    /// ```
674    /// use heapless::String;
675    ///
676    /// let mut s: String<8> = String::try_from("foo")?;
677    ///
678    /// s.clear();
679    ///
680    /// assert!(s.is_empty());
681    /// assert_eq!(0, s.len());
682    /// assert_eq!(8, s.capacity());
683    /// Ok::<(), heapless::CapacityError>(())
684    /// ```
685    #[inline]
686    pub fn clear(&mut self) {
687        self.vec.clear();
688    }
689
690    /// Inserts a character into this `String` at a byte position.
691    ///
692    /// This is an *O*(*n*) operation as it requires copying every element in the
693    /// buffer.
694    ///
695    /// # Panics
696    ///
697    /// Panics if `idx` is larger than the `String`'s length, or if it does not
698    /// lie on a [`char`] boundary.
699    ///
700    /// # Examples
701    ///
702    /// ```
703    /// use heapless::String;
704    ///
705    /// let mut s: String<4> = String::new();
706    ///
707    /// s.insert(0, 'f').unwrap();
708    /// s.insert(1, 'o').unwrap();
709    /// s.insert(2, 'o').unwrap();
710    ///
711    /// assert_eq!("foo", s);
712    /// # Ok::<(), heapless::CapacityError>(())
713    /// ```
714    #[inline]
715    pub fn insert(&mut self, idx: usize, ch: char) -> Result<(), CapacityError> {
716        assert!(self.is_char_boundary(idx), "index must be a char boundary");
717
718        let len = self.len();
719        let ch_len = ch.len_utf8();
720
721        // Check if there is enough capacity
722        if len + ch_len > self.capacity() {
723            return Err(CapacityError);
724        }
725
726        // SAFETY: Move the bytes starting from `idx` to their new location `ch_len`
727        // bytes ahead. This is safe because we checked `len + ch_len` does not
728        // exceed the capacity and `idx` is a char boundary.
729        unsafe {
730            let ptr = self.vec.as_mut_ptr();
731            core::ptr::copy(ptr.add(idx), ptr.add(idx + ch_len), len - idx);
732        }
733
734        // SAFETY: Encode the character into the vacated region if `idx != len`,
735        // or into the uninitialized spare capacity otherwise. This is safe
736        // because `is_char_boundary` checks that `idx <= len`, and we checked that
737        // `(idx + ch_len)` does not exceed the capacity.
738        unsafe {
739            let buf = core::slice::from_raw_parts_mut(self.vec.as_mut_ptr().add(idx), ch_len);
740            ch.encode_utf8(buf);
741        }
742
743        // SAFETY: Update the length to include the newly added bytes. This is
744        // safe because we checked that `len + ch_len` does not exceed the capacity.
745        unsafe {
746            self.vec.set_len(len + ch_len);
747        }
748
749        Ok(())
750    }
751
752    /// Inserts a string slice into this `String` at a byte position.
753    ///
754    /// This is an *O*(*n*) operation as it requires copying every element in the
755    /// buffer.
756    ///
757    /// # Panics
758    ///
759    /// Panics if `idx` is larger than the `String`'s length, or if it does not
760    /// lie on a [`char`] boundary.
761    ///
762    /// # Examples
763    ///
764    /// ```
765    /// use heapless::String;
766    ///
767    /// let mut s: String<8> = String::try_from("bar")?;
768    ///
769    /// s.insert_str(0, "foo")?;
770    ///
771    /// assert_eq!("foobar", s);
772    /// # Ok::<(), heapless::CapacityError>(())
773    /// ```
774    #[inline]
775    pub fn insert_str(&mut self, idx: usize, string: &str) -> Result<(), CapacityError> {
776        assert!(self.is_char_boundary(idx), "index must be a char boundary");
777
778        let len = self.len();
779        let string_len = string.len();
780
781        // Check if there is enough capacity
782        if len + string_len > self.capacity() {
783            return Err(CapacityError);
784        }
785
786        // SAFETY: Move the bytes starting from `idx` to their new location
787        // `string_len` bytes ahead. This is safe because we checked there is
788        // sufficient capacity, and `idx` is a char boundary.
789        unsafe {
790            let ptr = self.vec.as_mut_ptr();
791            core::ptr::copy(ptr.add(idx), ptr.add(idx + string_len), len - idx);
792        }
793
794        // SAFETY: Copy the new string slice into the vacated region if `idx != len`,
795        // or into the uninitialized spare capacity otherwise. The borrow checker
796        // ensures that the source and destination do not overlap.
797        unsafe {
798            core::ptr::copy_nonoverlapping(
799                string.as_ptr(),
800                self.vec.as_mut_ptr().add(idx),
801                string_len,
802            );
803        }
804
805        // SAFETY: Update the length to include the newly added bytes.
806        unsafe {
807            self.vec.set_len(len + string_len);
808        }
809
810        Ok(())
811    }
812}
813
814impl<LenT: LenType, const N: usize> Default for String<N, LenT> {
815    fn default() -> Self {
816        Self::new()
817    }
818}
819
820impl<'a, LenT: LenType, const N: usize> TryFrom<&'a str> for String<N, LenT> {
821    type Error = CapacityError;
822
823    fn try_from(s: &'a str) -> Result<Self, Self::Error> {
824        let mut new = Self::new();
825        new.push_str(s)?;
826        Ok(new)
827    }
828}
829
830impl<LenT: LenType, const N: usize> str::FromStr for String<N, LenT> {
831    type Err = CapacityError;
832
833    fn from_str(s: &str) -> Result<Self, Self::Err> {
834        let mut new = Self::new();
835        new.push_str(s)?;
836        Ok(new)
837    }
838}
839
840impl<LenT: LenType, const N: usize> iter::FromIterator<char> for String<N, LenT> {
841    fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
842        let mut new = Self::new();
843        for c in iter {
844            new.push(c).unwrap();
845        }
846        new
847    }
848}
849
850impl<'a, LenT: LenType, const N: usize> iter::FromIterator<&'a char> for String<N, LenT> {
851    fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self {
852        let mut new = Self::new();
853        for c in iter {
854            new.push(*c).unwrap();
855        }
856        new
857    }
858}
859
860impl<'a, LenT: LenType, const N: usize> iter::FromIterator<&'a str> for String<N, LenT> {
861    fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
862        let mut new = Self::new();
863        for c in iter {
864            new.push_str(c).unwrap();
865        }
866        new
867    }
868}
869
870impl<LenT: LenType, const N: usize> Clone for String<N, LenT> {
871    fn clone(&self) -> Self {
872        Self {
873            vec: self.vec.clone(),
874        }
875    }
876}
877
878impl<LenT: LenType, S: StringStorage + ?Sized> fmt::Debug for StringInner<LenT, S> {
879    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
880        <str as fmt::Debug>::fmt(self, f)
881    }
882}
883
884impl<LenT: LenType, S: StringStorage + ?Sized> fmt::Display for StringInner<LenT, S> {
885    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
886        <str as fmt::Display>::fmt(self, f)
887    }
888}
889
890impl<LenT: LenType, S: StringStorage + ?Sized> hash::Hash for StringInner<LenT, S> {
891    #[inline]
892    fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
893        <str as hash::Hash>::hash(self, hasher);
894    }
895}
896
897impl<LenT: LenType, S: StringStorage + ?Sized> fmt::Write for StringInner<LenT, S> {
898    fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
899        self.push_str(s).map_err(|_| fmt::Error)
900    }
901
902    fn write_char(&mut self, c: char) -> Result<(), fmt::Error> {
903        self.push(c).map_err(|_| fmt::Error)
904    }
905}
906
907impl<LenT: LenType, S: StringStorage + ?Sized> ops::Deref for StringInner<LenT, S> {
908    type Target = str;
909
910    fn deref(&self) -> &str {
911        self.as_str()
912    }
913}
914
915impl<LenT: LenType, S: StringStorage + ?Sized> ops::DerefMut for StringInner<LenT, S> {
916    fn deref_mut(&mut self) -> &mut str {
917        self.as_mut_str()
918    }
919}
920
921impl<LenT: LenType, S: StringStorage + ?Sized> borrow::Borrow<str> for StringInner<LenT, S> {
922    fn borrow(&self) -> &str {
923        self.as_str()
924    }
925}
926impl<LenT: LenType, S: StringStorage + ?Sized> borrow::BorrowMut<str> for StringInner<LenT, S> {
927    fn borrow_mut(&mut self) -> &mut str {
928        self.as_mut_str()
929    }
930}
931
932impl<LenT: LenType, S: StringStorage + ?Sized> AsRef<str> for StringInner<LenT, S> {
933    #[inline]
934    fn as_ref(&self) -> &str {
935        self
936    }
937}
938
939impl<LenT: LenType, S: StringStorage + ?Sized> AsRef<[u8]> for StringInner<LenT, S> {
940    #[inline]
941    fn as_ref(&self) -> &[u8] {
942        self.as_bytes()
943    }
944}
945
946impl<LenT1: LenType, LenT2: LenType, S1: StringStorage + ?Sized, S2: StringStorage + ?Sized>
947    PartialEq<StringInner<LenT1, S1>> for StringInner<LenT2, S2>
948{
949    fn eq(&self, rhs: &StringInner<LenT1, S1>) -> bool {
950        str::eq(&**self, &**rhs)
951    }
952}
953
954// String<N> == str
955impl<LenT: LenType, S: StringStorage + ?Sized> PartialEq<str> for StringInner<LenT, S> {
956    #[inline]
957    fn eq(&self, other: &str) -> bool {
958        str::eq(self, other)
959    }
960}
961
962// String<N> == &'str
963impl<LenT: LenType, S: StringStorage + ?Sized> PartialEq<&str> for StringInner<LenT, S> {
964    #[inline]
965    fn eq(&self, other: &&str) -> bool {
966        str::eq(self, &other[..])
967    }
968}
969
970// str == String<N>
971impl<LenT: LenType, S: StringStorage + ?Sized> PartialEq<StringInner<LenT, S>> for str {
972    #[inline]
973    fn eq(&self, other: &StringInner<LenT, S>) -> bool {
974        Self::eq(self, &other[..])
975    }
976}
977
978// &'str == String<N>
979impl<LenT: LenType, S: StringStorage + ?Sized> PartialEq<StringInner<LenT, S>> for &str {
980    #[inline]
981    fn eq(&self, other: &StringInner<LenT, S>) -> bool {
982        str::eq(self, &other[..])
983    }
984}
985
986impl<LenT: LenType, S: StringStorage + ?Sized> Eq for StringInner<LenT, S> {}
987
988impl<LenT1: LenType, LenT2: LenType, S1: StringStorage + ?Sized, S2: StringStorage + ?Sized>
989    PartialOrd<StringInner<LenT1, S1>> for StringInner<LenT2, S2>
990{
991    #[inline]
992    fn partial_cmp(&self, other: &StringInner<LenT1, S1>) -> Option<Ordering> {
993        PartialOrd::partial_cmp(&**self, &**other)
994    }
995}
996
997impl<LenT: LenType, S: StringStorage + ?Sized> Ord for StringInner<LenT, S> {
998    #[inline]
999    fn cmp(&self, other: &Self) -> Ordering {
1000        Ord::cmp(&**self, &**other)
1001    }
1002}
1003
1004/// Equivalent to [`format`](https://doc.rust-lang.org/std/fmt/fn.format.html).
1005///
1006/// Please note that using [`format!`] might be preferable.
1007///
1008/// # Errors
1009///
1010/// There are two possible error cases. Both return the unit type [`core::fmt::Error`].
1011///
1012/// - In case the formatting exceeds the string's capacity. This error does not exist in
1013/// the standard library as the string would just grow.
1014/// - If a formatting trait implementation returns an error. The standard library panics
1015/// in this case.
1016///
1017/// [`format!`]: crate::format!
1018#[doc(hidden)]
1019pub fn format<const N: usize, LenT: LenType>(
1020    args: Arguments<'_>,
1021) -> Result<String<N, LenT>, fmt::Error> {
1022    fn format_inner<const N: usize, LenT: LenType>(
1023        args: Arguments<'_>,
1024    ) -> Result<String<N, LenT>, fmt::Error> {
1025        let mut output = String::new();
1026        output.write_fmt(args)?;
1027        Ok(output)
1028    }
1029
1030    args.as_str().map_or_else(
1031        || format_inner(args),
1032        |s| s.try_into().map_err(|_| fmt::Error),
1033    )
1034}
1035
1036/// Macro that creates a fixed capacity [`String`]. Equivalent to [`format!`](https://doc.rust-lang.org/std/macro.format.html).
1037///
1038/// The macro's arguments work in the same way as the regular macro.
1039///
1040/// It is possible to explicitly specify the capacity of the returned string as the first argument.
1041/// In this case it is necessary to disambiguate by separating the capacity with a semicolon.
1042///
1043/// # Errors
1044///
1045/// There are two possible error cases. Both return the unit type [`core::fmt::Error`].
1046///
1047/// - In case the formatting exceeds the string's capacity. This error does not exist in the
1048///   standard library as the string would just grow.
1049/// - If a formatting trait implementation returns an error. The standard library panics in this
1050///   case.
1051///
1052/// # Examples
1053///
1054/// ```
1055/// # fn main() -> Result<(), core::fmt::Error> {
1056/// use heapless::{format, String};
1057///
1058/// // Notice semicolon instead of comma!
1059/// format!(4; "test")?;
1060/// format!(15; "hello {}", "world!")?;
1061/// format!(20; "x = {}, y = {y}", 10, y = 30)?;
1062/// let (x, y) = (1, 2);
1063/// format!(12; "{x} + {y} = 3")?;
1064///
1065/// let implicit: String<10> = format!("speed = {}", 7)?;
1066/// # Ok(())
1067/// # }
1068/// ```
1069#[macro_export]
1070macro_rules! format {
1071    // Without semicolon as separator to disambiguate between arms, Rust just
1072    // chooses the first so that the format string would land in $max.
1073    ($max:expr; $lenT:path; $($arg:tt)*) => {{
1074        let res = $crate::_export::format::<$max, $lenT>(core::format_args!($($arg)*));
1075        res
1076    }};
1077    ($max:expr; $($arg:tt)*) => {{
1078        let res = $crate::_export::format::<$max, usize>(core::format_args!($($arg)*));
1079        res
1080    }};
1081    ($($arg:tt)*) => {{
1082        let res = $crate::_export::format(core::format_args!($($arg)*));
1083        res
1084    }};
1085}
1086
1087macro_rules! impl_try_from_num {
1088    ($num:ty, $size:expr) => {
1089        impl<LenT: LenType, const N: usize> core::convert::TryFrom<$num> for String<N, LenT> {
1090            type Error = ();
1091            fn try_from(s: $num) -> Result<Self, Self::Error> {
1092                let mut new = String::new();
1093                write!(&mut new, "{}", s).map_err(|_| ())?;
1094                Ok(new)
1095            }
1096        }
1097    };
1098}
1099
1100impl_try_from_num!(i8, 4);
1101impl_try_from_num!(i16, 6);
1102impl_try_from_num!(i32, 11);
1103impl_try_from_num!(i64, 20);
1104
1105impl_try_from_num!(u8, 3);
1106impl_try_from_num!(u16, 5);
1107impl_try_from_num!(u32, 10);
1108impl_try_from_num!(u64, 20);
1109
1110#[cfg(test)]
1111mod tests {
1112    use crate::{CapacityError, String, Vec};
1113
1114    #[test]
1115    fn static_new() {
1116        static mut _S: String<8> = String::new();
1117    }
1118
1119    #[test]
1120    fn clone() {
1121        let s1: String<20> = String::try_from("abcd").unwrap();
1122        let mut s2 = s1.clone();
1123        s2.push_str(" efgh").unwrap();
1124
1125        assert_eq!(s1, "abcd");
1126        assert_eq!(s2, "abcd efgh");
1127    }
1128
1129    #[test]
1130    fn cmp() {
1131        let s1: String<4> = String::try_from("abcd").unwrap();
1132        let s2: String<4> = String::try_from("zzzz").unwrap();
1133
1134        assert!(s1 < s2);
1135    }
1136
1137    #[test]
1138    fn cmp_heterogenous_size() {
1139        let s1: String<4> = String::try_from("abcd").unwrap();
1140        let s2: String<8> = String::try_from("zzzz").unwrap();
1141
1142        assert!(s1 < s2);
1143    }
1144
1145    #[test]
1146    fn debug() {
1147        use core::fmt::Write;
1148
1149        let s: String<8> = String::try_from("abcd").unwrap();
1150        let mut std_s = std::string::String::new();
1151        write!(std_s, "{s:?}").unwrap();
1152        assert_eq!("\"abcd\"", std_s);
1153    }
1154
1155    #[test]
1156    fn display() {
1157        use core::fmt::Write;
1158
1159        let s: String<8> = String::try_from("abcd").unwrap();
1160        let mut std_s = std::string::String::new();
1161        write!(std_s, "{s}").unwrap();
1162        assert_eq!("abcd", std_s);
1163    }
1164
1165    #[test]
1166    fn empty() {
1167        let s: String<4> = String::new();
1168        assert!(s.capacity() == 4);
1169        assert_eq!(s, "");
1170        assert_eq!(s.len(), 0);
1171        assert_ne!(s.len(), 4);
1172    }
1173
1174    #[test]
1175    fn try_from() {
1176        let s: String<4> = String::try_from("123").unwrap();
1177        assert!(s.len() == 3);
1178        assert_eq!(s, "123");
1179
1180        let _: CapacityError = String::<2>::try_from("123").unwrap_err();
1181    }
1182
1183    #[test]
1184    fn from_str() {
1185        use core::str::FromStr;
1186
1187        let s: String<4> = String::<4>::from_str("123").unwrap();
1188        assert!(s.len() == 3);
1189        assert_eq!(s, "123");
1190
1191        let _: CapacityError = String::<2>::from_str("123").unwrap_err();
1192    }
1193
1194    #[test]
1195    fn from_iter() {
1196        let mut v: Vec<char, 5> = Vec::new();
1197        v.push('h').unwrap();
1198        v.push('e').unwrap();
1199        v.push('l').unwrap();
1200        v.push('l').unwrap();
1201        v.push('o').unwrap();
1202        let string1: String<5> = v.iter().collect(); //&char
1203        let string2: String<5> = "hello".chars().collect(); //char
1204        assert_eq!(string1, "hello");
1205        assert_eq!(string2, "hello");
1206    }
1207
1208    #[test]
1209    #[should_panic]
1210    fn from_panic() {
1211        let _: String<4> = String::try_from("12345").unwrap();
1212    }
1213
1214    #[test]
1215    fn try_from_num() {
1216        let v: String<20> = String::try_from(18446744073709551615_u64).unwrap();
1217        assert_eq!(v, "18446744073709551615");
1218
1219        let _: () = String::<2>::try_from(18446744073709551615_u64).unwrap_err();
1220    }
1221
1222    #[test]
1223    fn into_bytes() {
1224        let s: String<4> = String::try_from("ab").unwrap();
1225        let b: Vec<u8, 4> = s.into_bytes();
1226        assert_eq!(b.len(), 2);
1227        assert_eq!(b"ab", &b[..]);
1228    }
1229
1230    #[test]
1231    fn as_str() {
1232        let s: String<4> = String::try_from("ab").unwrap();
1233
1234        assert_eq!(s.as_str(), "ab");
1235        // should be moved to fail test
1236        //    let _s = s.as_str();
1237        // s.push('c'); // <- cannot borrow `s` as mutable because it is also borrowed as immutable
1238    }
1239
1240    #[test]
1241    fn as_mut_str() {
1242        let mut s: String<4> = String::try_from("ab").unwrap();
1243        let s = s.as_mut_str();
1244        s.make_ascii_uppercase();
1245        assert_eq!(s, "AB");
1246    }
1247
1248    #[test]
1249    fn push_str() {
1250        let mut s: String<8> = String::try_from("foo").unwrap();
1251        assert!(s.push_str("bar").is_ok());
1252        assert_eq!("foobar", s);
1253        assert_eq!(s, "foobar");
1254        assert!(s.push_str("tender").is_err());
1255        assert_eq!("foobar", s);
1256        assert_eq!(s, "foobar");
1257    }
1258
1259    #[test]
1260    fn push() {
1261        let mut s: String<6> = String::try_from("abc").unwrap();
1262        assert!(s.push('1').is_ok());
1263        assert!(s.push('2').is_ok());
1264        assert!(s.push('3').is_ok());
1265        assert!(s.push('4').is_err());
1266        assert!("abc123" == s.as_str());
1267    }
1268
1269    #[test]
1270    fn as_bytes() {
1271        let s: String<8> = String::try_from("hello").unwrap();
1272        assert_eq!(&[104, 101, 108, 108, 111], s.as_bytes());
1273    }
1274
1275    #[test]
1276    fn truncate() {
1277        let mut s: String<8> = String::try_from("hello").unwrap();
1278        s.truncate(6);
1279        assert_eq!(s.len(), 5);
1280        s.truncate(2);
1281        assert_eq!(s.len(), 2);
1282        assert_eq!("he", s);
1283        assert_eq!(s, "he");
1284    }
1285
1286    #[test]
1287    fn pop() {
1288        let mut s: String<8> = String::try_from("foo").unwrap();
1289        assert_eq!(s.pop(), Some('o'));
1290        assert_eq!(s.pop(), Some('o'));
1291        assert_eq!(s.pop(), Some('f'));
1292        assert_eq!(s.pop(), None);
1293    }
1294
1295    #[test]
1296    fn pop_uenc() {
1297        let mut s: String<8> = String::try_from("é").unwrap();
1298        assert_eq!(s.len(), 3);
1299        match s.pop() {
1300            Some(c) => {
1301                assert_eq!(s.len(), 1);
1302                assert_eq!(c, '\u{0301}'); // acute accent of e
1303            }
1304            None => panic!(),
1305        };
1306    }
1307
1308    #[test]
1309    fn is_empty() {
1310        let mut v: String<8> = String::new();
1311        assert!(v.is_empty());
1312        let _ = v.push('a');
1313        assert!(!v.is_empty());
1314    }
1315
1316    #[test]
1317    fn clear() {
1318        let mut s: String<8> = String::try_from("foo").unwrap();
1319        s.clear();
1320        assert!(s.is_empty());
1321        assert_eq!(0, s.len());
1322        assert_eq!(8, s.capacity());
1323    }
1324
1325    #[test]
1326    fn remove() {
1327        let mut s: String<8> = String::try_from("foo").unwrap();
1328        assert_eq!(s.remove(0), 'f');
1329        assert_eq!(s.as_str(), "oo");
1330    }
1331
1332    #[test]
1333    fn remove_uenc() {
1334        let mut s: String<8> = String::try_from("ĝėēƶ").unwrap();
1335        assert_eq!(s.remove(2), 'ė');
1336        assert_eq!(s.remove(2), 'ē');
1337        assert_eq!(s.remove(2), 'ƶ');
1338        assert_eq!(s.as_str(), "ĝ");
1339    }
1340
1341    #[test]
1342    fn remove_uenc_combo_characters() {
1343        let mut s: String<8> = String::try_from("héy").unwrap();
1344        assert_eq!(s.remove(2), '\u{0301}');
1345        assert_eq!(s.as_str(), "hey");
1346    }
1347
1348    #[test]
1349    fn format() {
1350        let number = 5;
1351        let float = 3.12;
1352        let formatted = format!(15; "{:0>3} plus {float}", number).unwrap();
1353        assert_eq!(formatted, "005 plus 3.12");
1354    }
1355    #[test]
1356    fn format_inferred_capacity() {
1357        let number = 5;
1358        let float = 3.12;
1359        let formatted: String<15> = format!("{:0>3} plus {float}", number).unwrap();
1360        assert_eq!(formatted, "005 plus 3.12");
1361    }
1362
1363    #[test]
1364    fn format_overflow() {
1365        let i = 1234567;
1366        let formatted = format!(4; "13{}", i);
1367        assert_eq!(formatted, Err(core::fmt::Error));
1368    }
1369
1370    #[test]
1371    fn format_plain_string_overflow() {
1372        let formatted = format!(2; "123");
1373        assert_eq!(formatted, Err(core::fmt::Error));
1374    }
1375
1376    #[test]
1377    fn insert() {
1378        let mut s: String<6> = String::try_from("123").unwrap();
1379        assert!(s.insert(0, 'a').is_ok());
1380        assert_eq!(s, "a123");
1381
1382        assert!(s.insert(2, 'b').is_ok());
1383        assert_eq!(s, "a1b23");
1384
1385        assert!(s.insert(s.len(), '4').is_ok());
1386        assert_eq!(s, "a1b234");
1387
1388        assert_eq!(s.len(), 6);
1389        assert!(s.insert(0, 'd').is_err());
1390        assert_eq!(s, "a1b234");
1391    }
1392
1393    #[test]
1394    fn insert_unicode() {
1395        let mut s: String<21> = String::try_from("ĝėēƶ").unwrap();
1396        let idx = s.find("ė").unwrap();
1397
1398        assert!(s.insert(idx, '🦀').is_ok());
1399        assert_eq!(s, "ĝ🦀ėēƶ");
1400
1401        s.insert(s.len(), '🦀').unwrap();
1402        assert_eq!(s, "ĝ🦀ėēƶ🦀");
1403
1404        s.insert(0, '🦀').unwrap();
1405        assert_eq!(s, "🦀ĝ🦀ėēƶ🦀");
1406
1407        assert_eq!(s.len(), 20);
1408        assert_eq!('ƶ'.len_utf8(), 2);
1409        assert!(s.insert(0, 'ƶ').is_err());
1410        assert_eq!(s, "🦀ĝ🦀ėēƶ🦀");
1411    }
1412
1413    #[test]
1414    #[should_panic = "index must be a char boundary"]
1415    fn insert_at_non_char_boundary_panics() {
1416        let mut s: String<8> = String::try_from("é").unwrap();
1417        _ = s.insert(1, 'a');
1418    }
1419
1420    #[test]
1421    #[should_panic = "index must be a char boundary"]
1422    fn insert_beyond_length_panics() {
1423        let mut s: String<8> = String::try_from("a").unwrap();
1424        _ = s.insert(2, 'a');
1425    }
1426
1427    #[test]
1428    fn insert_str() {
1429        let mut s: String<14> = String::try_from("bar").unwrap();
1430        assert!(s.insert_str(0, "foo").is_ok());
1431        assert_eq!(s, "foobar");
1432
1433        assert!(s.insert_str(3, "baz").is_ok());
1434        assert_eq!(s, "foobazbar");
1435
1436        assert!(s.insert_str(s.len(), "end").is_ok());
1437        assert_eq!(s, "foobazbarend");
1438
1439        assert_eq!(s.len(), 12);
1440        assert!(s.insert_str(0, "def").is_err());
1441        assert_eq!(s, "foobazbarend");
1442    }
1443
1444    #[test]
1445    fn insert_str_unicode() {
1446        let mut s: String<20> = String::try_from("Héllô").unwrap();
1447        let idx = s.find("lô").unwrap();
1448
1449        assert!(s.insert_str(idx, "p, í'm ").is_ok());
1450        assert_eq!(s, "Hélp, í'm lô");
1451
1452        assert!(s.insert_str(s.len(), "st").is_ok());
1453        assert_eq!(s, "Hélp, í'm lôst");
1454
1455        assert_eq!(s.len(), 17);
1456        assert_eq!("🦀".len(), 4);
1457        assert!(s.insert_str(0, "🦀").is_err());
1458        assert_eq!(s, "Hélp, í'm lôst");
1459    }
1460
1461    #[test]
1462    #[should_panic = "index must be a char boundary"]
1463    fn insert_str_at_non_char_boundary_panics() {
1464        let mut s: String<8> = String::try_from("é").unwrap();
1465        _ = s.insert_str(1, "a");
1466    }
1467
1468    #[test]
1469    #[should_panic = "index must be a char boundary"]
1470    fn insert_str_beyond_length_panics() {
1471        let mut s: String<8> = String::try_from("a").unwrap();
1472        _ = s.insert_str(2, "a");
1473    }
1474
1475    #[test]
1476    #[cfg(feature = "zeroize")]
1477    fn test_string_zeroize() {
1478        use zeroize::Zeroize;
1479
1480        let mut s: String<32> = String::try_from("sensitive_password").unwrap();
1481
1482        assert_eq!(s.as_str(), "sensitive_password");
1483        assert!(!s.is_empty());
1484        assert_eq!(s.len(), 18);
1485
1486        s.truncate(9);
1487        assert_eq!(s.as_str(), "sensitive");
1488        assert_eq!(s.len(), 9);
1489
1490        // zeroized using Vec's implementation
1491        s.zeroize();
1492
1493        assert_eq!(s.len(), 0);
1494        assert!(s.is_empty());
1495    }
1496}