heapless/
string.rs

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