Skip to content

Commit 6e9b043

Browse files
authored
Merge pull request #397 from newAM/impl-try-from-string
string: replace From<&str> with TryFrom<&str>
2 parents 7e6bff3 + 11603de commit 6e9b043

File tree

2 files changed

+69
-49
lines changed

2 files changed

+69
-49
lines changed

CHANGELOG.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,9 +31,9 @@ and this project adheres to [Semantic Versioning](http://semver.org/).
3131
- export `IndexSet` and `IndexMap` iterator types.
3232
- [breaking-change] export `IndexMapKeys`, `IndexMapValues` and
3333
`IndexMapValuesMut` iterator types.
34-
3534
- [breaking-change] this crate now uses `portable-atomic` v1.0 instead of `atomic-polyfill` for emulating
3635
CAS instructions on targets where they're not natively available.
36+
- [breaking-change] `From<&str>` for `String` was replaced with `TryFrom<&str>` because the `From` trait must not fail.
3737

3838
### Fixed
3939

src/string.rs

Lines changed: 68 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -39,11 +39,12 @@ impl<const N: usize> String<N> {
3939
/// ```
4040
/// use heapless::String;
4141
///
42-
/// let s: String<4> = String::from("ab");
42+
/// let s: String<4> = String::try_from("ab")?;
4343
/// let b = s.into_bytes();
4444
/// assert!(b.len() == 2);
4545
///
4646
/// assert_eq!(&['a' as u8, 'b' as u8], &b[..]);
47+
/// # Ok::<(), ()>(())
4748
/// ```
4849
#[inline]
4950
pub fn into_bytes(self) -> Vec<u8, N> {
@@ -59,11 +60,12 @@ impl<const N: usize> String<N> {
5960
/// ```
6061
/// use heapless::String;
6162
///
62-
/// let mut s: String<4> = String::from("ab");
63+
/// let mut s: String<4> = String::try_from("ab")?;
6364
/// assert!(s.as_str() == "ab");
6465
///
6566
/// let _s = s.as_str();
6667
/// // s.push('c'); // <- cannot borrow `s` as mutable because it is also borrowed as immutable
68+
/// # Ok::<(), ()>(())
6769
/// ```
6870
#[inline]
6971
pub fn as_str(&self) -> &str {
@@ -79,9 +81,10 @@ impl<const N: usize> String<N> {
7981
/// ```
8082
/// use heapless::String;
8183
///
82-
/// let mut s: String<4> = String::from("ab");
84+
/// let mut s: String<4> = String::try_from("ab")?;
8385
/// let s = s.as_mut_str();
8486
/// s.make_ascii_uppercase();
87+
/// # Ok::<(), ()>(())
8588
/// ```
8689
#[inline]
8790
pub fn as_mut_str(&mut self) -> &mut str {
@@ -102,7 +105,9 @@ impl<const N: usize> String<N> {
102105
/// Basic usage:
103106
///
104107
/// ```
105-
/// let mut s = String::from("hello");
108+
/// use heapless::String;
109+
///
110+
/// let mut s: String<8> = String::try_from("hello")?;
106111
///
107112
/// unsafe {
108113
/// let vec = s.as_mut_vec();
@@ -111,6 +116,7 @@ impl<const N: usize> String<N> {
111116
/// vec.reverse();
112117
/// }
113118
/// assert_eq!(s, "olleh");
119+
/// # Ok::<(), ()>(())
114120
/// ```
115121
pub unsafe fn as_mut_vec(&mut self) -> &mut Vec<u8, N> {
116122
&mut self.vec
@@ -125,13 +131,14 @@ impl<const N: usize> String<N> {
125131
/// ```
126132
/// use heapless::String;
127133
///
128-
/// let mut s: String<8> = String::from("foo");
134+
/// let mut s: String<8> = String::try_from("foo")?;
129135
///
130136
/// assert!(s.push_str("bar").is_ok());
131137
///
132138
/// assert_eq!("foobar", s);
133139
///
134140
/// assert!(s.push_str("tender").is_err());
141+
/// # Ok::<(), ()>(())
135142
/// ```
136143
#[inline]
137144
pub fn push_str(&mut self, string: &str) -> Result<(), ()> {
@@ -166,7 +173,7 @@ impl<const N: usize> String<N> {
166173
/// ```
167174
/// use heapless::String;
168175
///
169-
/// let mut s: String<8> = String::from("abc");
176+
/// let mut s: String<8> = String::try_from("abc")?;
170177
///
171178
/// s.push('1').unwrap();
172179
/// s.push('2').unwrap();
@@ -175,6 +182,7 @@ impl<const N: usize> String<N> {
175182
/// assert!("abc123" == s.as_str());
176183
///
177184
/// assert_eq!("abc123", s);
185+
/// # Ok::<(), ()>(())
178186
/// ```
179187
#[inline]
180188
pub fn push(&mut self, c: char) -> Result<(), ()> {
@@ -207,11 +215,12 @@ impl<const N: usize> String<N> {
207215
/// ```
208216
/// use heapless::String;
209217
///
210-
/// let mut s: String<8> = String::from("hello");
218+
/// let mut s: String<8> = String::try_from("hello")?;
211219
///
212220
/// s.truncate(2);
213221
///
214222
/// assert_eq!("he", s);
223+
/// # Ok::<(), ()>(())
215224
/// ```
216225
#[inline]
217226
pub fn truncate(&mut self, new_len: usize) {
@@ -234,13 +243,14 @@ impl<const N: usize> String<N> {
234243
/// ```
235244
/// use heapless::String;
236245
///
237-
/// let mut s: String<8> = String::from("foo");
246+
/// let mut s: String<8> = String::try_from("foo")?;
238247
///
239248
/// assert_eq!(s.pop(), Some('o'));
240249
/// assert_eq!(s.pop(), Some('o'));
241250
/// assert_eq!(s.pop(), Some('f'));
242251
///
243252
/// assert_eq!(s.pop(), None);
253+
/// Ok::<(), ()>(())
244254
/// ```
245255
pub fn pop(&mut self) -> Option<char> {
246256
let ch = self.chars().rev().next()?;
@@ -267,13 +277,14 @@ impl<const N: usize> String<N> {
267277
/// ```
268278
/// use heapless::String;
269279
///
270-
/// let mut s: String<8> = String::from("foo");
280+
/// let mut s: String<8> = String::try_from("foo")?;
271281
///
272282
/// s.clear();
273283
///
274284
/// assert!(s.is_empty());
275285
/// assert_eq!(0, s.len());
276286
/// assert_eq!(8, s.capacity());
287+
/// Ok::<(), ()>(())
277288
/// ```
278289
#[inline]
279290
pub fn clear(&mut self) {
@@ -287,11 +298,12 @@ impl<const N: usize> Default for String<N> {
287298
}
288299
}
289300

290-
impl<'a, const N: usize> From<&'a str> for String<N> {
291-
fn from(s: &'a str) -> Self {
301+
impl<'a, const N: usize> TryFrom<&'a str> for String<N> {
302+
type Error = ();
303+
fn try_from(s: &'a str) -> Result<Self, Self::Error> {
292304
let mut new = String::new();
293-
new.push_str(s).unwrap();
294-
new
305+
new.push_str(s)?;
306+
Ok(new)
295307
}
296308
}
297309

@@ -474,31 +486,33 @@ impl<const N: usize> Ord for String<N> {
474486
}
475487
}
476488

477-
macro_rules! impl_from_num {
489+
macro_rules! impl_try_from_num {
478490
($num:ty, $size:expr) => {
479-
impl<const N: usize> From<$num> for String<N> {
480-
fn from(s: $num) -> Self {
491+
impl<const N: usize> core::convert::TryFrom<$num> for String<N> {
492+
type Error = ();
493+
fn try_from(s: $num) -> Result<Self, Self::Error> {
481494
let mut new = String::new();
482-
write!(&mut new, "{}", s).unwrap();
483-
new
495+
write!(&mut new, "{}", s).map_err(|_| ())?;
496+
Ok(new)
484497
}
485498
}
486499
};
487500
}
488501

489-
impl_from_num!(i8, 4);
490-
impl_from_num!(i16, 6);
491-
impl_from_num!(i32, 11);
492-
impl_from_num!(i64, 20);
502+
impl_try_from_num!(i8, 4);
503+
impl_try_from_num!(i16, 6);
504+
impl_try_from_num!(i32, 11);
505+
impl_try_from_num!(i64, 20);
493506

494-
impl_from_num!(u8, 3);
495-
impl_from_num!(u16, 5);
496-
impl_from_num!(u32, 10);
497-
impl_from_num!(u64, 20);
507+
impl_try_from_num!(u8, 3);
508+
impl_try_from_num!(u16, 5);
509+
impl_try_from_num!(u32, 10);
510+
impl_try_from_num!(u64, 20);
498511

499512
#[cfg(test)]
500513
mod tests {
501514
use crate::{String, Vec};
515+
use core::convert::TryFrom;
502516

503517
#[test]
504518
fn static_new() {
@@ -507,7 +521,7 @@ mod tests {
507521

508522
#[test]
509523
fn clone() {
510-
let s1: String<20> = String::from("abcd");
524+
let s1: String<20> = String::try_from("abcd").unwrap();
511525
let mut s2 = s1.clone();
512526
s2.push_str(" efgh").unwrap();
513527

@@ -517,16 +531,16 @@ mod tests {
517531

518532
#[test]
519533
fn cmp() {
520-
let s1: String<4> = String::from("abcd");
521-
let s2: String<4> = String::from("zzzz");
534+
let s1: String<4> = String::try_from("abcd").unwrap();
535+
let s2: String<4> = String::try_from("zzzz").unwrap();
522536

523537
assert!(s1 < s2);
524538
}
525539

526540
#[test]
527541
fn cmp_heterogenous_size() {
528-
let s1: String<4> = String::from("abcd");
529-
let s2: String<8> = String::from("zzzz");
542+
let s1: String<4> = String::try_from("abcd").unwrap();
543+
let s2: String<8> = String::try_from("zzzz").unwrap();
530544

531545
assert!(s1 < s2);
532546
}
@@ -535,7 +549,7 @@ mod tests {
535549
fn debug() {
536550
use core::fmt::Write;
537551

538-
let s: String<8> = String::from("abcd");
552+
let s: String<8> = String::try_from("abcd").unwrap();
539553
let mut std_s = std::string::String::new();
540554
write!(std_s, "{:?}", s).unwrap();
541555
assert_eq!("\"abcd\"", std_s);
@@ -545,7 +559,7 @@ mod tests {
545559
fn display() {
546560
use core::fmt::Write;
547561

548-
let s: String<8> = String::from("abcd");
562+
let s: String<8> = String::try_from("abcd").unwrap();
549563
let mut std_s = std::string::String::new();
550564
write!(std_s, "{}", s).unwrap();
551565
assert_eq!("abcd", std_s);
@@ -561,10 +575,13 @@ mod tests {
561575
}
562576

563577
#[test]
564-
fn from() {
565-
let s: String<4> = String::from("123");
578+
fn try_from() {
579+
let s: String<4> = String::try_from("123").unwrap();
566580
assert!(s.len() == 3);
567581
assert_eq!(s, "123");
582+
583+
let e: () = String::<2>::try_from("123").unwrap_err();
584+
assert_eq!(e, ());
568585
}
569586

570587
#[test]
@@ -596,26 +613,29 @@ mod tests {
596613
#[test]
597614
#[should_panic]
598615
fn from_panic() {
599-
let _: String<4> = String::from("12345");
616+
let _: String<4> = String::try_from("12345").unwrap();
600617
}
601618

602619
#[test]
603-
fn from_num() {
604-
let v: String<20> = String::from(18446744073709551615 as u64);
620+
fn try_from_num() {
621+
let v: String<20> = String::try_from(18446744073709551615 as u64).unwrap();
605622
assert_eq!(v, "18446744073709551615");
623+
624+
let e: () = String::<2>::try_from(18446744073709551615 as u64).unwrap_err();
625+
assert_eq!(e, ());
606626
}
607627

608628
#[test]
609629
fn into_bytes() {
610-
let s: String<4> = String::from("ab");
630+
let s: String<4> = String::try_from("ab").unwrap();
611631
let b: Vec<u8, 4> = s.into_bytes();
612632
assert_eq!(b.len(), 2);
613633
assert_eq!(&['a' as u8, 'b' as u8], &b[..]);
614634
}
615635

616636
#[test]
617637
fn as_str() {
618-
let s: String<4> = String::from("ab");
638+
let s: String<4> = String::try_from("ab").unwrap();
619639

620640
assert_eq!(s.as_str(), "ab");
621641
// should be moved to fail test
@@ -625,15 +645,15 @@ mod tests {
625645

626646
#[test]
627647
fn as_mut_str() {
628-
let mut s: String<4> = String::from("ab");
648+
let mut s: String<4> = String::try_from("ab").unwrap();
629649
let s = s.as_mut_str();
630650
s.make_ascii_uppercase();
631651
assert_eq!(s, "AB");
632652
}
633653

634654
#[test]
635655
fn push_str() {
636-
let mut s: String<8> = String::from("foo");
656+
let mut s: String<8> = String::try_from("foo").unwrap();
637657
assert!(s.push_str("bar").is_ok());
638658
assert_eq!("foobar", s);
639659
assert_eq!(s, "foobar");
@@ -644,7 +664,7 @@ mod tests {
644664

645665
#[test]
646666
fn push() {
647-
let mut s: String<6> = String::from("abc");
667+
let mut s: String<6> = String::try_from("abc").unwrap();
648668
assert!(s.push('1').is_ok());
649669
assert!(s.push('2').is_ok());
650670
assert!(s.push('3').is_ok());
@@ -654,13 +674,13 @@ mod tests {
654674

655675
#[test]
656676
fn as_bytes() {
657-
let s: String<8> = String::from("hello");
677+
let s: String<8> = String::try_from("hello").unwrap();
658678
assert_eq!(&[104, 101, 108, 108, 111], s.as_bytes());
659679
}
660680

661681
#[test]
662682
fn truncate() {
663-
let mut s: String<8> = String::from("hello");
683+
let mut s: String<8> = String::try_from("hello").unwrap();
664684
s.truncate(6);
665685
assert_eq!(s.len(), 5);
666686
s.truncate(2);
@@ -671,7 +691,7 @@ mod tests {
671691

672692
#[test]
673693
fn pop() {
674-
let mut s: String<8> = String::from("foo");
694+
let mut s: String<8> = String::try_from("foo").unwrap();
675695
assert_eq!(s.pop(), Some('o'));
676696
assert_eq!(s.pop(), Some('o'));
677697
assert_eq!(s.pop(), Some('f'));
@@ -680,7 +700,7 @@ mod tests {
680700

681701
#[test]
682702
fn pop_uenc() {
683-
let mut s: String<8> = String::from("é");
703+
let mut s: String<8> = String::try_from("é").unwrap();
684704
assert_eq!(s.len(), 3);
685705
match s.pop() {
686706
Some(c) => {
@@ -702,7 +722,7 @@ mod tests {
702722

703723
#[test]
704724
fn clear() {
705-
let mut s: String<8> = String::from("foo");
725+
let mut s: String<8> = String::try_from("foo").unwrap();
706726
s.clear();
707727
assert!(s.is_empty());
708728
assert_eq!(0, s.len());

0 commit comments

Comments
 (0)