heapless/
string.rs

1use core::{
2    cmp::Ordering,
3    fmt,
4    fmt::Write,
5    hash, iter, ops,
6    str::{self, Utf8Error},
7};
8
9use crate::Vec;
10
11/// A fixed capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html)
12pub struct String<const N: usize> {
13    vec: Vec<u8, N>,
14}
15
16impl<const N: usize> String<N> {
17    /// Constructs a new, empty `String` with a fixed capacity of `N` bytes
18    ///
19    /// # Examples
20    ///
21    /// Basic usage:
22    ///
23    /// ```
24    /// use heapless::String;
25    ///
26    /// // allocate the string on the stack
27    /// let mut s: String<4> = String::new();
28    ///
29    /// // allocate the string in a static variable
30    /// static mut S: String<4> = String::new();
31    /// ```
32    #[inline]
33    pub const fn new() -> Self {
34        Self { vec: Vec::new() }
35    }
36
37    /// Convert UTF-8 bytes into a `String`.
38    ///
39    /// # Examples
40    ///
41    /// Basic usage:
42    ///
43    /// ```
44    /// use heapless::{String, Vec};
45    ///
46    /// let mut sparkle_heart = Vec::<u8, 4>::new();
47    /// sparkle_heart.extend_from_slice(&[240, 159, 146, 150]);
48    ///
49    /// let sparkle_heart: String<4> = String::from_utf8(sparkle_heart)?;
50    /// assert_eq!("💖", sparkle_heart);
51    /// # Ok::<(), core::str::Utf8Error>(())
52    /// ```
53    ///
54    /// Invalid UTF-8:
55    ///
56    /// ```
57    /// use core::str::Utf8Error;
58    /// use heapless::{String, Vec};
59    ///
60    /// let mut vec = Vec::<u8, 4>::new();
61    /// vec.extend_from_slice(&[0, 159, 146, 150]);
62    ///
63    /// let e: Utf8Error = String::from_utf8(vec).unwrap_err();
64    /// assert_eq!(e.valid_up_to(), 1);
65    /// # Ok::<(), core::str::Utf8Error>(())
66    /// ```
67    #[inline]
68    pub fn from_utf8(vec: Vec<u8, N>) -> Result<Self, Utf8Error> {
69        core::str::from_utf8(&vec)?;
70        Ok(Self { vec })
71    }
72
73    /// Convert UTF-8 bytes into a `String`, without checking that the string
74    /// contains valid UTF-8.
75    ///
76    /// # Safety
77    ///
78    /// The bytes passed in must be valid UTF-8.
79    ///
80    /// # Examples
81    ///
82    /// Basic usage:
83    ///
84    /// ```
85    /// use heapless::{String, Vec};
86    ///
87    /// let mut sparkle_heart = Vec::<u8, 4>::new();
88    /// sparkle_heart.extend_from_slice(&[240, 159, 146, 150]);
89    ///
90    /// // Safety: `sparkle_heart` Vec is known to contain valid UTF-8
91    /// let sparkle_heart: String<4> = unsafe { String::from_utf8_unchecked(sparkle_heart) };
92    /// assert_eq!("💖", sparkle_heart);
93    /// ```
94    #[inline]
95    pub unsafe fn from_utf8_unchecked(vec: Vec<u8, N>) -> Self {
96        Self { vec }
97    }
98
99    /// Converts a `String` into a byte vector.
100    ///
101    /// This consumes the `String`, so we do not need to copy its contents.
102    ///
103    /// # Examples
104    ///
105    /// Basic usage:
106    ///
107    /// ```
108    /// use heapless::String;
109    ///
110    /// let s: String<4> = String::try_from("ab")?;
111    /// let b = s.into_bytes();
112    /// assert!(b.len() == 2);
113    ///
114    /// assert_eq!(&['a' as u8, 'b' as u8], &b[..]);
115    /// # Ok::<(), ()>(())
116    /// ```
117    #[inline]
118    pub fn into_bytes(self) -> Vec<u8, N> {
119        self.vec
120    }
121
122    /// Extracts a string slice containing the entire string.
123    ///
124    /// # Examples
125    ///
126    /// Basic usage:
127    ///
128    /// ```
129    /// use heapless::String;
130    ///
131    /// let mut s: String<4> = String::try_from("ab")?;
132    /// assert!(s.as_str() == "ab");
133    ///
134    /// let _s = s.as_str();
135    /// // s.push('c'); // <- cannot borrow `s` as mutable because it is also borrowed as immutable
136    /// # Ok::<(), ()>(())
137    /// ```
138    #[inline]
139    pub fn as_str(&self) -> &str {
140        unsafe { str::from_utf8_unchecked(self.vec.as_slice()) }
141    }
142
143    /// Converts a `String` into a mutable string slice.
144    ///
145    /// # Examples
146    ///
147    /// Basic usage:
148    ///
149    /// ```
150    /// use heapless::String;
151    ///
152    /// let mut s: String<4> = String::try_from("ab")?;
153    /// let s = s.as_mut_str();
154    /// s.make_ascii_uppercase();
155    /// # Ok::<(), ()>(())
156    /// ```
157    #[inline]
158    pub fn as_mut_str(&mut self) -> &mut str {
159        unsafe { str::from_utf8_unchecked_mut(self.vec.as_mut_slice()) }
160    }
161
162    /// Returns a mutable reference to the contents of this `String`.
163    ///
164    /// # Safety
165    ///
166    /// This function is unsafe because it does not check that the bytes passed
167    /// to it are valid UTF-8. If this constraint is violated, it may cause
168    /// memory unsafety issues with future users of the `String`, as the rest of
169    /// the library assumes that `String`s are valid UTF-8.
170    ///
171    /// # Examples
172    ///
173    /// Basic usage:
174    ///
175    /// ```
176    /// use heapless::String;
177    ///
178    /// let mut s: String<8> = String::try_from("hello")?;
179    ///
180    /// unsafe {
181    ///     let vec = s.as_mut_vec();
182    ///     assert_eq!(&[104, 101, 108, 108, 111][..], &vec[..]);
183    ///
184    ///     vec.reverse();
185    /// }
186    /// assert_eq!(s, "olleh");
187    /// # Ok::<(), ()>(())
188    /// ```
189    pub unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8, N> {
190        &mut self.vec
191    }
192
193    /// Appends a given string slice onto the end of this `String`.
194    ///
195    /// # Examples
196    ///
197    /// Basic usage:
198    ///
199    /// ```
200    /// use heapless::String;
201    ///
202    /// let mut s: String<8> = String::try_from("foo")?;
203    ///
204    /// assert!(s.push_str("bar").is_ok());
205    ///
206    /// assert_eq!("foobar", s);
207    ///
208    /// assert!(s.push_str("tender").is_err());
209    /// # Ok::<(), ()>(())
210    /// ```
211    #[inline]
212    pub fn push_str(&mut self, string: &str) -> Result<(), ()> {
213        self.vec.extend_from_slice(string.as_bytes())
214    }
215
216    /// Returns the maximum number of elements the String can hold
217    ///
218    /// # Examples
219    ///
220    /// Basic usage:
221    ///
222    /// ```
223    /// use heapless::String;
224    ///
225    /// let mut s: String<4> = String::new();
226    /// assert!(s.capacity() == 4);
227    /// ```
228    #[inline]
229    pub fn capacity(&self) -> usize {
230        self.vec.capacity()
231    }
232
233    /// Appends the given [`char`] to the end of this `String`.
234    ///
235    /// # Examples
236    ///
237    /// Basic usage:
238    ///
239    /// ```
240    /// use heapless::String;
241    ///
242    /// let mut s: String<8> = String::try_from("abc")?;
243    ///
244    /// s.push('1').unwrap();
245    /// s.push('2').unwrap();
246    /// s.push('3').unwrap();
247    ///
248    /// assert!("abc123" == s.as_str());
249    ///
250    /// assert_eq!("abc123", s);
251    /// # Ok::<(), ()>(())
252    /// ```
253    #[inline]
254    pub fn push(&mut self, c: char) -> Result<(), ()> {
255        match c.len_utf8() {
256            1 => self.vec.push(c as u8).map_err(|_| {}),
257            _ => self
258                .vec
259                .extend_from_slice(c.encode_utf8(&mut [0; 4]).as_bytes()),
260        }
261    }
262
263    /// Shortens this `String` to the specified length.
264    ///
265    /// If `new_len` is greater than the string's current length, this has no
266    /// effect.
267    ///
268    /// Note that this method has no effect on the allocated capacity
269    /// of the string
270    ///
271    /// # Panics
272    ///
273    /// Panics if `new_len` does not lie on a [`char`] boundary.
274    ///
275    /// # Examples
276    ///
277    /// Basic usage:
278    ///
279    /// ```
280    /// use heapless::String;
281    ///
282    /// let mut s: String<8> = String::try_from("hello")?;
283    ///
284    /// s.truncate(2);
285    ///
286    /// assert_eq!("he", s);
287    /// # Ok::<(), ()>(())
288    /// ```
289    #[inline]
290    pub fn truncate(&mut self, new_len: usize) {
291        if new_len <= self.len() {
292            assert!(self.is_char_boundary(new_len));
293            self.vec.truncate(new_len)
294        }
295    }
296
297    /// Removes the last character from the string buffer and returns it.
298    ///
299    /// Returns [`None`] if this `String` is empty.
300    ///
301    /// # Examples
302    ///
303    /// Basic usage:
304    ///
305    /// ```
306    /// use heapless::String;
307    ///
308    /// let mut s: String<8> = String::try_from("foo")?;
309    ///
310    /// assert_eq!(s.pop(), Some('o'));
311    /// assert_eq!(s.pop(), Some('o'));
312    /// assert_eq!(s.pop(), Some('f'));
313    ///
314    /// assert_eq!(s.pop(), None);
315    /// Ok::<(), ()>(())
316    /// ```
317    pub fn pop(&mut self) -> Option<char> {
318        let ch = self.chars().rev().next()?;
319
320        // pop bytes that correspond to `ch`
321        for _ in 0..ch.len_utf8() {
322            unsafe {
323                self.vec.pop_unchecked();
324            }
325        }
326
327        Some(ch)
328    }
329
330    /// Removes a [`char`] from this `String` at a byte position and returns it.
331    ///
332    /// Note: Because this shifts over the remaining elements, it has a
333    /// worst-case performance of *O*(*n*).
334    ///
335    /// # Panics
336    ///
337    /// Panics if `idx` is larger than or equal to the `String`'s length,
338    /// or if it does not lie on a [`char`] boundary.
339    ///
340    /// # Examples
341    ///
342    /// Basic usage:
343    ///
344    /// ```
345    /// use heapless::String;
346    ///
347    /// let mut s: String<8> = String::try_from("foo").unwrap();
348    ///
349    /// assert_eq!(s.remove(0), 'f');
350    /// assert_eq!(s.remove(1), 'o');
351    /// assert_eq!(s.remove(0), 'o');
352    /// ```
353    #[inline]
354    pub fn remove(&mut self, index: usize) -> char {
355        let ch = match self[index..].chars().next() {
356            Some(ch) => ch,
357            None => panic!("cannot remove a char from the end of a string"),
358        };
359
360        let next = index + ch.len_utf8();
361        let len = self.len();
362        let ptr = self.vec.as_mut_ptr();
363        unsafe {
364            core::ptr::copy(ptr.add(next), ptr.add(index), len - next);
365            self.vec.set_len(len - (next - index));
366        }
367        ch
368    }
369
370    /// Truncates this `String`, removing all contents.
371    ///
372    /// While this means the `String` will have a length of zero, it does not
373    /// touch its capacity.
374    ///
375    /// # Examples
376    ///
377    /// Basic usage:
378    ///
379    /// ```
380    /// use heapless::String;
381    ///
382    /// let mut s: String<8> = String::try_from("foo")?;
383    ///
384    /// s.clear();
385    ///
386    /// assert!(s.is_empty());
387    /// assert_eq!(0, s.len());
388    /// assert_eq!(8, s.capacity());
389    /// Ok::<(), ()>(())
390    /// ```
391    #[inline]
392    pub fn clear(&mut self) {
393        self.vec.clear()
394    }
395}
396
397impl<const N: usize> Default for String<N> {
398    fn default() -> Self {
399        Self::new()
400    }
401}
402
403impl<'a, const N: usize> TryFrom<&'a str> for String<N> {
404    type Error = ();
405    fn try_from(s: &'a str) -> Result<Self, Self::Error> {
406        let mut new = String::new();
407        new.push_str(s)?;
408        Ok(new)
409    }
410}
411
412impl<const N: usize> str::FromStr for String<N> {
413    type Err = ();
414
415    fn from_str(s: &str) -> Result<Self, Self::Err> {
416        let mut new = String::new();
417        new.push_str(s)?;
418        Ok(new)
419    }
420}
421
422impl<const N: usize> iter::FromIterator<char> for String<N> {
423    fn from_iter<T: IntoIterator<Item = char>>(iter: T) -> Self {
424        let mut new = String::new();
425        for c in iter {
426            new.push(c).unwrap();
427        }
428        new
429    }
430}
431
432impl<'a, const N: usize> iter::FromIterator<&'a char> for String<N> {
433    fn from_iter<T: IntoIterator<Item = &'a char>>(iter: T) -> Self {
434        let mut new = String::new();
435        for c in iter {
436            new.push(*c).unwrap();
437        }
438        new
439    }
440}
441
442impl<'a, const N: usize> iter::FromIterator<&'a str> for String<N> {
443    fn from_iter<T: IntoIterator<Item = &'a str>>(iter: T) -> Self {
444        let mut new = String::new();
445        for c in iter {
446            new.push_str(c).unwrap();
447        }
448        new
449    }
450}
451
452impl<const N: usize> Clone for String<N> {
453    fn clone(&self) -> Self {
454        Self {
455            vec: self.vec.clone(),
456        }
457    }
458}
459
460impl<const N: usize> fmt::Debug for String<N> {
461    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
462        <str as fmt::Debug>::fmt(self, f)
463    }
464}
465
466impl<const N: usize> fmt::Display for String<N> {
467    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
468        <str as fmt::Display>::fmt(self, f)
469    }
470}
471
472impl<const N: usize> hash::Hash for String<N> {
473    #[inline]
474    fn hash<H: hash::Hasher>(&self, hasher: &mut H) {
475        <str as hash::Hash>::hash(self, hasher)
476    }
477}
478
479impl<const N: usize> fmt::Write for String<N> {
480    fn write_str(&mut self, s: &str) -> Result<(), fmt::Error> {
481        self.push_str(s).map_err(|_| fmt::Error)
482    }
483
484    fn write_char(&mut self, c: char) -> Result<(), fmt::Error> {
485        self.push(c).map_err(|_| fmt::Error)
486    }
487}
488
489impl<const N: usize> ops::Deref for String<N> {
490    type Target = str;
491
492    fn deref(&self) -> &str {
493        self.as_str()
494    }
495}
496
497impl<const N: usize> ops::DerefMut for String<N> {
498    fn deref_mut(&mut self) -> &mut str {
499        self.as_mut_str()
500    }
501}
502
503impl<const N: usize> AsRef<str> for String<N> {
504    #[inline]
505    fn as_ref(&self) -> &str {
506        self
507    }
508}
509
510impl<const N: usize> AsRef<[u8]> for String<N> {
511    #[inline]
512    fn as_ref(&self) -> &[u8] {
513        self.as_bytes()
514    }
515}
516
517impl<const N1: usize, const N2: usize> PartialEq<String<N2>> for String<N1> {
518    fn eq(&self, rhs: &String<N2>) -> bool {
519        str::eq(&**self, &**rhs)
520    }
521
522    fn ne(&self, rhs: &String<N2>) -> bool {
523        str::ne(&**self, &**rhs)
524    }
525}
526
527// String<N> == str
528impl<const N: usize> PartialEq<str> for String<N> {
529    #[inline]
530    fn eq(&self, other: &str) -> bool {
531        str::eq(&self[..], &other[..])
532    }
533    #[inline]
534    fn ne(&self, other: &str) -> bool {
535        str::ne(&self[..], &other[..])
536    }
537}
538
539// String<N> == &'str
540impl<const N: usize> PartialEq<&str> for String<N> {
541    #[inline]
542    fn eq(&self, other: &&str) -> bool {
543        str::eq(&self[..], &other[..])
544    }
545    #[inline]
546    fn ne(&self, other: &&str) -> bool {
547        str::ne(&self[..], &other[..])
548    }
549}
550
551// str == String<N>
552impl<const N: usize> PartialEq<String<N>> for str {
553    #[inline]
554    fn eq(&self, other: &String<N>) -> bool {
555        str::eq(&self[..], &other[..])
556    }
557    #[inline]
558    fn ne(&self, other: &String<N>) -> bool {
559        str::ne(&self[..], &other[..])
560    }
561}
562
563// &'str == String<N>
564impl<const N: usize> PartialEq<String<N>> for &str {
565    #[inline]
566    fn eq(&self, other: &String<N>) -> bool {
567        str::eq(&self[..], &other[..])
568    }
569    #[inline]
570    fn ne(&self, other: &String<N>) -> bool {
571        str::ne(&self[..], &other[..])
572    }
573}
574
575impl<const N: usize> Eq for String<N> {}
576
577impl<const N1: usize, const N2: usize> PartialOrd<String<N2>> for String<N1> {
578    #[inline]
579    fn partial_cmp(&self, other: &String<N2>) -> Option<Ordering> {
580        PartialOrd::partial_cmp(&**self, &**other)
581    }
582}
583
584impl<const N: usize> Ord for String<N> {
585    #[inline]
586    fn cmp(&self, other: &Self) -> Ordering {
587        Ord::cmp(&**self, &**other)
588    }
589}
590
591macro_rules! impl_try_from_num {
592    ($num:ty, $size:expr) => {
593        impl<const N: usize> core::convert::TryFrom<$num> for String<N> {
594            type Error = ();
595            fn try_from(s: $num) -> Result<Self, Self::Error> {
596                let mut new = String::new();
597                write!(&mut new, "{}", s).map_err(|_| ())?;
598                Ok(new)
599            }
600        }
601    };
602}
603
604impl_try_from_num!(i8, 4);
605impl_try_from_num!(i16, 6);
606impl_try_from_num!(i32, 11);
607impl_try_from_num!(i64, 20);
608
609impl_try_from_num!(u8, 3);
610impl_try_from_num!(u16, 5);
611impl_try_from_num!(u32, 10);
612impl_try_from_num!(u64, 20);
613
614#[cfg(test)]
615mod tests {
616    use crate::{String, Vec};
617    use core::convert::TryFrom;
618
619    #[test]
620    fn static_new() {
621        static mut _S: String<8> = String::new();
622    }
623
624    #[test]
625    fn clone() {
626        let s1: String<20> = String::try_from("abcd").unwrap();
627        let mut s2 = s1.clone();
628        s2.push_str(" efgh").unwrap();
629
630        assert_eq!(s1, "abcd");
631        assert_eq!(s2, "abcd efgh");
632    }
633
634    #[test]
635    fn cmp() {
636        let s1: String<4> = String::try_from("abcd").unwrap();
637        let s2: String<4> = String::try_from("zzzz").unwrap();
638
639        assert!(s1 < s2);
640    }
641
642    #[test]
643    fn cmp_heterogenous_size() {
644        let s1: String<4> = String::try_from("abcd").unwrap();
645        let s2: String<8> = String::try_from("zzzz").unwrap();
646
647        assert!(s1 < s2);
648    }
649
650    #[test]
651    fn debug() {
652        use core::fmt::Write;
653
654        let s: String<8> = String::try_from("abcd").unwrap();
655        let mut std_s = std::string::String::new();
656        write!(std_s, "{:?}", s).unwrap();
657        assert_eq!("\"abcd\"", std_s);
658    }
659
660    #[test]
661    fn display() {
662        use core::fmt::Write;
663
664        let s: String<8> = String::try_from("abcd").unwrap();
665        let mut std_s = std::string::String::new();
666        write!(std_s, "{}", s).unwrap();
667        assert_eq!("abcd", std_s);
668    }
669
670    #[test]
671    fn empty() {
672        let s: String<4> = String::new();
673        assert!(s.capacity() == 4);
674        assert_eq!(s, "");
675        assert_eq!(s.len(), 0);
676        assert_ne!(s.len(), 4);
677    }
678
679    #[test]
680    fn try_from() {
681        let s: String<4> = String::try_from("123").unwrap();
682        assert!(s.len() == 3);
683        assert_eq!(s, "123");
684
685        let e: () = String::<2>::try_from("123").unwrap_err();
686        assert_eq!(e, ());
687    }
688
689    #[test]
690    fn from_str() {
691        use core::str::FromStr;
692
693        let s: String<4> = String::<4>::from_str("123").unwrap();
694        assert!(s.len() == 3);
695        assert_eq!(s, "123");
696
697        let e: () = String::<2>::from_str("123").unwrap_err();
698        assert_eq!(e, ());
699    }
700
701    #[test]
702    fn from_iter() {
703        let mut v: Vec<char, 5> = Vec::new();
704        v.push('h').unwrap();
705        v.push('e').unwrap();
706        v.push('l').unwrap();
707        v.push('l').unwrap();
708        v.push('o').unwrap();
709        let string1: String<5> = v.iter().collect(); //&char
710        let string2: String<5> = "hello".chars().collect(); //char
711        assert_eq!(string1, "hello");
712        assert_eq!(string2, "hello");
713    }
714
715    #[test]
716    #[should_panic]
717    fn from_panic() {
718        let _: String<4> = String::try_from("12345").unwrap();
719    }
720
721    #[test]
722    fn try_from_num() {
723        let v: String<20> = String::try_from(18446744073709551615 as u64).unwrap();
724        assert_eq!(v, "18446744073709551615");
725
726        let e: () = String::<2>::try_from(18446744073709551615 as u64).unwrap_err();
727        assert_eq!(e, ());
728    }
729
730    #[test]
731    fn into_bytes() {
732        let s: String<4> = String::try_from("ab").unwrap();
733        let b: Vec<u8, 4> = s.into_bytes();
734        assert_eq!(b.len(), 2);
735        assert_eq!(&['a' as u8, 'b' as u8], &b[..]);
736    }
737
738    #[test]
739    fn as_str() {
740        let s: String<4> = String::try_from("ab").unwrap();
741
742        assert_eq!(s.as_str(), "ab");
743        // should be moved to fail test
744        //    let _s = s.as_str();
745        // s.push('c'); // <- cannot borrow `s` as mutable because it is also borrowed as immutable
746    }
747
748    #[test]
749    fn as_mut_str() {
750        let mut s: String<4> = String::try_from("ab").unwrap();
751        let s = s.as_mut_str();
752        s.make_ascii_uppercase();
753        assert_eq!(s, "AB");
754    }
755
756    #[test]
757    fn push_str() {
758        let mut s: String<8> = String::try_from("foo").unwrap();
759        assert!(s.push_str("bar").is_ok());
760        assert_eq!("foobar", s);
761        assert_eq!(s, "foobar");
762        assert!(s.push_str("tender").is_err());
763        assert_eq!("foobar", s);
764        assert_eq!(s, "foobar");
765    }
766
767    #[test]
768    fn push() {
769        let mut s: String<6> = String::try_from("abc").unwrap();
770        assert!(s.push('1').is_ok());
771        assert!(s.push('2').is_ok());
772        assert!(s.push('3').is_ok());
773        assert!(s.push('4').is_err());
774        assert!("abc123" == s.as_str());
775    }
776
777    #[test]
778    fn as_bytes() {
779        let s: String<8> = String::try_from("hello").unwrap();
780        assert_eq!(&[104, 101, 108, 108, 111], s.as_bytes());
781    }
782
783    #[test]
784    fn truncate() {
785        let mut s: String<8> = String::try_from("hello").unwrap();
786        s.truncate(6);
787        assert_eq!(s.len(), 5);
788        s.truncate(2);
789        assert_eq!(s.len(), 2);
790        assert_eq!("he", s);
791        assert_eq!(s, "he");
792    }
793
794    #[test]
795    fn pop() {
796        let mut s: String<8> = String::try_from("foo").unwrap();
797        assert_eq!(s.pop(), Some('o'));
798        assert_eq!(s.pop(), Some('o'));
799        assert_eq!(s.pop(), Some('f'));
800        assert_eq!(s.pop(), None);
801    }
802
803    #[test]
804    fn pop_uenc() {
805        let mut s: String<8> = String::try_from("é").unwrap();
806        assert_eq!(s.len(), 3);
807        match s.pop() {
808            Some(c) => {
809                assert_eq!(s.len(), 1);
810                assert_eq!(c, '\u{0301}'); // accute accent of e
811                ()
812            }
813            None => assert!(false),
814        };
815    }
816
817    #[test]
818    fn is_empty() {
819        let mut v: String<8> = String::new();
820        assert!(v.is_empty());
821        let _ = v.push('a');
822        assert!(!v.is_empty());
823    }
824
825    #[test]
826    fn clear() {
827        let mut s: String<8> = String::try_from("foo").unwrap();
828        s.clear();
829        assert!(s.is_empty());
830        assert_eq!(0, s.len());
831        assert_eq!(8, s.capacity());
832    }
833
834    #[test]
835    fn remove() {
836        let mut s: String<8> = String::try_from("foo").unwrap();
837        assert_eq!(s.remove(0), 'f');
838        assert_eq!(s.as_str(), "oo");
839    }
840
841    #[test]
842    fn remove_uenc() {
843        let mut s: String<8> = String::try_from("ĝėēƶ").unwrap();
844        assert_eq!(s.remove(2), 'ė');
845        assert_eq!(s.remove(2), 'ē');
846        assert_eq!(s.remove(2), 'ƶ');
847        assert_eq!(s.as_str(), "ĝ");
848    }
849
850    #[test]
851    fn remove_uenc_combo_characters() {
852        let mut s: String<8> = String::try_from("héy").unwrap();
853        assert_eq!(s.remove(2), '\u{0301}');
854        assert_eq!(s.as_str(), "hey");
855    }
856}