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),
}