rust-for-linux.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v3] rust: optimize error type to use nonzero
@ 2024-10-03 23:16 Filipe Xavier
  2024-10-03 23:23 ` Miguel Ojeda
  0 siblings, 1 reply; 8+ messages in thread
From: Filipe Xavier @ 2024-10-03 23:16 UTC (permalink / raw)
  To: ojeda@kernel.org, aliceryhl@google.com, boqun.feng@gmail.com,
	Benno Lossin, gary@garyguo.net, alex.gaynor@gmail.com
  Cc: rust-for-linux@vger.kernel.org, Filipe Xavier

Optimize `Result<(), Error>` size by changing `Error` type to 
`NonZero*` for niche optimization.

This reduces the space used by the `Result` type, as the `NonZero*` 
type enables the compiler to apply more efficient memory layout.
For example, the `Result<(), Error>` changes size from 8 to 4 bytes.

Link: https://github.com/Rust-for-Linux/linux/issues/1120
Signed-off-by: Filipe Xavier <felipe_life@live.com>
---
 rust/kernel/error.rs | 32 +++++++++++++++++++++++---------
 1 file changed, 23 insertions(+), 9 deletions(-)

diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index d7965ded2973..9e2910a6c1ea 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -9,6 +9,7 @@
 use alloc::alloc::LayoutError;
 
 use core::fmt;
+use core::num::NonZeroI32;
 use core::num::TryFromIntError;
 use core::str::Utf8Error;
 
@@ -20,7 +21,18 @@ macro_rules! declare_err {
             $(
             #[doc = $doc]
             )*
-            pub const $err: super::Error = super::Error(-(crate::bindings::$err as i32));
+            pub const $err: super::Error = {
+                let err_code: i32 = -(crate::bindings::$err as i32);
+                crate::build_assert!(
+                    err_code >= -(bindings::MAX_ERRNO as i32) && err_code < 0,
+                    "`err` must be within error code range (i.e. `>= -MAX_ERRNO && < 0`)"
+                );
+
+                // SAFETY: `err_code` is checked above to be in a valid range.
+                unsafe {
+                    super::Error::from_errno_unchecked(err_code)
+                }
+            };
         };
     }
 
@@ -88,7 +100,7 @@ macro_rules! declare_err {
 ///
 /// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`).
 #[derive(Clone, Copy, PartialEq, Eq)]
-pub struct Error(core::ffi::c_int);
+pub struct Error(NonZeroI32);
 
 impl Error {
     /// Creates an [`Error`] from a kernel error code.
@@ -107,7 +119,8 @@ pub fn from_errno(errno: core::ffi::c_int) -> Error {
 
         // INVARIANT: The check above ensures the type invariant
         // will hold.
-        Error(errno)
+        // SAFETY: `errno` must be within error code range (i.e. `>= -MAX_ERRNO && < 0`).
+        unsafe { Error::from_errno_unchecked(errno) }
     }
 
     /// Creates an [`Error`] from a kernel error code.
@@ -115,21 +128,22 @@ pub fn from_errno(errno: core::ffi::c_int) -> Error {
     /// # Safety
     ///
     /// `errno` must be within error code range (i.e. `>= -MAX_ERRNO && < 0`).
-    unsafe fn from_errno_unchecked(errno: core::ffi::c_int) -> Error {
+    const unsafe fn from_errno_unchecked(errno: core::ffi::c_int) -> Error {
         // INVARIANT: The contract ensures the type invariant
         // will hold.
-        Error(errno)
+        // SAFETY: The caller guarantees `errno` is non-zero.
+        Error(unsafe { NonZeroI32::new_unchecked(errno) })
     }
 
     /// Returns the kernel error code.
     pub fn to_errno(self) -> core::ffi::c_int {
-        self.0
+        self.0.get()
     }
 
     #[cfg(CONFIG_BLOCK)]
     pub(crate) fn to_blk_status(self) -> bindings::blk_status_t {
         // SAFETY: `self.0` is a valid error due to its invariant.
-        unsafe { bindings::errno_to_blk_status(self.0) }
+        unsafe { bindings::errno_to_blk_status(self.0.get()) }
     }
 
     /// Returns the error encoded as a pointer.
@@ -137,7 +151,7 @@ pub fn to_ptr<T>(self) -> *mut T {
         #[cfg_attr(target_pointer_width = "32", allow(clippy::useless_conversion))]
         // SAFETY: `self.0` is a valid error due to its invariant.
         unsafe {
-            bindings::ERR_PTR(self.0.into()) as *mut _
+            bindings::ERR_PTR(self.0.get().into()) as *mut _
         }
     }
 
@@ -145,7 +159,7 @@ pub fn to_ptr<T>(self) -> *mut T {
     #[cfg(not(testlib))]
     pub fn name(&self) -> Option<&'static CStr> {
         // SAFETY: Just an FFI call, there are no extra safety requirements.
-        let ptr = unsafe { bindings::errname(-self.0) };
+        let ptr = unsafe { bindings::errname(-self.0.get()) };
         if ptr.is_null() {
             None
         } else {
-- 
2.46.0

^ permalink raw reply related	[flat|nested] 8+ messages in thread

end of thread, other threads:[~2024-10-05 19:03 UTC | newest]

Thread overview: 8+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2024-10-03 23:16 [PATCH v3] rust: optimize error type to use nonzero Filipe Xavier
2024-10-03 23:23 ` Miguel Ojeda
2024-10-04 11:50   ` Filipe Xavier
2024-10-04 12:57     ` Miguel Ojeda
2024-10-05 17:14       ` Filipe Xavier
2024-10-05 17:50         ` Miguel Ojeda
2024-10-05 18:52           ` Filipe Xavier
2024-10-05 19:03             ` Miguel Ojeda

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).