rust-for-linux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Onur Özkan" <work@onurozkan.dev>
To: rust-for-linux@vger.kernel.org
Cc: ojeda@kernel.org, alex.gaynor@gmail.com, boqun.feng@gmail.com,
	gary@garyguo.net, bjorn3_gh@protonmail.com, lossin@kernel.org,
	a.hindborg@kernel.org, aliceryhl@google.com, tmgross@umich.edu,
	dakr@kernel.org, tamird@gmail.com,
	"Onur Özkan" <work@onurozkan.dev>
Subject: [PATCH v3 1/2] rust: add `ToResult` trait
Date: Mon, 13 Oct 2025 15:41:38 +0300	[thread overview]
Message-ID: <20251013124139.18809-2-work@onurozkan.dev> (raw)
In-Reply-To: <20251013124139.18809-1-work@onurozkan.dev>

Adds `ToResult` trait to handle integer return values from C
kernel functions.

Example:
    let _value = unsafe { bindings::foo() }.to_result()?;

This will replace the existing `error::to_result` function,
but it will be handled in the next commit to keep the diff
more readable.

Signed-off-by: Onur Özkan <work@onurozkan.dev>
---
 rust/kernel/error.rs | 74 ++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 74 insertions(+)

diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index 1c0e0e241daa..dc566b0cef13 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -392,6 +392,80 @@ fn from(e: core::convert::Infallible) -> Error {
 /// [Rust documentation]: https://doc.rust-lang.org/book/ch09-02-recoverable-errors-with-result.html
 pub type Result<T = (), E = Error> = core::result::Result<T, E>;
 
+/// Trait for handling integer return values from C kernel functions by converting
+/// them into idiomatic Rust [`Result`]s.
+pub trait ToResult {
+    /// The unsigned version of the integer type used for successful return values.
+    type Unsigned;
+
+    /// Converts an integer as returned by a C kernel function to a [`Result`].
+    ///
+    /// If the integer is negative, an [`Err`] with an [`Error`] as given by [`Error::from_errno`]
+    /// is returned. This means the integer must be `>= -MAX_ERRNO`.
+    ///
+    /// Otherwise, it returns the original value as an unsigned integer.
+    ///
+    /// It is a bug to pass an out-of-range negative integer. `Err(EINVAL)` is returned
+    /// in such a case.
+    ///
+    /// # Examples
+    ///
+    /// This function may be used to easily perform early returns with the [`?`] operator
+    /// when working with C APIs within Rust abstractions:
+    ///
+    /// ```
+    /// # use kernel::error::ToResult;
+    /// # mod bindings {
+    /// #     #![expect(clippy::missing_safety_doc)]
+    /// #     use kernel::prelude::*;
+    /// #     pub(super) unsafe fn f1() -> c_int { 0 }
+    /// #     pub(super) unsafe fn f2() -> c_int { EINVAL.to_errno() }
+    /// # }
+    /// fn f() -> Result {
+    ///     // SAFETY: ...
+    ///     let _value = unsafe { bindings::f1() }.to_result()?;
+    ///
+    ///     // SAFETY: ...
+    ///     let _value = unsafe { bindings::f2() }.to_result()?;
+    ///
+    ///     // ...
+    ///
+    ///     Ok(())
+    /// }
+    /// # assert_eq!(f(), Err(EINVAL));
+    /// ```
+    ///
+    /// [`?`]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#the-question-mark-operator
+    fn to_result(self) -> Result<Self::Unsigned>;
+}
+
+impl ToResult for i32 {
+    type Unsigned = u32;
+
+    fn to_result(self) -> Result<Self::Unsigned> {
+        if self < 0 {
+            Err(Error::from_errno(self))
+        } else {
+            Ok(self as u32)
+        }
+    }
+}
+
+impl ToResult for isize {
+    type Unsigned = usize;
+
+    fn to_result(self) -> Result<Self::Unsigned> {
+        // Try casting into `i32`.
+        let casted: crate::ffi::c_int = self.try_into().map_err(|_| code::EINVAL)?;
+
+        if casted < 0 {
+            Err(Error::from_errno(casted))
+        } else {
+            Ok(self as usize)
+        }
+    }
+}
+
 /// Converts an integer as returned by a C kernel function to a [`Result`].
 ///
 /// If the integer is negative, an [`Err`] with an [`Error`] as given by [`Error::from_errno`] is
-- 
2.51.0


  reply	other threads:[~2025-10-13 12:43 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2025-10-13 12:41 [PATCH v3 0/2] rust: refactor `to_result` Onur Özkan
2025-10-13 12:41 ` Onur Özkan [this message]
2025-10-13 12:48   ` [PATCH v3 1/2] rust: add `ToResult` trait Onur Özkan
2025-10-13 12:41 ` [PATCH v3 2/2] rust: drop `error::to_result` and utilize `ToResult` Onur Özkan
2025-10-13 17:04   ` Miguel Ojeda
2025-10-13 19:03     ` Onur Özkan
2025-10-13 18:29   ` Alice Ryhl

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=20251013124139.18809-2-work@onurozkan.dev \
    --to=work@onurozkan.dev \
    --cc=a.hindborg@kernel.org \
    --cc=alex.gaynor@gmail.com \
    --cc=aliceryhl@google.com \
    --cc=bjorn3_gh@protonmail.com \
    --cc=boqun.feng@gmail.com \
    --cc=dakr@kernel.org \
    --cc=gary@garyguo.net \
    --cc=lossin@kernel.org \
    --cc=ojeda@kernel.org \
    --cc=rust-for-linux@vger.kernel.org \
    --cc=tamird@gmail.com \
    --cc=tmgross@umich.edu \
    /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;
as well as URLs for NNTP newsgroup(s).