Enum propagate::Result [−][src]
pub enum Result<T, E, S = ErrorTrace> {
Ok(T),
Err(E, S),
}
Expand description
A replacement for std::result::Result
that supports tracing via the ?
operator.
After a propagate::Result
has been constructed, it will keep a running
“return trace” of the code locations where the ?
operator is invoked on it.
Working with propagate::Result
There are a few things to remember when using propagate::Result
as a
replacement for the std library result.
Creating Errors
Construct an Err
variant by providing an error value and a new trace
(e.g., using ErrorTrace::new()
):
use propagate::ErrorTrace;
fn gives_error() -> propagate::Result<(), &'static str> {
propagate::Err("Nothing here", ErrorTrace::new())
}
Pattern Matching
The Err
variant contains two values: the error and its associated trace.
Pattern matching should look like this:
let result: propagate::Result<_, _> = gives_error();
match result {
propagate::Ok(_) => {}
propagate::Err(err, trace) => {
println!("error: {}", err);
println!("trace: {}", trace);
}
}
IMPORTANT: Forwarding Errors
When not using try
blocks, you must remember to surround result values
with Ok(..?)
when returning them in a function. The compiler will not
force you to do this if the result value’s type is identical to the
function’s return type.
// YES: Result surrounded by Ok(..?), so the error trace will include foo()
fn foo() -> propagate::Result<(), &'static str> {
let result = gives_error();
propagate::Ok(result?)
}
// NO: Result returned directly, so the error trace will not include bar()
fn bar() -> propagate::Result<(), &'static str> {
let result = gives_error();
result
}
When you use try
blocks, you do not need the Ok
:
#![feature(try_blocks)]
fn foo() -> propagate::Result<(), &'static str> {
try {
let result = gives_error();
result?
}
}
And the compiler will force you to use ?
:
#![feature(try_blocks)]
fn bar() -> propagate::Result<(), &'static str> {
try {
let result = gives_error();
result
}
}
Coercion Using ?
The ?
operator can be used to coerce between result types.
From propagate
to propagate
One propagate::Result
can be coerced to another if there is an
implementation of From
between the two error types:
#![feature(try_blocks)]
let result: propagate::Result<(), &str> =
propagate::Err("str slice", ErrorTrace::new());
// Coerces string slice to String object
let result: propagate::Result<(), String> = try { result? };
From std
to propagate
To provide easy interoperability with standard library modules and other
crates that return results, any std::result::Result
can be coerced to a
propagate::Result
:
#![feature(try_blocks)]
let result: Result<(), u32> = Err(42);
// Coerces std::result::Result to propagate::Result
let result: propagate::Result<(), u32> = try { result? };
And if there is an implementation of From
between the two error types,
you can do that coercion at the same time:
#![feature(try_blocks)]
let result: Result<(), &str> = Err("string slice");
// Coerces std::result::Result to propagate::Result
// AND
// Coerces string slice to String object
let result: propagate::Result<(), String> = try { result? };
Variants
Contains the success value.
Contains the error value and associated error trace.
Implementations
Stuff not from the standard library.
Converts from Result<T, E, S>
to std::result::Result<T, E>
.
Converts self
into a std::result::Result<T, E>
, consuming self
,
and discarding the error trace, if any.
Examples
Basic usage:
let x: Result<u32, &str> = propagate::Ok(2);
assert_eq!(x.to_std(), std::result::Result::Ok(2));
let x: Result<u32, &str> = Result::new_err("Nothing here");
assert_eq!(x.to_std(), std::result::Result::Err("Nothing here"));
Converts from Result<T, E, S>
to Option<(E, S)>
.
Converts self
into an Option<(E, S)>
, consuming self
,
and discarding the success value, if any.
Examples
Basic usage:
let x: Result<u32, &str> = propagate::Ok(2);
assert!(x.err_trace().is_none());
let x: Result<u32, &str> = Result::new_err("Nothing here");
match x.err_trace() {
Some((err, trace)) => {
assert_eq!(err, "Nothing here");
assert_eq!(trace.0.len(), 1);
}
None => unreachable!(),
}
Returns true
if the result is Ok
.
Examples
Basic usage:
let x: Result<i32, &str> = propagate::Ok(-3);
assert_eq!(x.is_ok(), true);
let x: Result<i32, &str> = Result::new_err("Some error message");
assert_eq!(x.is_ok(), false);
Returns true
if the result is Err
.
Examples
Basic usage:
let x: Result<i32, &str> = propagate::Ok(-3);
assert_eq!(x.is_err(), false);
let x: Result<i32, &str> = Result::new_err("Some error message");
assert_eq!(x.is_err(), true);
Converts from Result<T, E, S>
to Option<T>
.
Converts self
into an Option<T>
, consuming self
,
and discarding the error, if any.
Examples
Basic usage:
let x: Result<u32, &str> = propagate::Ok(2);
assert_eq!(x.ok(), Some(2));
let x: Result<u32, &str> = Result::new_err("Nothing here");
assert_eq!(x.ok(), None);
Converts from Result<T, E, S>
to Option<E>
.
Converts self
into an Option<E>
, consuming self
,
and discarding the success value and error trace, if any.
Examples
Basic usage:
let x: Result<u32, &str> = propagate::Ok(2);
assert_eq!(x.err(), None);
let x: Result<u32, &str> = Result::new_err("Nothing here");
assert_eq!(x.err(), Some("Nothing here"));
Converts from &Result<T, E, S>
to Result<&T, &E, &S>
.
Produces a new Result
, containing a reference
into the original, leaving the original in place.
Examples
Basic usage:
let x: Result<u32, &str> = propagate::Ok(2);
assert_eq!(x.as_ref(), propagate::Ok(&2));
let x: Result<u32, &str> = Result::new_err("Error");
assert!(matches!(x.as_ref(), propagate::Err(&"Error", _)));
Converts from &mut Result<T, E, S>
to Result<&mut T, &mut E, &mut S>
.
Examples
Basic usage:
fn mutate(r: &mut Result<i32, i32>) {
match r.as_mut() {
propagate::Ok(v) => *v = 42,
propagate::Err(e, _) => *e = 0,
}
}
let mut x: Result<i32, i32> = propagate::Ok(2);
mutate(&mut x);
assert_eq!(x.unwrap(), 42);
let mut x: Result<i32, i32> = Result::new_err(13);
mutate(&mut x);
assert_eq!(x.unwrap_err(), 0);
Maps a Result<T, E>
to Result<T, F>
by applying a function to a
contained Err
value, leaving an Ok
value untouched.
This function can be used to pass through a successful result while handling an error.
Examples
Basic usage:
fn stringify(x: i32) -> String { format!("error code: {}", x) }
let x: Result<i32, i32> = propagate::Ok(2);
assert_eq!(x.map_err(stringify), propagate::Ok(2));
let x: Result<i32, i32> = Result::new_err(13);
let y: Result<i32, String> = x.map_err(stringify);
assert_eq!(y.err().unwrap(), "error code: 13".to_string());
Returns the contained Ok
value or a provided default.
Arguments passed to unwrap_or
are eagerly evaluated; if you are passing
the result of a function call, it is recommended to use unwrap_or_else
,
which is lazily evaluated.
Examples
Basic usage:
let default = 2;
let x: Result<u32, &str> = propagate::Ok(9);
assert_eq!(x.unwrap_or(default), 9);
let x: Result<u32, &str> = Result::new_err("error");
assert_eq!(x.unwrap_or(default), default);
Returns the contained Ok
value or computes it from a closure.
Examples
Basic usage:
fn count(x: &str) -> usize { x.len() }
let x: Result<usize, &str> = propagate::Ok(2);
assert_eq!(x.unwrap_or_else(count), 2);
let x: Result<usize, &str> = propagate::Err("foo", ErrorTrace::new());
assert_eq!(x.unwrap_or_else(count), 3);
Returns the contained Ok
value, consuming the self
value.
Panics
Panics if the value is an Err
, with a panic message including the
passed message, and the content of the Err
.
Examples
Basic usage:
let x: Result<u32, &str> = Result::new_err("emergency failure");
x.expect("Testing expect"); // panics with `Testing expect: emergency failure`
Returns the contained Ok
value, consuming the self
value.
Because this function may panic, its use is generally discouraged.
Instead, prefer to use pattern matching and handle the Err
case explicitly, or call unwrap_or
, unwrap_or_else
, or
unwrap_or_default
.
Panics
Panics if the value is an Err
, with a panic message provided by the
Err
’s value.
Examples
Basic usage:
let x: Result<u32, &str> = propagate::Ok(2);
assert_eq!(x.unwrap(), 2);
let x: Result<u32, &str> = Result::new_err("emergency failure");
x.unwrap(); // panics with `emergency failure`
Returns the contained Err
value, consuming the self
value.
Panics
Panics if the value is an Ok
, with a panic message including the
passed message, and the content of the Ok
.
Examples
Basic usage:
let x: Result<u32, &str> = propagate::Ok(10);
x.expect_err("Testing expect_err"); // panics with `Testing expect_err: 10`
Returns the contained Err
value, consuming the self
value.
Panics
Panics if the value is an Ok
, with a custom panic message provided
by the Ok
’s value.
Examples
let x: Result<u32, &str> = propagate::Ok(2);
x.unwrap_err(); // panics with `2`
let x: Result<u32, &str> = Result::new_err("emergency failure");
assert_eq!(x.unwrap_err(), "emergency failure");
Returns the contained Ok
value or a default
Consumes the self
argument then, if Ok
, returns the contained
value, otherwise if Err
, returns the default value for that
type.
Examples
Converts a string to an integer, turning poorly-formed strings
into 0 (the default value for integers). parse
converts
a string to any other type that implements FromStr
, returning an
Err
on error.
let good_year_from_input = "1909";
let bad_year_from_input = "190blarg";
let good_year = good_year_from_input.parse().unwrap_or_default();
let bad_year = bad_year_from_input.parse().unwrap_or_default();
assert_eq!(1909, good_year);
assert_eq!(0, bad_year);
Transposes a Result
of an Option
into an Option
of a Result
.
Ok(None)
will be mapped to None
.
Ok(Some(_))
and Err(_, _)
will be mapped to Some(Ok(_))
and
Some(Err(_, _))
.
Examples
#[derive(Debug, Eq, PartialEq)]
struct SomeErr;
let x: Result<Option<i32>, SomeErr> = propagate::Ok(Some(5));
let y: Option<Result<i32, SomeErr>> = Some(propagate::Ok(5));
assert_eq!(x.transpose(), y);
Trait Implementations
impl<T, E, S, F> FromResidual<Result<Infallible, E, S>> for Result<T, F, S> where
S: Traced,
F: From<E>,
impl<T, E, S, F> FromResidual<Result<Infallible, E, S>> for Result<T, F, S> where
S: Traced,
F: From<E>,
Pushes an entry to the trace when one Result
is coerced to another using the ?
operator.
try_trait_v2
)Constructs the type from a compatible Residual
type. Read more
impl<T, E, S, F> FromResidual<Result<Infallible, E>> for Result<T, F, S> where
S: Traced + Default,
F: From<E>,
impl<T, E, S, F> FromResidual<Result<Infallible, E>> for Result<T, F, S> where
S: Traced + Default,
F: From<E>,
Starts a new trace when a std::result::Result
is coerced to a Result
using ?
.
try_trait_v2
)Constructs the type from a compatible Residual
type. Read more
Overriding the try operator ?
for Result
.
Invoking the ?
operator invokes Self::branch()
under the hood. This
function returns a ControlFlow
enum which dictates whether the execution
will continue forward (i.e., Ok()
), or break early (i.e., Err()
). The
value produced when continuing is the Output
, and the value produced when
breaking early is called the Residual
.
Coercion between residual types is achieved by implementing the
FromResidual
trait. Result
allows coercion from standard library
results (std::result::Result
) as well as from other Result
instances
whose inner error types are convertible from one to another.
type Output = T
type Output = T
try_trait_v2
)The type of the value produced by ?
when not short-circuiting.
type Residual = Result<Infallible, E, S>
type Residual = Result<Infallible, E, S>
try_trait_v2
)The type of the value passed to FromResidual::from_residual
as part of ?
when short-circuiting. Read more
try_trait_v2
)Constructs the type from its Output
type. Read more
try_trait_v2
)Used in ?
to decide whether the operator should produce a value
(because this returned ControlFlow::Continue
)
or propagate a value back to the caller
(because this returned ControlFlow::Break
). Read more