summaryrefslogtreecommitdiff
path: root/exercises
diff options
context:
space:
mode:
authorTaylor Yu <tlyu@mit.edu>2021-06-06 23:05:01 -0500
committerTaylor Yu <tlyu@mit.edu>2021-06-06 23:08:57 -0500
commit68d3ac567cd5c23f5593c2f4df51612bca3d09a9 (patch)
tree75619fb6489e1cb7abbde7d35e29ba0b3ce055d2 /exercises
parent50ab289da6b9eb19a7486c341b00048c516b88c0 (diff)
feature: improve error_handling exercises
Add new exercises errors5 and errors6, to introduce boxed errors and custom error enums more gently. Delete errorsn, because it tried to do too much too soon.
Diffstat (limited to 'exercises')
-rw-r--r--exercises/error_handling/errors5.rs53
-rw-r--r--exercises/error_handling/errors6.rs86
-rw-r--r--exercises/error_handling/errorsn.rs117
3 files changed, 139 insertions, 117 deletions
diff --git a/exercises/error_handling/errors5.rs b/exercises/error_handling/errors5.rs
new file mode 100644
index 0000000..1b11800
--- /dev/null
+++ b/exercises/error_handling/errors5.rs
@@ -0,0 +1,53 @@
+// errors5.rs
+
+// This program uses a completed version of the code from errors4.
+// It won't compile right now! Why?
+// Execute `rustlings hint errors5` for hints!
+
+// I AM NOT DONE
+
+use std::error;
+use std::fmt;
+use std::num::ParseIntError;
+
+// TODO: update the return type of `main()` to make this compile.
+fn main() -> Result<(), ParseIntError> {
+ let pretend_user_input = "42";
+ let x: i64 = pretend_user_input.parse()?;
+ println!("output={:?}", PositiveNonzeroInteger::new(x)?);
+ Ok(())
+}
+
+// Don't change anything below this line.
+
+#[derive(PartialEq, Debug)]
+struct PositiveNonzeroInteger(u64);
+
+#[derive(PartialEq, Debug)]
+enum CreationError {
+ Negative,
+ Zero,
+}
+
+impl PositiveNonzeroInteger {
+ fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
+ match value {
+ x if x < 0 => Err(CreationError::Negative),
+ x if x == 0 => Err(CreationError::Zero),
+ x => Ok(PositiveNonzeroInteger(x as u64))
+ }
+ }
+}
+
+// This is required so that `CreationError` can implement `error::Error`.
+impl fmt::Display for CreationError {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ let description = match *self {
+ CreationError::Negative => "Number is negative",
+ CreationError::Zero => "Number is zero",
+ };
+ f.write_str(description)
+ }
+}
+
+impl error::Error for CreationError {}
diff --git a/exercises/error_handling/errors6.rs b/exercises/error_handling/errors6.rs
new file mode 100644
index 0000000..cee7250
--- /dev/null
+++ b/exercises/error_handling/errors6.rs
@@ -0,0 +1,86 @@
+// errors6.rs
+
+// Using catch-all error types like `Box<dyn error::Error>` isn't recommended
+// for library code, where callers might want to make decisions based on the
+// error content, instead of printing it out or propagating it further. Here,
+// we define a custom error type to make it possible for callers to decide
+// what to do next when our function returns an error.
+
+// Make these tests pass! Execute `rustlings hint errors6` for hints :)
+
+// I AM NOT DONE
+
+// This is a custom error type that we will be using in `parse_pos_nonzero()`.
+#[derive(PartialEq, Debug)]
+enum ParsePosNonzeroError {
+ CreationError,
+ ParseIntError
+}
+
+fn parse_pos_nonzero(s: &str)
+ -> Result<PositiveNonzeroInteger, ParsePosNonzeroError>
+{
+ // TODO: change this to return an appropriate error instead of panicking
+ // when `parse()` returns an error.
+ let x: i64 = s.parse().unwrap();
+ PositiveNonzeroInteger::new(x)
+ .or(Err(ParsePosNonzeroError::CreationError))
+}
+
+// Don't change anything below this line.
+
+#[derive(PartialEq, Debug)]
+struct PositiveNonzeroInteger(u64);
+
+#[derive(PartialEq, Debug)]
+enum CreationError {
+ Negative,
+ Zero,
+}
+
+impl PositiveNonzeroInteger {
+ fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
+ match value {
+ x if x < 0 => Err(CreationError::Negative),
+ x if x == 0 => Err(CreationError::Zero),
+ x => Ok(PositiveNonzeroInteger(x as u64))
+ }
+ }
+}
+
+#[cfg(test)]
+mod test {
+ use super::*;
+
+ #[test]
+ fn test_parse_error() {
+ assert_eq!(
+ parse_pos_nonzero("not a number"),
+ Err(ParsePosNonzeroError::ParseIntError)
+ );
+ }
+
+ #[test]
+ fn test_negative() {
+ assert_eq!(
+ parse_pos_nonzero("-555"),
+ Err(ParsePosNonzeroError::CreationError)
+ );
+ }
+
+ #[test]
+ fn test_zero() {
+ assert_eq!(
+ parse_pos_nonzero("0"),
+ Err(ParsePosNonzeroError::CreationError)
+ );
+ }
+
+ #[test]
+ fn test_positive() {
+ assert_eq!(
+ parse_pos_nonzero("42"),
+ Ok(PositiveNonzeroInteger(42))
+ );
+ }
+}
diff --git a/exercises/error_handling/errorsn.rs b/exercises/error_handling/errorsn.rs
deleted file mode 100644
index 5fe212b..0000000
--- a/exercises/error_handling/errorsn.rs
+++ /dev/null
@@ -1,117 +0,0 @@
-// errorsn.rs
-// This is a bigger error exercise than the previous ones!
-// You can do it! :)
-//
-// Edit the `read_and_validate` function ONLY. Don't create any Errors
-// that do not already exist.
-//
-// So many things could go wrong!
-//
-// - Reading from stdin could produce an io::Error
-// - Parsing the input could produce a num::ParseIntError
-// - Validating the input could produce a CreationError (defined below)
-//
-// How can we lump these errors into one general error? That is, what
-// type goes where the question marks are, and how do we return
-// that type from the body of read_and_validate?
-//
-// Execute `rustlings hint errorsn` for hints :)
-
-// I AM NOT DONE
-
-use std::error;
-use std::fmt;
-use std::io;
-
-// PositiveNonzeroInteger is a struct defined below the tests.
-fn read_and_validate(b: &mut dyn io::BufRead) -> Result<PositiveNonzeroInteger, ???> {
- let mut line = String::new();
- b.read_line(&mut line);
- let num: i64 = line.trim().parse();
- let answer = PositiveNonzeroInteger::new(num);
- answer
-}
-
-//
-// Nothing below this needs to be modified
-//
-
-// This is a test helper function that turns a &str into a BufReader.
-fn test_with_str(s: &str) -> Result<PositiveNonzeroInteger, Box<dyn error::Error>> {
- let mut b = io::BufReader::new(s.as_bytes());
- read_and_validate(&mut b)
-}
-
-#[test]
-fn test_success() {
- let x = test_with_str("42\n");
- assert_eq!(PositiveNonzeroInteger(42), x.unwrap());
-}
-
-#[test]
-fn test_not_num() {
- let x = test_with_str("eleven billion\n");
- assert!(x.is_err());
-}
-
-#[test]
-fn test_non_positive() {
- let x = test_with_str("-40\n");
- assert!(x.is_err());
-}
-
-#[test]
-fn test_ioerror() {
- struct Broken;
- impl io::Read for Broken {
- fn read(&mut self, _buf: &mut [u8]) -> io::Result<usize> {
- Err(io::Error::new(io::ErrorKind::BrokenPipe, "uh-oh!"))
- }
- }
- let mut b = io::BufReader::new(Broken);
- assert!(read_and_validate(&mut b).is_err());
- assert_eq!("uh-oh!", read_and_validate(&mut b).unwrap_err().to_string());
-}
-
-#[derive(PartialEq, Debug)]
-struct PositiveNonzeroInteger(u64);
-
-impl PositiveNonzeroInteger {
- fn new(value: i64) -> Result<PositiveNonzeroInteger, CreationError> {
- if value == 0 {
- Err(CreationError::Zero)
- } else if value < 0 {
- Err(CreationError::Negative)
- } else {
- Ok(PositiveNonzeroInteger(value as u64))
- }
- }
-}
-
-#[test]
-fn test_positive_nonzero_integer_creation() {
- assert!(PositiveNonzeroInteger::new(10).is_ok());
- assert_eq!(
- Err(CreationError::Negative),
- PositiveNonzeroInteger::new(-10)
- );
- assert_eq!(Err(CreationError::Zero), PositiveNonzeroInteger::new(0));
-}
-
-#[derive(PartialEq, Debug)]
-enum CreationError {
- Negative,
- Zero,
-}
-
-impl fmt::Display for CreationError {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- let description = match *self {
- CreationError::Negative => "Number is negative",
- CreationError::Zero => "Number is zero",
- };
- f.write_str(description)
- }
-}
-
-impl error::Error for CreationError {}