Rust for Linux List
 help / color / mirror / Atom feed
From: Dirk Behme <dirk.behme@de.bosch.com>
To: <rust-for-linux@vger.kernel.org>
Cc: <dirk.behme@de.bosch.com>, <ojeda@kernel.org>
Subject: [PATCH] rust: error: Extend the Result documentation
Date: Tue, 7 Jan 2025 07:21:34 +0100	[thread overview]
Message-ID: <20250107062134.2981602-2-dirk.behme@de.bosch.com> (raw)
In-Reply-To: <20250107062134.2981602-1-dirk.behme@de.bosch.com>

Extend the Result documentation by some guidelines and examples how
to handle Result error cases gracefully. And how to not handle them.

Link: https://lore.kernel.org/rust-for-linux/CANiq72keOdXy0LFKk9SzYWwSjiD710v=hQO4xi+5E4xNALa6cA@mail.gmail.com/
Signed-off-by: Dirk Behme <dirk.behme@de.bosch.com>
---
 rust/kernel/error.rs | 66 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 66 insertions(+)

diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index 0b01975c2286c..456487d4a8ed8 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -256,6 +256,72 @@ fn from(e: core::convert::Infallible) -> Error {
 /// 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`] needs the caller to handle
+/// the returned [`Result`].
+///
+/// This can be done "manually" by using [`match`](https://doc.rust-lang.org/reference/expressions/match-expr.html)
+/// Using [`match`](https://doc.rust-lang.org/reference/expressions/match-expr.html) 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`](https://doc.rust-lang.org/reference/expressions/match-expr.html)
+/// the error and success handling can be implemented in all detail as required.
+/// For example (inspired by [samples/rust/rust_minimal.rs](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/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());},
+///         Ok(()) => (), // Do nothing, continue
+///     }
+///     match numbers.push(108, GFP_KERNEL){
+///         Err(e) => {pr_err!("Error pushing 108: {:?}", e); return Err(e.into());},
+///         Ok(()) => (), // Do nothing, continue
+///     }
+///     match numbers.push(200, GFP_KERNEL){
+///         Err(e) => {pr_err!("Error pushing 200: {:?}", e); return Err(e.into());},
+///         Ok(()) => (), // Do nothing, continue
+///     }
+///     Ok(())
+/// }
+/// ```
+/// Instead of the verbose [`match`](https://doc.rust-lang.org/reference/expressions/match-expr.html)
+/// the [`?`](https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator)-operator
+/// or [`unwrap()`](https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap)/
+/// [`expect()`](https://doc.rust-lang.org/std/result/enum.Result.html#method.expect)
+/// can be used to handle the [`Result`] "automatically". However, in the kernel
+/// context, the usage of [`unwrap()`](https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap) or
+/// [`expect()`](https://doc.rust-lang.org/std/result/enum.Result.html#method.expect) has a side effect which is often
+/// not wanted: The [`panic`](https://docs.kernel.org/driver-api/basics.html#c.panic) called when using
+/// [`unwrap()`](https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap) or
+/// [`expect()`](https://doc.rust-lang.org/std/result/enum.Result.html#method.expect). While the
+/// console output from [`panic`](https://docs.kernel.org/driver-api/basics.html#c.panic) is
+/// nice and quite helpful for debugging the error, stopping the whole Linux system due to the kernel
+/// panic is often **not** desired:
+/// ```
+/// fn example () -> Result {
+///     let mut numbers = KVec::new();
+///     numbers.push(72, GFP_KERNEL).expect("Error pushing 72"); // Panics the system in case of an error
+///     numbers.push(108, GFP_KERNEL).expect("Error pushing 108"); // Panics the system in case of an error
+///     numbers.push(200, GFP_KERNEL).expect("Error pushing 200"); // Panics the system in case of an error
+///     Ok(())
+/// }
+/// ```
+/// Instead [`unwrap_or()`](https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap_or),
+/// [`unwrap_or_else()`](https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap_or_else) or
+/// [`unwrap_or_default()`](https://doc.rust-lang.org/std/result/enum.Result.html#method.unwrap_or_default)
+/// can be used. But in consequence, using the [`?`](https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator)-operator
+/// is often the best choice to handle [`Result`] in a non-verbose way as done in
+/// [samples/rust/rust_minimal.rs](https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/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(())
+/// }
+/// ```
 pub type Result<T = (), E = Error> = core::result::Result<T, E>;
 
 /// Converts an integer as returned by a C kernel function to an error if it's negative, and
-- 
2.46.2


  reply	other threads:[~2025-01-07  6:21 UTC|newest]

Thread overview: 6+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-01-07  6:21 [PATCH] docs: rust: Add error handling sections Dirk Behme
2025-01-07  6:21 ` Dirk Behme [this message]
2025-01-07 12:16   ` [PATCH] rust: error: Extend the Result documentation Daniel Sedlak
2025-01-07 12:54   ` Alice Ryhl
2025-01-12 13:10   ` Miguel Ojeda
2025-01-12 13:45 ` [PATCH] docs: rust: Add error handling sections Miguel Ojeda

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20250107062134.2981602-2-dirk.behme@de.bosch.com \
    --to=dirk.behme@de.bosch.com \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox