From 1787c39be01df1400261f458639cc45e935ccf07 Mon Sep 17 00:00:00 2001 From: lilymonade Date: Tue, 11 Mar 2025 17:43:28 +0000 Subject: [PATCH] Add result part Reviewed-on: https://gitea.lilymonade.fr/lilymonade/exowos/pulls/1 --- practical.yml | 15 +++++++ subject_source/src/errors.rs | 1 + subject_source/src/errors/result.rs | 37 +++++++++++++++++ subject_source/tests/result.rs | 53 ++++++++++++++++++++++++ subject_text/errors/index.md | 2 +- subject_text/errors/result.md | 64 +++++++++++++++++++++++++++++ 6 files changed, 171 insertions(+), 1 deletion(-) create mode 100644 subject_source/src/errors/result.rs create mode 100644 subject_source/tests/result.rs create mode 100644 subject_text/errors/result.md diff --git a/practical.yml b/practical.yml index e8b2d34..c74b803 100644 --- a/practical.yml +++ b/practical.yml @@ -22,3 +22,18 @@ exercises: - "get_or_default_some_diff" - "get_or_panic_none" - "get_or_panic_some" + result: + required_files: + - "src/errors.rs" + - "src/errors/option.rs" + tests: + - "is_err_err" + - "is_ok_err" + - "is_err_ok" + - "is_ok_ok" + - "get_err_or_panic_err" + - "get_err_or_panic_ok" + - "get_val_or_panic_err" + - "get_val_or_panic_ok" + - "discard_err_ok" + - "discard_err_err" diff --git a/subject_source/src/errors.rs b/subject_source/src/errors.rs index ba0e383..8c45a69 100644 --- a/subject_source/src/errors.rs +++ b/subject_source/src/errors.rs @@ -1 +1,2 @@ pub mod option; +pub mod result; diff --git a/subject_source/src/errors/result.rs b/subject_source/src/errors/result.rs new file mode 100644 index 0000000..aeb89ff --- /dev/null +++ b/subject_source/src/errors/result.rs @@ -0,0 +1,37 @@ +/// Returns `true` if the result contains an `Err` +pub fn is_err(res: &Result) -> bool { + match res { + Err(_) => true, + Ok(_) => false, + } +} + +/// Returns `true` if the result contains a `Ok` +pub fn is_ok(res: &Result) -> bool { + !is_err(res) +} + +/// Returns the wrapped `&str` if any, panic otherwise +pub fn get_err_or_panic(res: Result) -> &str { + match res { + Err(e) => e, + Ok(_) => panic!("result was not an error"), + } +} + +/// Returns the wrapped `i32` if any, panic otherwise +pub fn get_val_or_panic(res: Result) -> i32 { + match res { + Ok(v) => v, + Err(_) => panic!("result was an error"), + } +} + +/// Transforms `Ok` to `Some` and `Err` to `None` +/// effectively discarding the `Err` wrapped value +pub fn discard_err(res: Result) -> Option { + match res { + Ok(v) => Some(v), + Err(_) => None, + } +} diff --git a/subject_source/tests/result.rs b/subject_source/tests/result.rs new file mode 100644 index 0000000..6ae82a4 --- /dev/null +++ b/subject_source/tests/result.rs @@ -0,0 +1,53 @@ +use subject_source::errors::result; + +#[test] +pub fn is_err_err() { + assert!(result::is_err(&Err("oh no"))); +} + +#[test] +pub fn is_err_ok() { + assert!(!result::is_err(&Ok(420))); +} + +#[test] +pub fn is_ok_err() { + assert!(!result::is_ok(&Err("oh no"))); +} + +#[test] +pub fn is_ok_ok() { + assert!(result::is_ok(&Ok(420))); +} + +#[test] +pub fn get_err_or_panic_err() { + assert_eq!(result::get_err_or_panic(Err("ayaya")), "ayaya"); +} + +#[test] +#[should_panic] +pub fn get_err_or_panic_ok() { + let _ = std::hint::black_box(result::get_err_or_panic(Ok(10))); +} + +#[test] +pub fn get_val_or_panic_ok() { + assert_eq!(result::get_val_or_panic(Ok(10)), 10); +} + +#[test] +#[should_panic] +pub fn get_val_or_panic_err() { + let _ = std::hint::black_box(result::get_val_or_panic(Err("oaizjd"))); +} + +#[test] +pub fn discard_err_err() { + assert_eq!(result::discard_err(Err("hello")), None); +} + +#[test] +pub fn discard_err_ok() { + assert_eq!(result::discard_err(Ok(128)), Some(128)); +} diff --git a/subject_text/errors/index.md b/subject_text/errors/index.md index 627e9c3..4f8ac3e 100644 --- a/subject_text/errors/index.md +++ b/subject_text/errors/index.md @@ -1,6 +1,6 @@ --- name = "Errors" difficulty = 1 -exercises = ["option.md"] +exercises = ["option.md", "result.md"] --- diff --git a/subject_text/errors/result.md b/subject_text/errors/result.md new file mode 100644 index 0000000..f1769d4 --- /dev/null +++ b/subject_text/errors/result.md @@ -0,0 +1,64 @@ +--- +name = "Results" +file = "src/errors/result.rs" +--- + +We saw earlier the `Option` type, which represents a possibly absent value (sometimes called "nullable" in other languages). Now it would be useful to carry **the reason** of this absence of value. Let's say you are parsing an integer from a `String`, there are multiple ways it can fail. + +- The string contains invalid characters (non-digits). +- The value we want to parse is too large (for example, trying to parse `"999999999999"` as an i32). + +If we want to react properly, we need to know why it failed. So instead of having only `None` as output, we would like a variant like `SomeError(v)`. In Rust, this type with `Some` and `SomeError` variants is called [`Result`](https://doc.rust-lang.org/std/result/). + +Its variants are `Ok` and `Err`, and we can use it much like `Option`: + +```rust +// creating values of type Result +let itworked: Result = Ok(420); +let oops: Result = Err("badb002e"); + +// using values from Result +match itworked { + Ok(value) => println!("yes, we got {value}"), + Err(err) => eprintln!("oh no, some error occured: {err}"), +} +``` + +```prototype +/// Returns `true` if the result contains an `Err` +pub fn is_err(res: &Result) -> bool { + unimplemented!() +} + +/// Returns `true` if the result contains a `Ok` +pub fn is_ok(res: &Result) -> bool { + unimplemented!() +} + +/// Returns the wrapped `&str` if any, panic otherwise +pub fn get_err_or_panic(res: Result) -> &str { + unimplemented!() +} + +/// Returns the wrapped `i32` if any, panic otherwise +pub fn get_val_or_panic(res: Result) -> i32 { + unimplemented!() +} + +/// Transforms `Ok` to `Some` and `Err` to `None` +/// effectively discarding the `Err` wrapped value +pub fn discard_err(res: Result) -> Option { + unimplemented!() +} +``` + +```example +fn main() { + dbg!(is_err(Ok(10))); // false + dbg!(is_ok(Ok(128))); // true + dbg!(get_err_or_panic(Err("oh no"))); // "oh no" + dbg!(get_val_or_panic(Ok(420))); // 420 + dbg!(discard_err(Ok(69))); // Some(69) +} +``` +