Reverse the order of Error and FatalError parameters in the Result

In other usage, I discovered that it's rather confusing to have the parameters in the order that they were in. It feels better to have the fatal error after the regular error.
This commit is contained in:
Savanni D'Gerinel 2023-10-18 22:13:11 -04:00
parent 3cb742d863
commit b756e8ca81
1 changed files with 36 additions and 36 deletions

View File

@ -35,73 +35,73 @@ pub trait FatalError: Error {}
/// Result<A, FE, E> represents a return value that might be a success, might be a fatal error, or /// Result<A, FE, E> represents a return value that might be a success, might be a fatal error, or
/// might be a normal handleable error. /// might be a normal handleable error.
pub enum Result<A, FE, E> { pub enum Result<A, E, FE> {
/// The operation was successful /// The operation was successful
Ok(A), Ok(A),
/// Ordinary errors. These should be handled and the application should recover gracefully.
Err(E),
/// The operation encountered a fatal error. These should be bubbled up to a level that can /// The operation encountered a fatal error. These should be bubbled up to a level that can
/// safely shut the application down. /// safely shut the application down.
Fatal(FE), Fatal(FE),
/// Ordinary errors. These should be handled and the application should recover gracefully.
Err(E),
} }
impl<A, FE, E> Result<A, FE, E> { impl<A, E, FE> Result<A, E, FE> {
/// Apply an infallible function to a successful value. /// Apply an infallible function to a successful value.
pub fn map<B, O>(self, mapper: O) -> Result<B, FE, E> pub fn map<B, O>(self, mapper: O) -> Result<B, E, FE>
where where
O: FnOnce(A) -> B, O: FnOnce(A) -> B,
{ {
match self { match self {
Result::Ok(val) => Result::Ok(mapper(val)), Result::Ok(val) => Result::Ok(mapper(val)),
Result::Fatal(err) => Result::Fatal(err),
Result::Err(err) => Result::Err(err), Result::Err(err) => Result::Err(err),
Result::Fatal(err) => Result::Fatal(err),
} }
} }
/// Apply a potentially fallible function to a successful value. /// Apply a potentially fallible function to a successful value.
/// ///
/// Like `Result.and_then`, the mapping function can itself fail. /// Like `Result.and_then`, the mapping function can itself fail.
pub fn and_then<B, O>(self, handler: O) -> Result<B, FE, E> pub fn and_then<B, O>(self, handler: O) -> Result<B, E, FE>
where where
O: FnOnce(A) -> Result<B, FE, E>, O: FnOnce(A) -> Result<B, E, FE>,
{ {
match self { match self {
Result::Ok(val) => handler(val), Result::Ok(val) => handler(val),
Result::Fatal(err) => Result::Fatal(err),
Result::Err(err) => Result::Err(err), Result::Err(err) => Result::Err(err),
Result::Fatal(err) => Result::Fatal(err),
} }
} }
/// Map a normal error from one type to another. This is useful for converting an error from /// Map a normal error from one type to another. This is useful for converting an error from
/// one type to another, especially in re-throwing an underlying error. `?` syntax does not /// one type to another, especially in re-throwing an underlying error. `?` syntax does not
/// work with `Result`, so you will likely need to use this a lot. /// work with `Result`, so you will likely need to use this a lot.
pub fn map_err<F, O>(self, mapper: O) -> Result<A, FE, F> pub fn map_err<F, O>(self, mapper: O) -> Result<A, F, FE>
where where
O: FnOnce(E) -> F, O: FnOnce(E) -> F,
{ {
match self { match self {
Result::Ok(val) => Result::Ok(val), Result::Ok(val) => Result::Ok(val),
Result::Fatal(err) => Result::Fatal(err),
Result::Err(err) => Result::Err(mapper(err)), Result::Err(err) => Result::Err(mapper(err)),
Result::Fatal(err) => Result::Fatal(err),
} }
} }
/// Provide a function to use to recover from (or simply re-throw) an error. /// Provide a function to use to recover from (or simply re-throw) an error.
pub fn or_else<O, F>(self, handler: O) -> Result<A, FE, F> pub fn or_else<O, F>(self, handler: O) -> Result<A, F, FE>
where where
O: FnOnce(E) -> Result<A, FE, F>, O: FnOnce(E) -> Result<A, F, FE>,
{ {
match self { match self {
Result::Ok(val) => Result::Ok(val), Result::Ok(val) => Result::Ok(val),
Result::Fatal(err) => Result::Fatal(err),
Result::Err(err) => handler(err), Result::Err(err) => handler(err),
Result::Fatal(err) => Result::Fatal(err),
} }
} }
} }
/// Convert from a normal `Result` type to a `Result` type. The error condition for a `Result` will /// Convert from a normal `Result` type to a `Result` type. The error condition for a `Result` will
/// be treated as `Result::Err`, never `Result::Fatal`. /// be treated as `Result::Err`, never `Result::Fatal`.
impl<A, FE, E> From<std::result::Result<A, E>> for Result<A, FE, E> { impl<A, E, FE> From<std::result::Result<A, E>> for Result<A, E, FE> {
fn from(r: std::result::Result<A, E>) -> Self { fn from(r: std::result::Result<A, E>) -> Self {
match r { match r {
Ok(val) => Result::Ok(val), Ok(val) => Result::Ok(val),
@ -110,7 +110,7 @@ impl<A, FE, E> From<std::result::Result<A, E>> for Result<A, FE, E> {
} }
} }
impl<A, FE, E> fmt::Debug for Result<A, FE, E> impl<A, E, FE> fmt::Debug for Result<A, E, FE>
where where
A: fmt::Debug, A: fmt::Debug,
FE: fmt::Debug, FE: fmt::Debug,
@ -125,7 +125,7 @@ where
} }
} }
impl<A, FE, E> PartialEq for Result<A, FE, E> impl<A, E, FE> PartialEq for Result<A, E, FE>
where where
A: PartialEq, A: PartialEq,
FE: PartialEq, FE: PartialEq,
@ -142,17 +142,17 @@ where
} }
/// Convenience function to create an ok value. /// Convenience function to create an ok value.
pub fn ok<A, FE: FatalError, E: Error>(val: A) -> Result<A, FE, E> { pub fn ok<A, E: Error, FE: FatalError>(val: A) -> Result<A, E, FE> {
Result::Ok(val) Result::Ok(val)
} }
/// Convenience function to create an error value. /// Convenience function to create an error value.
pub fn error<A, FE: FatalError, E: Error>(err: E) -> Result<A, FE, E> { pub fn error<A, E: Error, FE: FatalError>(err: E) -> Result<A, E, FE> {
Result::Err(err) Result::Err(err)
} }
/// Convenience function to create a fatal value. /// Convenience function to create a fatal value.
pub fn fatal<A, FE: FatalError, E: Error>(err: FE) -> Result<A, FE, E> { pub fn fatal<A, E: Error, FE: FatalError>(err: FE) -> Result<A, E, FE> {
Result::Fatal(err) Result::Fatal(err)
} }
@ -210,45 +210,45 @@ mod test {
#[test] #[test]
fn it_can_map_things() { fn it_can_map_things() {
let success: Result<i32, FatalError, Error> = ok(15); let success: Result<i32, Error, FatalError> = ok(15);
assert_eq!(ok(16), success.map(|v| v + 1)); assert_eq!(ok(16), success.map(|v| v + 1));
} }
#[test] #[test]
fn it_can_chain_success() { fn it_can_chain_success() {
let success: Result<i32, FatalError, Error> = ok(15); let success: Result<i32, Error, FatalError> = ok(15);
assert_eq!(ok(16), success.and_then(|v| ok(v + 1))); assert_eq!(ok(16), success.and_then(|v| ok(v + 1)));
} }
#[test] #[test]
fn it_can_handle_an_error() { fn it_can_handle_an_error() {
let failure: Result<i32, FatalError, Error> = error(Error::Error); let failure: Result<i32, Error, FatalError> = error(Error::Error);
assert_eq!( assert_eq!(
ok::<i32, FatalError, Error>(16), ok::<i32, Error, FatalError>(16),
failure.or_else(|_| ok(16)) failure.or_else(|_| ok(16))
); );
} }
#[test] #[test]
fn early_exit_on_fatal() { fn early_exit_on_fatal() {
fn ok_func() -> Result<i32, FatalError, Error> { fn ok_func() -> Result<i32, Error, FatalError> {
let value = return_fatal!(ok::<i32, FatalError, Error>(15)); let value = return_fatal!(ok::<i32, Error, FatalError>(15));
match value { match value {
Ok(_) => ok(14), Ok(_) => ok(14),
Err(err) => error(err), Err(err) => error(err),
} }
} }
fn err_func() -> Result<i32, FatalError, Error> { fn err_func() -> Result<i32, Error, FatalError> {
let value = return_fatal!(error::<i32, FatalError, Error>(Error::Error)); let value = return_fatal!(error::<i32, Error, FatalError>(Error::Error));
match value { match value {
Ok(_) => panic!("shouldn't have gotten here"), Ok(_) => panic!("shouldn't have gotten here"),
Err(_) => ok(0), Err(_) => ok(0),
} }
} }
fn fatal_func() -> Result<i32, FatalError, Error> { fn fatal_func() -> Result<i32, Error, FatalError> {
return_fatal!(fatal::<i32, FatalError, Error>(FatalError::FatalError)); let _ = return_fatal!(fatal::<i32, Error, FatalError>(FatalError::FatalError));
panic!("failed to bail"); panic!("failed to bail");
} }
@ -259,19 +259,19 @@ mod test {
#[test] #[test]
fn it_can_early_exit_on_all_errors() { fn it_can_early_exit_on_all_errors() {
fn ok_func() -> Result<i32, FatalError, Error> { fn ok_func() -> Result<i32, Error, FatalError> {
let value = return_error!(ok::<i32, FatalError, Error>(15)); let value = return_error!(ok::<i32, Error, FatalError>(15));
assert_eq!(value, 15); assert_eq!(value, 15);
ok(14) ok(14)
} }
fn err_func() -> Result<i32, FatalError, Error> { fn err_func() -> Result<i32, Error, FatalError> {
return_error!(error::<i32, FatalError, Error>(Error::Error)); return_error!(error::<i32, Error, FatalError>(Error::Error));
panic!("failed to bail"); panic!("failed to bail");
} }
fn fatal_func() -> Result<i32, FatalError, Error> { fn fatal_func() -> Result<i32, Error, FatalError> {
return_error!(fatal::<i32, FatalError, Error>(FatalError::FatalError)); return_error!(fatal::<i32, Error, FatalError>(FatalError::FatalError));
panic!("failed to bail"); panic!("failed to bail");
} }