pub type Result<T = (), E = Error> = Result<T, E>;
Expand description
A Result
with an Error
error type.
To be used as the return type for functions that may fail.
§Error codes in C and Rust
In C, it is common that functions indicate success or failure through
their return value; modifying or returning extra data through non-const
pointer parameters. In particular, in the kernel, functions that may fail
typically return an int
that represents a generic error code. We model
those as Error
.
In Rust, it is idiomatic to model functions that may fail as returning
a Result
. Since in the kernel many functions return an error code,
Result
is a type alias for a core::result::Result
that uses
Error
as its error type.
Note that even if a function does not return anything when it succeeds,
it should still be modeled as returning a Result
rather than
just an Error
.
Calling a function that returns Result
forces the caller to handle
the returned Result
.
This can be done “manually” by using match
. Using match
to decode
the Result
is similar to C where all the return value decoding and the
error handling is done explicitly by writing handling code for each
error to cover. Using match
the error and success handling can be
implemented in all detail as required. For example (inspired by
samples/rust/rust_minimal.rs
):
fn example() -> Result {
let mut numbers = KVec::new();
match numbers.push(72, GFP_KERNEL) {
Err(e) => {
pr_err!("Error pushing 72: {e:?}");
return Err(e.into());
}
// Do nothing, continue.
Ok(()) => (),
}
match numbers.push(108, GFP_KERNEL) {
Err(e) => {
pr_err!("Error pushing 108: {e:?}");
return Err(e.into());
}
// Do nothing, continue.
Ok(()) => (),
}
match numbers.push(200, GFP_KERNEL) {
Err(e) => {
pr_err!("Error pushing 200: {e:?}");
return Err(e.into());
}
// Do nothing, continue.
Ok(()) => (),
}
Ok(())
}
An alternative to be more concise is the if let
syntax:
fn example() -> Result {
let mut numbers = KVec::new();
if let Err(e) = numbers.push(72, GFP_KERNEL) {
pr_err!("Error pushing 72: {e:?}");
return Err(e.into());
}
if let Err(e) = numbers.push(108, GFP_KERNEL) {
pr_err!("Error pushing 108: {e:?}");
return Err(e.into());
}
if let Err(e) = numbers.push(200, GFP_KERNEL) {
pr_err!("Error pushing 200: {e:?}");
return Err(e.into());
}
Ok(())
}
Instead of these verbose match
/if let
, the ?
operator can
be used to handle the Result
. Using the ?
operator is often
the best choice to handle Result
in a non-verbose way as done in
samples/rust/rust_minimal.rs
:
fn example() -> Result {
let mut numbers = KVec::new();
numbers.push(72, GFP_KERNEL)?;
numbers.push(108, GFP_KERNEL)?;
numbers.push(200, GFP_KERNEL)?;
Ok(())
}
Another possibility is to call unwrap()
or
expect()
. However, use of these functions is
heavily discouraged in the kernel because they trigger a Rust
panic!
if an error happens, which may destabilize the system or
entirely break it as a result – just like the C BUG()
macro.
Please see the documentation for the C macro BUG()
for guidance
on when to use these functions.
Alternatively, depending on the use case, using unwrap_or()
,
unwrap_or_else()
, unwrap_or_default()
or unwrap_unchecked()
might be an option, as well.
For even more details, please see the Rust documentation.
Aliased Type§
enum Result<T = (), E = Error> {
Ok(T),
Err(E),
}