mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
synced 2025-01-17 02:15:57 +00:00
rust: error: optimize error type to use nonzero
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> Reviewed-by: Gary Guo <gary@garyguo.net> Reviewed-by: Alice Ryhl <aliceryhl@google.com> Reviewed-by: Fiona Behrens <me@kloenk.dev> Link: https://lore.kernel.org/r/BL0PR02MB4914B9B088865CF237731207E9732@BL0PR02MB4914.namprd02.prod.outlook.com [ Removed unneeded block around `match`, added backticks in panic message and added intra-doc link. - Miguel ] Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
This commit is contained in:
parent
f4c2c90bb7
commit
e9759c5b9e
@ -9,6 +9,7 @@ use crate::{alloc::AllocError, str::CStr};
|
|||||||
use alloc::alloc::LayoutError;
|
use alloc::alloc::LayoutError;
|
||||||
|
|
||||||
use core::fmt;
|
use core::fmt;
|
||||||
|
use core::num::NonZeroI32;
|
||||||
use core::num::TryFromIntError;
|
use core::num::TryFromIntError;
|
||||||
use core::str::Utf8Error;
|
use core::str::Utf8Error;
|
||||||
|
|
||||||
@ -20,7 +21,11 @@ pub mod code {
|
|||||||
$(
|
$(
|
||||||
#[doc = $doc]
|
#[doc = $doc]
|
||||||
)*
|
)*
|
||||||
pub const $err: super::Error = super::Error(-(crate::bindings::$err as i32));
|
pub const $err: super::Error =
|
||||||
|
match super::Error::try_from_errno(-(crate::bindings::$err as i32)) {
|
||||||
|
Some(err) => err,
|
||||||
|
None => panic!("Invalid errno in `declare_err!`"),
|
||||||
|
};
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -88,7 +93,7 @@ pub mod code {
|
|||||||
///
|
///
|
||||||
/// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`).
|
/// The value is a valid `errno` (i.e. `>= -MAX_ERRNO && < 0`).
|
||||||
#[derive(Clone, Copy, PartialEq, Eq)]
|
#[derive(Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct Error(core::ffi::c_int);
|
pub struct Error(NonZeroI32);
|
||||||
|
|
||||||
impl Error {
|
impl Error {
|
||||||
/// Creates an [`Error`] from a kernel error code.
|
/// Creates an [`Error`] from a kernel error code.
|
||||||
@ -107,7 +112,20 @@ impl Error {
|
|||||||
|
|
||||||
// INVARIANT: The check above ensures the type invariant
|
// INVARIANT: The check above ensures the type invariant
|
||||||
// will hold.
|
// will hold.
|
||||||
Error(errno)
|
// SAFETY: `errno` is checked above to be in a valid range.
|
||||||
|
unsafe { Error::from_errno_unchecked(errno) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an [`Error`] from a kernel error code.
|
||||||
|
///
|
||||||
|
/// Returns [`None`] if `errno` is out-of-range.
|
||||||
|
const fn try_from_errno(errno: core::ffi::c_int) -> Option<Error> {
|
||||||
|
if errno < -(bindings::MAX_ERRNO as i32) || errno >= 0 {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
// SAFETY: `errno` is checked above to be in a valid range.
|
||||||
|
Some(unsafe { Error::from_errno_unchecked(errno) })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Creates an [`Error`] from a kernel error code.
|
/// Creates an [`Error`] from a kernel error code.
|
||||||
@ -115,21 +133,22 @@ impl Error {
|
|||||||
/// # Safety
|
/// # Safety
|
||||||
///
|
///
|
||||||
/// `errno` must be within error code range (i.e. `>= -MAX_ERRNO && < 0`).
|
/// `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
|
// INVARIANT: The contract ensures the type invariant
|
||||||
// will hold.
|
// will hold.
|
||||||
Error(errno)
|
// SAFETY: The caller guarantees `errno` is non-zero.
|
||||||
|
Error(unsafe { NonZeroI32::new_unchecked(errno) })
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the kernel error code.
|
/// Returns the kernel error code.
|
||||||
pub fn to_errno(self) -> core::ffi::c_int {
|
pub fn to_errno(self) -> core::ffi::c_int {
|
||||||
self.0
|
self.0.get()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(CONFIG_BLOCK)]
|
#[cfg(CONFIG_BLOCK)]
|
||||||
pub(crate) fn to_blk_status(self) -> bindings::blk_status_t {
|
pub(crate) fn to_blk_status(self) -> bindings::blk_status_t {
|
||||||
// SAFETY: `self.0` is a valid error due to its invariant.
|
// 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.
|
/// Returns the error encoded as a pointer.
|
||||||
@ -137,7 +156,7 @@ impl Error {
|
|||||||
#[cfg_attr(target_pointer_width = "32", allow(clippy::useless_conversion))]
|
#[cfg_attr(target_pointer_width = "32", allow(clippy::useless_conversion))]
|
||||||
// SAFETY: `self.0` is a valid error due to its invariant.
|
// SAFETY: `self.0` is a valid error due to its invariant.
|
||||||
unsafe {
|
unsafe {
|
||||||
bindings::ERR_PTR(self.0.into()) as *mut _
|
bindings::ERR_PTR(self.0.get().into()) as *mut _
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -145,7 +164,7 @@ impl Error {
|
|||||||
#[cfg(not(testlib))]
|
#[cfg(not(testlib))]
|
||||||
pub fn name(&self) -> Option<&'static CStr> {
|
pub fn name(&self) -> Option<&'static CStr> {
|
||||||
// SAFETY: Just an FFI call, there are no extra safety requirements.
|
// 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() {
|
if ptr.is_null() {
|
||||||
None
|
None
|
||||||
} else {
|
} else {
|
||||||
|
Loading…
x
Reference in New Issue
Block a user