summaryrefslogtreecommitdiff
path: root/exercises/conversions
diff options
context:
space:
mode:
authordiannasoriel <mokou@fastmail.com>2021-09-25 11:18:55 +0200
committerGitHub <noreply@github.com>2021-09-25 11:18:55 +0200
commitc2ed98deb3ee721bc35c7904271675ed1c49dc89 (patch)
tree7a0b4d9f2a2de8489bf66485667fb854d75a3ce9 /exercises/conversions
parent0de45ccdb7c30773aa6cb31acdf014a1066c8c86 (diff)
parentabd6b70c72dc6426752ff41f09160b839e5c449e (diff)
Merge pull request #781 from tlyu/advanced-errs
feature: advanced errors
Diffstat (limited to 'exercises/conversions')
-rw-r--r--exercises/conversions/from_str.rs56
-rw-r--r--exercises/conversions/try_from_into.rs74
2 files changed, 95 insertions, 35 deletions
diff --git a/exercises/conversions/from_str.rs b/exercises/conversions/from_str.rs
index 93a5299..ece0b3c 100644
--- a/exercises/conversions/from_str.rs
+++ b/exercises/conversions/from_str.rs
@@ -1,16 +1,31 @@
-// This does practically the same thing that TryFrom<&str> does.
+// from_str.rs
+// This is similar to from_into.rs, but this time we'll implement `FromStr`
+// and return errors instead of falling back to a default value.
// Additionally, upon implementing FromStr, you can use the `parse` method
// on strings to generate an object of the implementor type.
// You can read more about it at https://doc.rust-lang.org/std/str/trait.FromStr.html
-use std::error;
+use std::num::ParseIntError;
use std::str::FromStr;
-#[derive(Debug)]
+#[derive(Debug, PartialEq)]
struct Person {
name: String,
age: usize,
}
+// We will use this error type for the `FromStr` implementation.
+#[derive(Debug, PartialEq)]
+enum ParsePersonError {
+ // Empty input string
+ Empty,
+ // Incorrect number of fields
+ BadLen,
+ // Empty name field
+ NoName,
+ // Wrapped error from parse::<usize>()
+ ParseInt(ParseIntError),
+}
+
// I AM NOT DONE
// Steps:
@@ -24,7 +39,7 @@ struct Person {
// If everything goes well, then return a Result of a Person object
impl FromStr for Person {
- type Err = Box<dyn error::Error>;
+ type Err = ParsePersonError;
fn from_str(s: &str) -> Result<Person, Self::Err> {
}
}
@@ -40,7 +55,7 @@ mod tests {
#[test]
fn empty_input() {
- assert!("".parse::<Person>().is_err());
+ assert_eq!("".parse::<Person>(), Err(ParsePersonError::Empty));
}
#[test]
fn good_input() {
@@ -52,41 +67,56 @@ mod tests {
}
#[test]
fn missing_age() {
- assert!("John,".parse::<Person>().is_err());
+ assert!(matches!(
+ "John,".parse::<Person>(),
+ Err(ParsePersonError::ParseInt(_))
+ ));
}
#[test]
fn invalid_age() {
- assert!("John,twenty".parse::<Person>().is_err());
+ assert!(matches!(
+ "John,twenty".parse::<Person>(),
+ Err(ParsePersonError::ParseInt(_))
+ ));
}
#[test]
fn missing_comma_and_age() {
- assert!("John".parse::<Person>().is_err());
+ assert_eq!("John".parse::<Person>(), Err(ParsePersonError::BadLen));
}
#[test]
fn missing_name() {
- assert!(",1".parse::<Person>().is_err());
+ assert_eq!(",1".parse::<Person>(), Err(ParsePersonError::NoName));
}
#[test]
fn missing_name_and_age() {
- assert!(",".parse::<Person>().is_err());
+ assert!(matches!(
+ ",".parse::<Person>(),
+ Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_))
+ ));
}
#[test]
fn missing_name_and_invalid_age() {
- assert!(",one".parse::<Person>().is_err());
+ assert!(matches!(
+ ",one".parse::<Person>(),
+ Err(ParsePersonError::NoName | ParsePersonError::ParseInt(_))
+ ));
}
#[test]
fn trailing_comma() {
- assert!("John,32,".parse::<Person>().is_err());
+ assert_eq!("John,32,".parse::<Person>(), Err(ParsePersonError::BadLen));
}
#[test]
fn trailing_comma_and_some_string() {
- assert!("John,32,man".parse::<Person>().is_err());
+ assert_eq!(
+ "John,32,man".parse::<Person>(),
+ Err(ParsePersonError::BadLen)
+ );
}
}
diff --git a/exercises/conversions/try_from_into.rs b/exercises/conversions/try_from_into.rs
index c0b5d98..b8ec445 100644
--- a/exercises/conversions/try_from_into.rs
+++ b/exercises/conversions/try_from_into.rs
@@ -1,9 +1,9 @@
+// try_from_into.rs
// TryFrom is a simple and safe type conversion that may fail in a controlled way under some circumstances.
// Basically, this is the same as From. The main difference is that this should return a Result type
// instead of the target type itself.
// You can read more about it at https://doc.rust-lang.org/std/convert/trait.TryFrom.html
use std::convert::{TryFrom, TryInto};
-use std::error;
#[derive(Debug, PartialEq)]
struct Color {
@@ -12,12 +12,21 @@ struct Color {
blue: u8,
}
+// We will use this error type for these `TryFrom` conversions.
+#[derive(Debug, PartialEq)]
+enum IntoColorError {
+ // Incorrect length of slice
+ BadLen,
+ // Integer conversion error
+ IntConversion,
+}
+
// I AM NOT DONE
// Your task is to complete this implementation
// and return an Ok result of inner type Color.
// You need to create an implementation for a tuple of three integers,
-// an array of three integers and a slice of integers.
+// an array of three integers, and a slice of integers.
//
// Note that the implementation for tuple and array will be checked at compile time,
// but the slice implementation needs to check the slice length!
@@ -25,20 +34,23 @@ struct Color {
// Tuple implementation
impl TryFrom<(i16, i16, i16)> for Color {
- type Error = Box<dyn error::Error>;
- fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> {}
+ type Error = IntoColorError;
+ fn try_from(tuple: (i16, i16, i16)) -> Result<Self, Self::Error> {
+ }
}
// Array implementation
impl TryFrom<[i16; 3]> for Color {
- type Error = Box<dyn error::Error>;
- fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> {}
+ type Error = IntoColorError;
+ fn try_from(arr: [i16; 3]) -> Result<Self, Self::Error> {
+ }
}
// Slice implementation
impl TryFrom<&[i16]> for Color {
- type Error = Box<dyn error::Error>;
- fn try_from(slice: &[i16]) -> Result<Self, Self::Error> {}
+ type Error = IntoColorError;
+ fn try_from(slice: &[i16]) -> Result<Self, Self::Error> {
+ }
}
fn main() {
@@ -46,15 +58,15 @@ fn main() {
let c1 = Color::try_from((183, 65, 14));
println!("{:?}", c1);
- // Since From is implemented for Color, we should be able to use Into
+ // Since TryFrom is implemented for Color, we should be able to use TryInto
let c2: Result<Color, _> = [183, 65, 14].try_into();
println!("{:?}", c2);
let v = vec![183, 65, 14];
- // With slice we should use `from` function
+ // With slice we should use `try_from` function
let c3 = Color::try_from(&v[..]);
println!("{:?}", c3);
- // or take slice within round brackets and use Into
+ // or take slice within round brackets and use TryInto
let c4: Result<Color, _> = (&v[..]).try_into();
println!("{:?}", c4);
}
@@ -65,15 +77,24 @@ mod tests {
#[test]
fn test_tuple_out_of_range_positive() {
- assert!(Color::try_from((256, 1000, 10000)).is_err());
+ assert_eq!(
+ Color::try_from((256, 1000, 10000)),
+ Err(IntoColorError::IntConversion)
+ );
}
#[test]
fn test_tuple_out_of_range_negative() {
- assert!(Color::try_from((-1, -10, -256)).is_err());
+ assert_eq!(
+ Color::try_from((-1, -10, -256)),
+ Err(IntoColorError::IntConversion)
+ );
}
#[test]
fn test_tuple_sum() {
- assert!(Color::try_from((-1, 255, 255)).is_err());
+ assert_eq!(
+ Color::try_from((-1, 255, 255)),
+ Err(IntoColorError::IntConversion)
+ );
}
#[test]
fn test_tuple_correct() {
@@ -91,17 +112,17 @@ mod tests {
#[test]
fn test_array_out_of_range_positive() {
let c: Result<Color, _> = [1000, 10000, 256].try_into();
- assert!(c.is_err());
+ assert_eq!(c, Err(IntoColorError::IntConversion));
}
#[test]
fn test_array_out_of_range_negative() {
let c: Result<Color, _> = [-10, -256, -1].try_into();
- assert!(c.is_err());
+ assert_eq!(c, Err(IntoColorError::IntConversion));
}
#[test]
fn test_array_sum() {
let c: Result<Color, _> = [-1, 255, 255].try_into();
- assert!(c.is_err());
+ assert_eq!(c, Err(IntoColorError::IntConversion));
}
#[test]
fn test_array_correct() {
@@ -119,17 +140,26 @@ mod tests {
#[test]
fn test_slice_out_of_range_positive() {
let arr = [10000, 256, 1000];
- assert!(Color::try_from(&arr[..]).is_err());
+ assert_eq!(
+ Color::try_from(&arr[..]),
+ Err(IntoColorError::IntConversion)
+ );
}
#[test]
fn test_slice_out_of_range_negative() {
let arr = [-256, -1, -10];
- assert!(Color::try_from(&arr[..]).is_err());
+ assert_eq!(
+ Color::try_from(&arr[..]),
+ Err(IntoColorError::IntConversion)
+ );
}
#[test]
fn test_slice_sum() {
let arr = [-1, 255, 255];
- assert!(Color::try_from(&arr[..]).is_err());
+ assert_eq!(
+ Color::try_from(&arr[..]),
+ Err(IntoColorError::IntConversion)
+ );
}
#[test]
fn test_slice_correct() {
@@ -148,11 +178,11 @@ mod tests {
#[test]
fn test_slice_excess_length() {
let v = vec![0, 0, 0, 0];
- assert!(Color::try_from(&v[..]).is_err());
+ assert_eq!(Color::try_from(&v[..]), Err(IntoColorError::BadLen));
}
#[test]
fn test_slice_insufficient_length() {
let v = vec![0, 0];
- assert!(Color::try_from(&v[..]).is_err());
+ assert_eq!(Color::try_from(&v[..]), Err(IntoColorError::BadLen));
}
}