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 = String::new();
407 new.push_str(string: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 = String::new();
417 new.push_str(string: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 = String::new();
425 for c: char 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 = String::new();
435 for c: &'a char 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 = String::new();
445 for c: &'a str in iter {
446 new.push_str(string: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, state: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}
857