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.
pull/77/head
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
/// might be a normal handleable error.
pub enum Result<A, FE, E> {
pub enum Result<A, E, FE> {
/// The operation was successful
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
/// safely shut the application down.
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.
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
O: FnOnce(A) -> B,
{
match self {
Result::Ok(val) => Result::Ok(mapper(val)),
Result::Fatal(err) => Result::Fatal(err),
Result::Err(err) => Result::Err(err),
Result::Fatal(err) => Result::Fatal(err),
}
}
/// Apply a potentially fallible function to a successful value.
///
/// 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
O: FnOnce(A) -> Result<B, FE, E>,
O: FnOnce(A) -> Result<B, E, FE>,
{
match self {
Result::Ok(val) => handler(val),
Result::Fatal(err) => Result::Fatal(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
/// 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.
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
O: FnOnce(E) -> F,
{
match self {
Result::Ok(val) => Result::Ok(val),
Result::Fatal(err) => Result::Fatal(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.
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
O: FnOnce(E) -> Result<A, FE, F>,
O: FnOnce(E) -> Result<A, F, FE>,
{
match self {
Result::Ok(val) => Result::Ok(val),
Result::Fatal(err) => Result::Fatal(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
/// 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 {
match r {
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
A: 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
A: PartialEq,
FE: PartialEq,
@ -142,17 +142,17 @@ where
}
/// 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)
}
/// 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)
}
/// 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)
}
@ -210,45 +210,45 @@ mod test {
#[test]
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));
}
#[test]
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)));
}
#[test]
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!(
ok::<i32, FatalError, Error>(16),
ok::<i32, Error, FatalError>(16),
failure.or_else(|_| ok(16))
);
}
#[test]
fn early_exit_on_fatal() {
fn ok_func() -> Result<i32, FatalError, Error> {
let value = return_fatal!(ok::<i32, FatalError, Error>(15));
fn ok_func() -> Result<i32, Error, FatalError> {
let value = return_fatal!(ok::<i32, Error, FatalError>(15));
match value {
Ok(_) => ok(14),
Err(err) => error(err),
}
}
fn err_func() -> Result<i32, FatalError, Error> {
let value = return_fatal!(error::<i32, FatalError, Error>(Error::Error));
fn err_func() -> Result<i32, Error, FatalError> {
let value = return_fatal!(error::<i32, Error, FatalError>(Error::Error));
match value {
Ok(_) => panic!("shouldn't have gotten here"),
Err(_) => ok(0),
}
}
fn fatal_func() -> Result<i32, FatalError, Error> {
return_fatal!(fatal::<i32, FatalError, Error>(FatalError::FatalError));
fn fatal_func() -> Result<i32, Error, FatalError> {
let _ = return_fatal!(fatal::<i32, Error, FatalError>(FatalError::FatalError));
panic!("failed to bail");
}
@ -259,19 +259,19 @@ mod test {
#[test]
fn it_can_early_exit_on_all_errors() {
fn ok_func() -> Result<i32, FatalError, Error> {
let value = return_error!(ok::<i32, FatalError, Error>(15));
fn ok_func() -> Result<i32, Error, FatalError> {
let value = return_error!(ok::<i32, Error, FatalError>(15));
assert_eq!(value, 15);
ok(14)
}
fn err_func() -> Result<i32, FatalError, Error> {
return_error!(error::<i32, FatalError, Error>(Error::Error));
fn err_func() -> Result<i32, Error, FatalError> {
return_error!(error::<i32, Error, FatalError>(Error::Error));
panic!("failed to bail");
}
fn fatal_func() -> Result<i32, FatalError, Error> {
return_error!(fatal::<i32, FatalError, Error>(FatalError::FatalError));
fn fatal_func() -> Result<i32, Error, FatalError> {
return_error!(fatal::<i32, Error, FatalError>(FatalError::FatalError));
panic!("failed to bail");
}