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