1 | use core::{ |
2 | cmp::Ordering, |
3 | fmt, |
4 | fmt::Write, |
5 | hash, iter, ops, |
6 | str::{self, Utf8Error}, |
7 | }; |
8 | |
9 | use crate::Vec; |
10 | |
11 | /// A fixed capacity [`String`](https://doc.rust-lang.org/std/string/struct.String.html) |
12 | pub struct String<const N: usize> { |
13 | vec: Vec<u8, N>, |
14 | } |
15 | |
16 | impl<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 | |
397 | impl<const N: usize> Default for String<N> { |
398 | fn default() -> Self { |
399 | Self::new() |
400 | } |
401 | } |
402 | |
403 | impl<'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 | |
412 | impl<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 | |
422 | impl<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 | |
432 | impl<'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 | |
442 | impl<'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 | |
452 | impl<const N: usize> Clone for String<N> { |
453 | fn clone(&self) -> Self { |
454 | Self { |
455 | vec: self.vec.clone(), |
456 | } |
457 | } |
458 | } |
459 | |
460 | impl<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 | |
466 | impl<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 | |
472 | impl<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 | |
479 | impl<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 | |
489 | impl<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 | |
497 | impl<const N: usize> ops::DerefMut for String<N> { |
498 | fn deref_mut(&mut self) -> &mut str { |
499 | self.as_mut_str() |
500 | } |
501 | } |
502 | |
503 | impl<const N: usize> AsRef<str> for String<N> { |
504 | #[inline ] |
505 | fn as_ref(&self) -> &str { |
506 | self |
507 | } |
508 | } |
509 | |
510 | impl<const N: usize> AsRef<[u8]> for String<N> { |
511 | #[inline ] |
512 | fn as_ref(&self) -> &[u8] { |
513 | self.as_bytes() |
514 | } |
515 | } |
516 | |
517 | impl<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 |
528 | impl<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 |
540 | impl<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> |
552 | impl<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> |
564 | impl<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 | |
575 | impl<const N: usize> Eq for String<N> {} |
576 | |
577 | impl<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 | |
584 | impl<const N: usize> Ord for String<N> { |
585 | #[inline ] |
586 | fn cmp(&self, other: &Self) -> Ordering { |
587 | Ord::cmp(&**self, &**other) |
588 | } |
589 | } |
590 | |
591 | macro_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 | |
604 | impl_try_from_num!(i8, 4); |
605 | impl_try_from_num!(i16, 6); |
606 | impl_try_from_num!(i32, 11); |
607 | impl_try_from_num!(i64, 20); |
608 | |
609 | impl_try_from_num!(u8, 3); |
610 | impl_try_from_num!(u16, 5); |
611 | impl_try_from_num!(u32, 10); |
612 | impl_try_from_num!(u64, 20); |
613 | |
614 | #[cfg (test)] |
615 | mod 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 | |