Skip to content

Commit dc60dd0

Browse files
dirkbehmeojeda
authored andcommitted
rust: error: extend the Result documentation
Extend the Result documentation by some guidelines and examples how to handle Result error cases gracefully. And how to not handle them. While at it fix one missing `Result` link in the existing documentation. [ Moved links out-of-line for improved readability. Fixed `srctree` link. Sorted out-of-line links. Added newlines for consistency with other docs. Applied paragraph break suggestion. Reworded slightly the docs in a couple places. Added Markdown. In addition, added `#[allow(clippy::single_match)` for the first example. It cannot be an `expect` since due to a difference introduced in Rust 1.85.0 when there are comments in the arms of the `match`. Reported it upstream, but it was intended: rust-lang/rust-clippy#14418 Perhaps Clippy will lint about it in the future, but without autofix: rust-lang/rust-clippy#14420 - Miguel ] Link: https://lore.kernel.org/rust-for-linux/CANiq72keOdXy0LFKk9SzYWwSjiD710v=hQO4xi+5E4xNALa6cA@mail.gmail.com/ Signed-off-by: Dirk Behme <[email protected]> Reviewed-by: Fiona Behrens <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Miguel Ojeda <[email protected]>
1 parent ab2ebb7 commit dc60dd0

File tree

1 file changed

+122
-1
lines changed

1 file changed

+122
-1
lines changed

rust/kernel/error.rs

Lines changed: 122 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -248,8 +248,129 @@ impl From<core::convert::Infallible> for Error {
248248
/// [`Error`] as its error type.
249249
///
250250
/// Note that even if a function does not return anything when it succeeds,
251-
/// it should still be modeled as returning a `Result` rather than
251+
/// it should still be modeled as returning a [`Result`] rather than
252252
/// just an [`Error`].
253+
///
254+
/// Calling a function that returns [`Result`] forces the caller to handle
255+
/// the returned [`Result`].
256+
///
257+
/// This can be done "manually" by using [`match`]. Using [`match`] to decode
258+
/// the [`Result`] is similar to C where all the return value decoding and the
259+
/// error handling is done explicitly by writing handling code for each
260+
/// error to cover. Using [`match`] the error and success handling can be
261+
/// implemented in all detail as required. For example (inspired by
262+
/// [`samples/rust/rust_minimal.rs`]):
263+
///
264+
/// ```
265+
/// # #[allow(clippy::single_match)]
266+
/// fn example() -> Result {
267+
/// let mut numbers = KVec::new();
268+
///
269+
/// match numbers.push(72, GFP_KERNEL) {
270+
/// Err(e) => {
271+
/// pr_err!("Error pushing 72: {e:?}");
272+
/// return Err(e.into());
273+
/// }
274+
/// // Do nothing, continue.
275+
/// Ok(()) => (),
276+
/// }
277+
///
278+
/// match numbers.push(108, GFP_KERNEL) {
279+
/// Err(e) => {
280+
/// pr_err!("Error pushing 108: {e:?}");
281+
/// return Err(e.into());
282+
/// }
283+
/// // Do nothing, continue.
284+
/// Ok(()) => (),
285+
/// }
286+
///
287+
/// match numbers.push(200, GFP_KERNEL) {
288+
/// Err(e) => {
289+
/// pr_err!("Error pushing 200: {e:?}");
290+
/// return Err(e.into());
291+
/// }
292+
/// // Do nothing, continue.
293+
/// Ok(()) => (),
294+
/// }
295+
///
296+
/// Ok(())
297+
/// }
298+
/// # example()?;
299+
/// # Ok::<(), Error>(())
300+
/// ```
301+
///
302+
/// An alternative to be more concise is the [`if let`] syntax:
303+
///
304+
/// ```
305+
/// fn example() -> Result {
306+
/// let mut numbers = KVec::new();
307+
///
308+
/// if let Err(e) = numbers.push(72, GFP_KERNEL) {
309+
/// pr_err!("Error pushing 72: {e:?}");
310+
/// return Err(e.into());
311+
/// }
312+
///
313+
/// if let Err(e) = numbers.push(108, GFP_KERNEL) {
314+
/// pr_err!("Error pushing 108: {e:?}");
315+
/// return Err(e.into());
316+
/// }
317+
///
318+
/// if let Err(e) = numbers.push(200, GFP_KERNEL) {
319+
/// pr_err!("Error pushing 200: {e:?}");
320+
/// return Err(e.into());
321+
/// }
322+
///
323+
/// Ok(())
324+
/// }
325+
/// # example()?;
326+
/// # Ok::<(), Error>(())
327+
/// ```
328+
///
329+
/// Instead of these verbose [`match`]/[`if let`], the [`?`] operator can
330+
/// be used to handle the [`Result`]. Using the [`?`] operator is often
331+
/// the best choice to handle [`Result`] in a non-verbose way as done in
332+
/// [`samples/rust/rust_minimal.rs`]:
333+
///
334+
/// ```
335+
/// fn example() -> Result {
336+
/// let mut numbers = KVec::new();
337+
///
338+
/// numbers.push(72, GFP_KERNEL)?;
339+
/// numbers.push(108, GFP_KERNEL)?;
340+
/// numbers.push(200, GFP_KERNEL)?;
341+
///
342+
/// Ok(())
343+
/// }
344+
/// # example()?;
345+
/// # Ok::<(), Error>(())
346+
/// ```
347+
///
348+
/// Another possibility is to call [`unwrap()`](Result::unwrap) or
349+
/// [`expect()`](Result::expect). However, use of these functions is
350+
/// *heavily discouraged* in the kernel because they trigger a Rust
351+
/// [`panic!`] if an error happens, which may destabilize the system or
352+
/// entirely break it as a result -- just like the C [`BUG()`] macro.
353+
/// Please see the documentation for the C macro [`BUG()`] for guidance
354+
/// on when to use these functions.
355+
///
356+
/// Alternatively, depending on the use case, using [`unwrap_or()`],
357+
/// [`unwrap_or_else()`], [`unwrap_or_default()`] or [`unwrap_unchecked()`]
358+
/// might be an option, as well.
359+
///
360+
/// For even more details, please see the [Rust documentation].
361+
///
362+
/// [`match`]: https://doc.rust-lang.org/reference/expressions/match-expr.html
363+
/// [`samples/rust/rust_minimal.rs`]: srctree/samples/rust/rust_minimal.rs
364+
/// [`if let`]: https://doc.rust-lang.org/reference/expressions/if-expr.html#if-let-expressions
365+
/// [`?`]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator
366+
/// [`unwrap()`]: Result::unwrap
367+
/// [`expect()`]: Result::expect
368+
/// [`BUG()`]: https://docs.kernel.org/process/deprecated.html#bug-and-bug-on
369+
/// [`unwrap_or()`]: Result::unwrap_or
370+
/// [`unwrap_or_else()`]: Result::unwrap_or_else
371+
/// [`unwrap_or_default()`]: Result::unwrap_or_default
372+
/// [`unwrap_unchecked()`]: Result::unwrap_unchecked
373+
/// [Rust documentation]: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html
253374
pub type Result<T = (), E = Error> = core::result::Result<T, E>;
254375

255376
/// Converts an integer as returned by a C kernel function to an error if it's negative, and

0 commit comments

Comments
 (0)