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
/// 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");
}