Type Alias Result

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

Variants§

§1.0.0

Ok(T)

Contains the success value

§1.0.0

Err(E)

Contains the error value