summaryrefslogtreecommitdiff
path: root/rust/kernel
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2025-12-03 14:16:49 -0800
committerLinus Torvalds <torvalds@linux-foundation.org>2025-12-03 14:16:49 -0800
commit784faa8eca8270671e0ed6d9d21f04bbb80fc5f7 (patch)
tree6f97b300d759a9cac8a59d57a0611474543ae127 /rust/kernel
parent51ab33fc0a8bef9454849371ef897a1241911b37 (diff)
parent54e3eae855629702c566bd2e130d9f40e7f35bde (diff)
Merge tag 'rust-6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux
Pull Rust updates from Miguel Ojeda: "Toolchain and infrastructure: - Add support for 'syn'. Syn is a parsing library for parsing a stream of Rust tokens into a syntax tree of Rust source code. Currently this library is geared toward use in Rust procedural macros, but contains some APIs that may be useful more generally. 'syn' allows us to greatly simplify writing complex macros such as 'pin-init' (Benno has already prepared the 'syn'-based version). We will use it in the 'macros' crate too. 'syn' is the most downloaded Rust crate (according to crates.io), and it is also used by the Rust compiler itself. While the amount of code is substantial, there should not be many updates needed for these crates, and even if there are, they should not be too big, e.g. +7k -3k lines across the 3 crates in the last year. 'syn' requires two smaller dependencies: 'quote' and 'proc-macro2'. I only modified their code to remove a third dependency ('unicode-ident') and to add the SPDX identifiers. The code can be easily verified to exactly match upstream with the provided scripts. They are all licensed under "Apache-2.0 OR MIT", like the other vendored 'alloc' crate we had for a while. Please see the merge commit with the cover letter for more context. - Allow 'unreachable_pub' and 'clippy::disallowed_names' for doctests. Examples (i.e. doctests) may want to do things like show public items and use names such as 'foo'. Nevertheless, we still try to keep examples as close to real code as possible (this is part of why running Clippy on doctests is important for us, e.g. for safety comments, which userspace Rust does not support yet but we are stricter). 'kernel' crate: - Replace our custom 'CStr' type with 'core::ffi::CStr'. Using the standard library type reduces our custom code footprint, and we retain needed custom functionality through an extension trait and a new 'fmt!' macro which replaces the previous 'core' import. This started in 6.17 and continued in 6.18, and we finally land the replacement now. This required quite some stamina from Tamir, who split the changes in steps to prepare for the flag day change here. - Replace 'kernel::c_str!' with C string literals. C string literals were added in Rust 1.77, which produce '&CStr's (the 'core' one), so now we can write: c"hi" instead of: c_str!("hi") - Add 'num' module for numerical features. It includes the 'Integer' trait, implemented for all primitive integer types. It also includes the 'Bounded' integer wrapping type: an integer value that requires only the 'N' least significant bits of the wrapped type to be encoded: // An unsigned 8-bit integer, of which only the 4 LSBs are used. let v = Bounded::<u8, 4>::new::<15>(); assert_eq!(v.get(), 15); 'Bounded' is useful to e.g. enforce guarantees when working with bitfields that have an arbitrary number of bits. Values can also be constructed from simple non-constant expressions or, for more complex ones, validated at runtime. 'Bounded' also comes with comparison and arithmetic operations (with both their backing type and other 'Bounded's with a compatible backing type), casts to change the backing type, extending/shrinking and infallible/fallible conversions from/to primitives as applicable. - 'rbtree' module: add immutable cursor ('Cursor'). It enables to use just an immutable tree reference where appropriate. The existing fully-featured mutable cursor is renamed to 'CursorMut'. kallsyms: - Fix wrong "big" kernel symbol type read from procfs. 'pin-init' crate: - A couple minor fixes (Benno asked me to pick these patches up for him this cycle). Documentation: - Quick Start guide: add Debian 13 (Trixie). Debian Stable is now able to build Linux, since Debian 13 (released 2025-08-09) packages Rust 1.85.0, which is recent enough. We are planning to propose that the minimum supported Rust version in Linux follows Debian Stable releases, with Debian 13 being the first one we upgrade to, i.e. Rust 1.85. MAINTAINERS: - Add entry for the new 'num' module. - Remove Alex as Rust maintainer: he hasn't had the time to contribute for a few years now, so it is a no-op change in practice. And a few other cleanups and improvements" * tag 'rust-6.19' of git://git.kernel.org/pub/scm/linux/kernel/git/ojeda/linux: (53 commits) rust: macros: support `proc-macro2`, `quote` and `syn` rust: syn: enable support in kbuild rust: syn: add `README.md` rust: syn: remove `unicode-ident` dependency rust: syn: add SPDX License Identifiers rust: syn: import crate rust: quote: enable support in kbuild rust: quote: add `README.md` rust: quote: add SPDX License Identifiers rust: quote: import crate rust: proc-macro2: enable support in kbuild rust: proc-macro2: add `README.md` rust: proc-macro2: remove `unicode_ident` dependency rust: proc-macro2: add SPDX License Identifiers rust: proc-macro2: import crate rust: kbuild: support using libraries in `rustc_procmacro` rust: kbuild: support skipping flags in `rustc_test_library` rust: kbuild: add proc macro library support rust: kbuild: simplify `--cfg` handling rust: kbuild: introduce `core-flags` and `core-skip_flags` ...
Diffstat (limited to 'rust/kernel')
-rw-r--r--rust/kernel/alloc/kvec/errors.rs14
-rw-r--r--rust/kernel/clk.rs4
-rw-r--r--rust/kernel/configfs.rs2
-rw-r--r--rust/kernel/debugfs.rs2
-rw-r--r--rust/kernel/debugfs/callback_adapters.rs7
-rw-r--r--rust/kernel/debugfs/entry.rs2
-rw-r--r--rust/kernel/debugfs/file_ops.rs6
-rw-r--r--rust/kernel/debugfs/traits.rs10
-rw-r--r--rust/kernel/device.rs1
-rw-r--r--rust/kernel/drm/ioctl.rs4
-rw-r--r--rust/kernel/error.rs2
-rw-r--r--rust/kernel/firmware.rs15
-rw-r--r--rust/kernel/fmt.rs87
-rw-r--r--rust/kernel/init.rs3
-rw-r--r--rust/kernel/lib.rs1
-rw-r--r--rust/kernel/num.rs79
-rw-r--r--rust/kernel/num/bounded.rs1058
-rw-r--r--rust/kernel/opp.rs6
-rw-r--r--rust/kernel/pci/id.rs3
-rw-r--r--rust/kernel/prelude.rs7
-rw-r--r--rust/kernel/ptr.rs1
-rw-r--r--rust/kernel/rbtree.rs244
-rw-r--r--rust/kernel/regulator.rs13
-rw-r--r--rust/kernel/seq_file.rs2
-rw-r--r--rust/kernel/str.rs454
-rw-r--r--rust/kernel/sync.rs3
-rw-r--r--rust/kernel/sync/condvar.rs2
-rw-r--r--rust/kernel/sync/lock.rs2
-rw-r--r--rust/kernel/sync/lock/global.rs2
-rw-r--r--rust/kernel/types.rs1
30 files changed, 1600 insertions, 437 deletions
diff --git a/rust/kernel/alloc/kvec/errors.rs b/rust/kernel/alloc/kvec/errors.rs
index 21a920a4b09b..e7de5049ee47 100644
--- a/rust/kernel/alloc/kvec/errors.rs
+++ b/rust/kernel/alloc/kvec/errors.rs
@@ -2,14 +2,14 @@
//! Errors for the [`Vec`] type.
-use kernel::fmt::{self, Debug, Formatter};
+use kernel::fmt;
use kernel::prelude::*;
/// Error type for [`Vec::push_within_capacity`].
pub struct PushError<T>(pub T);
-impl<T> Debug for PushError<T> {
- fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+impl<T> fmt::Debug for PushError<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Not enough capacity")
}
}
@@ -25,8 +25,8 @@ impl<T> From<PushError<T>> for Error {
/// Error type for [`Vec::remove`].
pub struct RemoveError;
-impl Debug for RemoveError {
- fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+impl fmt::Debug for RemoveError {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Index out of bounds")
}
}
@@ -45,8 +45,8 @@ pub enum InsertError<T> {
OutOfCapacity(T),
}
-impl<T> Debug for InsertError<T> {
- fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
+impl<T> fmt::Debug for InsertError<T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
InsertError::IndexOutOfBounds(_) => write!(f, "Index out of bounds"),
InsertError::OutOfCapacity(_) => write!(f, "Not enough capacity"),
diff --git a/rust/kernel/clk.rs b/rust/kernel/clk.rs
index 1e6c8c42fb3a..c1cfaeaa36a2 100644
--- a/rust/kernel/clk.rs
+++ b/rust/kernel/clk.rs
@@ -136,7 +136,7 @@ mod common_clk {
///
/// [`clk_get`]: https://docs.kernel.org/core-api/kernel-api.html#c.clk_get
pub fn get(dev: &Device, name: Option<&CStr>) -> Result<Self> {
- let con_id = name.map_or(ptr::null(), |n| n.as_ptr());
+ let con_id = name.map_or(ptr::null(), |n| n.as_char_ptr());
// SAFETY: It is safe to call [`clk_get`] for a valid device pointer.
//
@@ -304,7 +304,7 @@ mod common_clk {
/// [`clk_get_optional`]:
/// https://docs.kernel.org/core-api/kernel-api.html#c.clk_get_optional
pub fn get(dev: &Device, name: Option<&CStr>) -> Result<Self> {
- let con_id = name.map_or(ptr::null(), |n| n.as_ptr());
+ let con_id = name.map_or(ptr::null(), |n| n.as_char_ptr());
// SAFETY: It is safe to call [`clk_get_optional`] for a valid device pointer.
//
diff --git a/rust/kernel/configfs.rs b/rust/kernel/configfs.rs
index 10f1547ca9f1..466fb7f40762 100644
--- a/rust/kernel/configfs.rs
+++ b/rust/kernel/configfs.rs
@@ -157,7 +157,7 @@ impl<Data> Subsystem<Data> {
unsafe {
bindings::config_group_init_type_name(
&mut (*place.get()).su_group,
- name.as_ptr(),
+ name.as_char_ptr(),
item_type.as_ptr(),
)
};
diff --git a/rust/kernel/debugfs.rs b/rust/kernel/debugfs.rs
index 381c23b3dd83..8c35d032acfe 100644
--- a/rust/kernel/debugfs.rs
+++ b/rust/kernel/debugfs.rs
@@ -8,12 +8,12 @@
// When DebugFS is disabled, many parameters are dead. Linting for this isn't helpful.
#![cfg_attr(not(CONFIG_DEBUG_FS), allow(unused_variables))]
+use crate::fmt;
use crate::prelude::*;
use crate::str::CStr;
#[cfg(CONFIG_DEBUG_FS)]
use crate::sync::Arc;
use crate::uaccess::UserSliceReader;
-use core::fmt;
use core::marker::PhantomData;
use core::marker::PhantomPinned;
#[cfg(CONFIG_DEBUG_FS)]
diff --git a/rust/kernel/debugfs/callback_adapters.rs b/rust/kernel/debugfs/callback_adapters.rs
index 6c024230f676..a260d8dee051 100644
--- a/rust/kernel/debugfs/callback_adapters.rs
+++ b/rust/kernel/debugfs/callback_adapters.rs
@@ -5,10 +5,9 @@
//! than a trait implementation. If provided, it will override the trait implementation.
use super::{Reader, Writer};
+use crate::fmt;
use crate::prelude::*;
use crate::uaccess::UserSliceReader;
-use core::fmt;
-use core::fmt::Formatter;
use core::marker::PhantomData;
use core::ops::Deref;
@@ -76,9 +75,9 @@ impl<D, F> Deref for FormatAdapter<D, F> {
impl<D, F> Writer for FormatAdapter<D, F>
where
- F: Fn(&D, &mut Formatter<'_>) -> fmt::Result + 'static,
+ F: Fn(&D, &mut fmt::Formatter<'_>) -> fmt::Result + 'static,
{
- fn write(&self, fmt: &mut Formatter<'_>) -> fmt::Result {
+ fn write(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
// SAFETY: FormatAdapter<_, F> can only be constructed if F is inhabited
let f: &F = unsafe { materialize_zst() };
f(&self.inner, fmt)
diff --git a/rust/kernel/debugfs/entry.rs b/rust/kernel/debugfs/entry.rs
index f99402cd3ba0..706cb7f73d6c 100644
--- a/rust/kernel/debugfs/entry.rs
+++ b/rust/kernel/debugfs/entry.rs
@@ -3,7 +3,7 @@
use crate::debugfs::file_ops::FileOps;
use crate::ffi::c_void;
-use crate::str::CStr;
+use crate::str::{CStr, CStrExt as _};
use crate::sync::Arc;
use core::marker::PhantomData;
diff --git a/rust/kernel/debugfs/file_ops.rs b/rust/kernel/debugfs/file_ops.rs
index 50fead17b6f3..9ad5e3fa6f69 100644
--- a/rust/kernel/debugfs/file_ops.rs
+++ b/rust/kernel/debugfs/file_ops.rs
@@ -3,11 +3,11 @@
use super::{Reader, Writer};
use crate::debugfs::callback_adapters::Adapter;
+use crate::fmt;
use crate::prelude::*;
use crate::seq_file::SeqFile;
use crate::seq_print;
use crate::uaccess::UserSlice;
-use core::fmt::{Display, Formatter, Result};
use core::marker::PhantomData;
#[cfg(CONFIG_DEBUG_FS)]
@@ -65,8 +65,8 @@ impl<T> Deref for FileOps<T> {
struct WriterAdapter<T>(T);
-impl<'a, T: Writer> Display for WriterAdapter<&'a T> {
- fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+impl<'a, T: Writer> fmt::Display for WriterAdapter<&'a T> {
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.0.write(f)
}
}
diff --git a/rust/kernel/debugfs/traits.rs b/rust/kernel/debugfs/traits.rs
index 92054fed2136..e8a8a98f18dc 100644
--- a/rust/kernel/debugfs/traits.rs
+++ b/rust/kernel/debugfs/traits.rs
@@ -3,11 +3,11 @@
//! Traits for rendering or updating values exported to DebugFS.
+use crate::fmt;
use crate::prelude::*;
use crate::sync::atomic::{Atomic, AtomicBasicOps, AtomicType, Relaxed};
use crate::sync::Mutex;
use crate::uaccess::UserSliceReader;
-use core::fmt::{self, Debug, Formatter};
use core::str::FromStr;
/// A trait for types that can be written into a string.
@@ -21,17 +21,17 @@ use core::str::FromStr;
/// explicitly instead.
pub trait Writer {
/// Formats the value using the given formatter.
- fn write(&self, f: &mut Formatter<'_>) -> fmt::Result;
+ fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result;
}
impl<T: Writer> Writer for Mutex<T> {
- fn write(&self, f: &mut Formatter<'_>) -> fmt::Result {
+ fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
self.lock().write(f)
}
}
-impl<T: Debug> Writer for T {
- fn write(&self, f: &mut Formatter<'_>) -> fmt::Result {
+impl<T: fmt::Debug> Writer for T {
+ fn write(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
writeln!(f, "{self:?}")
}
}
diff --git a/rust/kernel/device.rs b/rust/kernel/device.rs
index a849b7dde2fd..7116dd7539a6 100644
--- a/rust/kernel/device.rs
+++ b/rust/kernel/device.rs
@@ -13,6 +13,7 @@ use core::{marker::PhantomData, ptr};
#[cfg(CONFIG_PRINTK)]
use crate::c_str;
+use crate::str::CStrExt as _;
pub mod property;
diff --git a/rust/kernel/drm/ioctl.rs b/rust/kernel/drm/ioctl.rs
index 69efbdb4c85a..cf328101dde4 100644
--- a/rust/kernel/drm/ioctl.rs
+++ b/rust/kernel/drm/ioctl.rs
@@ -156,7 +156,9 @@ macro_rules! declare_drm_ioctls {
Some($cmd)
},
flags: $flags,
- name: $crate::c_str!(::core::stringify!($cmd)).as_char_ptr(),
+ name: $crate::str::as_char_ptr_in_const_context(
+ $crate::c_str!(::core::stringify!($cmd)),
+ ),
}
),*];
ioctls
diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index 1c0e0e241daa..258b12afdcba 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -182,6 +182,8 @@ impl Error {
if ptr.is_null() {
None
} else {
+ use crate::str::CStrExt as _;
+
// SAFETY: The string returned by `errname` is static and `NUL`-terminated.
Some(unsafe { CStr::from_char_ptr(ptr) })
}
diff --git a/rust/kernel/firmware.rs b/rust/kernel/firmware.rs
index 94e6bb88b903..71168d8004e2 100644
--- a/rust/kernel/firmware.rs
+++ b/rust/kernel/firmware.rs
@@ -4,7 +4,14 @@
//!
//! C header: [`include/linux/firmware.h`](srctree/include/linux/firmware.h)
-use crate::{bindings, device::Device, error::Error, error::Result, ffi, str::CStr};
+use crate::{
+ bindings,
+ device::Device,
+ error::Error,
+ error::Result,
+ ffi,
+ str::{CStr, CStrExt as _},
+};
use core::ptr::NonNull;
/// # Invariants
@@ -44,13 +51,13 @@ impl FwFunc {
/// # Examples
///
/// ```no_run
-/// # use kernel::{c_str, device::Device, firmware::Firmware};
+/// # use kernel::{device::Device, firmware::Firmware};
///
/// # fn no_run() -> Result<(), Error> {
/// # // SAFETY: *NOT* safe, just for the example to get an `ARef<Device>` instance
/// # let dev = unsafe { Device::get_device(core::ptr::null_mut()) };
///
-/// let fw = Firmware::request(c_str!("path/to/firmware.bin"), &dev)?;
+/// let fw = Firmware::request(c"path/to/firmware.bin", &dev)?;
/// let blob = fw.data();
///
/// # Ok(())
@@ -197,7 +204,7 @@ macro_rules! module_firmware {
($($builder:tt)*) => {
const _: () = {
const __MODULE_FIRMWARE_PREFIX: &'static $crate::str::CStr = if cfg!(MODULE) {
- $crate::c_str!("")
+ c""
} else {
<LocalModule as $crate::ModuleMetadata>::NAME
};
diff --git a/rust/kernel/fmt.rs b/rust/kernel/fmt.rs
index 0306e8388968..84d634201d90 100644
--- a/rust/kernel/fmt.rs
+++ b/rust/kernel/fmt.rs
@@ -4,4 +4,89 @@
//!
//! This module is intended to be used in place of `core::fmt` in kernel code.
-pub use core::fmt::{Arguments, Debug, Display, Error, Formatter, Result, Write};
+pub use core::fmt::{Arguments, Debug, Error, Formatter, Result, Write};
+
+/// Internal adapter used to route allow implementations of formatting traits for foreign types.
+///
+/// It is inserted automatically by the [`fmt!`] macro and is not meant to be used directly.
+///
+/// [`fmt!`]: crate::prelude::fmt!
+#[doc(hidden)]
+pub struct Adapter<T>(pub T);
+
+macro_rules! impl_fmt_adapter_forward {
+ ($($trait:ident),* $(,)?) => {
+ $(
+ impl<T: $trait> $trait for Adapter<T> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ let Self(t) = self;
+ $trait::fmt(t, f)
+ }
+ }
+ )*
+ };
+}
+
+use core::fmt::{Binary, LowerExp, LowerHex, Octal, Pointer, UpperExp, UpperHex};
+impl_fmt_adapter_forward!(Debug, LowerHex, UpperHex, Octal, Binary, Pointer, LowerExp, UpperExp);
+
+/// A copy of [`core::fmt::Display`] that allows us to implement it for foreign types.
+///
+/// Types should implement this trait rather than [`core::fmt::Display`]. Together with the
+/// [`Adapter`] type and [`fmt!`] macro, it allows for formatting foreign types (e.g. types from
+/// core) which do not implement [`core::fmt::Display`] directly.
+///
+/// [`fmt!`]: crate::prelude::fmt!
+pub trait Display {
+ /// Same as [`core::fmt::Display::fmt`].
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result;
+}
+
+impl<T: ?Sized + Display> Display for &T {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ Display::fmt(*self, f)
+ }
+}
+
+impl<T: ?Sized + Display> core::fmt::Display for Adapter<&T> {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ let Self(t) = self;
+ Display::fmt(t, f)
+ }
+}
+
+macro_rules! impl_display_forward {
+ ($(
+ $( { $($generics:tt)* } )? $ty:ty $( { where $($where:tt)* } )?
+ ),* $(,)?) => {
+ $(
+ impl$($($generics)*)? Display for $ty $(where $($where)*)? {
+ fn fmt(&self, f: &mut Formatter<'_>) -> Result {
+ core::fmt::Display::fmt(self, f)
+ }
+ }
+ )*
+ };
+}
+
+impl_display_forward!(
+ bool,
+ char,
+ core::panic::PanicInfo<'_>,
+ Arguments<'_>,
+ i128,
+ i16,
+ i32,
+ i64,
+ i8,
+ isize,
+ str,
+ u128,
+ u16,
+ u32,
+ u64,
+ u8,
+ usize,
+ {<T: ?Sized>} crate::sync::Arc<T> {where crate::sync::Arc<T>: core::fmt::Display},
+ {<T: ?Sized>} crate::sync::UniqueArc<T> {where crate::sync::UniqueArc<T>: core::fmt::Display},
+);
diff --git a/rust/kernel/init.rs b/rust/kernel/init.rs
index 4949047af8d7..899b9a962762 100644
--- a/rust/kernel/init.rs
+++ b/rust/kernel/init.rs
@@ -30,7 +30,7 @@
//! ## General Examples
//!
//! ```rust
-//! # #![expect(clippy::disallowed_names, clippy::undocumented_unsafe_blocks)]
+//! # #![expect(clippy::undocumented_unsafe_blocks)]
//! use kernel::types::Opaque;
//! use pin_init::pin_init_from_closure;
//!
@@ -67,7 +67,6 @@
//! ```
//!
//! ```rust
-//! # #![expect(unreachable_pub, clippy::disallowed_names)]
//! use kernel::{prelude::*, types::Opaque};
//! use core::{ptr::addr_of_mut, marker::PhantomPinned, pin::Pin};
//! # mod bindings {
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 3dd7bebe7888..235d0d8b1eff 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -109,6 +109,7 @@ pub mod miscdevice;
pub mod mm;
#[cfg(CONFIG_NET)]
pub mod net;
+pub mod num;
pub mod of;
#[cfg(CONFIG_PM_OPP)]
pub mod opp;
diff --git a/rust/kernel/num.rs b/rust/kernel/num.rs
new file mode 100644
index 000000000000..8532b511384c
--- /dev/null
+++ b/rust/kernel/num.rs
@@ -0,0 +1,79 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Additional numerical features for the kernel.
+
+use core::ops;
+
+pub mod bounded;
+pub use bounded::*;
+
+/// Designates unsigned primitive types.
+pub enum Unsigned {}
+
+/// Designates signed primitive types.
+pub enum Signed {}
+
+/// Describes core properties of integer types.
+pub trait Integer:
+ Sized
+ + Copy
+ + Clone
+ + PartialEq
+ + Eq
+ + PartialOrd
+ + Ord
+ + ops::Add<Output = Self>
+ + ops::AddAssign
+ + ops::Sub<Output = Self>
+ + ops::SubAssign
+ + ops::Mul<Output = Self>
+ + ops::MulAssign
+ + ops::Div<Output = Self>
+ + ops::DivAssign
+ + ops::Rem<Output = Self>
+ + ops::RemAssign
+ + ops::BitAnd<Output = Self>
+ + ops::BitAndAssign
+ + ops::BitOr<Output = Self>
+ + ops::BitOrAssign
+ + ops::BitXor<Output = Self>
+ + ops::BitXorAssign
+ + ops::Shl<u32, Output = Self>
+ + ops::ShlAssign<u32>
+ + ops::Shr<u32, Output = Self>
+ + ops::ShrAssign<u32>
+ + ops::Not
+{
+ /// Whether this type is [`Signed`] or [`Unsigned`].
+ type Signedness;
+
+ /// Number of bits used for value representation.
+ const BITS: u32;
+}
+
+macro_rules! impl_integer {
+ ($($type:ty: $signedness:ty), *) => {
+ $(
+ impl Integer for $type {
+ type Signedness = $signedness;
+
+ const BITS: u32 = <$type>::BITS;
+ }
+ )*
+ };
+}
+
+impl_integer!(
+ u8: Unsigned,
+ u16: Unsigned,
+ u32: Unsigned,
+ u64: Unsigned,
+ u128: Unsigned,
+ usize: Unsigned,
+ i8: Signed,
+ i16: Signed,
+ i32: Signed,
+ i64: Signed,
+ i128: Signed,
+ isize: Signed
+);
diff --git a/rust/kernel/num/bounded.rs b/rust/kernel/num/bounded.rs
new file mode 100644
index 000000000000..f870080af8ac
--- /dev/null
+++ b/rust/kernel/num/bounded.rs
@@ -0,0 +1,1058 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Implementation of [`Bounded`], a wrapper around integer types limiting the number of bits
+//! usable for value representation.
+
+use core::{
+ cmp,
+ fmt,
+ ops::{
+ self,
+ Deref, //
+ }, //,
+};
+
+use kernel::{
+ num::Integer,
+ prelude::*, //
+};
+
+/// Evaluates to `true` if `$value` can be represented using at most `$n` bits in a `$type`.
+///
+/// `expr` must be of type `type`, or the result will be incorrect.
+///
+/// Can be used in const context.
+macro_rules! fits_within {
+ ($value:expr, $type:ty, $n:expr) => {{
+ let shift: u32 = <$type>::BITS - $n;
+
+ // `value` fits within `$n` bits if shifting it left by the number of unused bits, then
+ // right by the same number, doesn't change it.
+ //
+ // This method has the benefit of working for both unsigned and signed values.
+ ($value << shift) >> shift == $value
+ }};
+}
+
+/// Returns `true` if `value` can be represented with at most `N` bits in a `T`.
+#[inline(always)]
+fn fits_within<T: Integer>(value: T, num_bits: u32) -> bool {
+ fits_within!(value, T, num_bits)
+}
+
+/// An integer value that requires only the `N` less significant bits of the wrapped type to be
+/// encoded.
+///
+/// This limits the number of usable bits in the wrapped integer type, and thus the stored value to
+/// a narrower range, which provides guarantees that can be useful when working with in e.g.
+/// bitfields.
+///
+/// # Invariants
+///
+/// - `N` is greater than `0`.
+/// - `N` is less than or equal to `T::BITS`.
+/// - Stored values can be represented with at most `N` bits.
+///
+/// # Examples
+///
+/// The preferred way to create values is through constants and the [`Bounded::new`] family of
+/// constructors, as they trigger a build error if the type invariants cannot be withheld.
+///
+/// ```
+/// use kernel::num::Bounded;
+///
+/// // An unsigned 8-bit integer, of which only the 4 LSBs are used.
+/// // The value `15` is statically validated to fit that constraint at build time.
+/// let v = Bounded::<u8, 4>::new::<15>();
+/// assert_eq!(v.get(), 15);
+///
+/// // Same using signed values.
+/// let v = Bounded::<i8, 4>::new::<-8>();
+/// assert_eq!(v.get(), -8);
+///
+/// // This doesn't build: a `u8` is smaller than the requested 9 bits.
+/// // let _ = Bounded::<u8, 9>::new::<10>();
+///
+/// // This also doesn't build: the requested value doesn't fit within 4 signed bits.
+/// // let _ = Bounded::<i8, 4>::new::<8>();
+/// ```
+///
+/// Values can also be validated at runtime with [`Bounded::try_new`].
+///
+/// ```
+/// use kernel::num::Bounded;
+///
+/// // This succeeds because `15` can be represented with 4 unsigned bits.
+/// assert!(Bounded::<u8, 4>::try_new(15).is_some());
+///
+/// // This fails because `16` cannot be represented with 4 unsigned bits.
+/// assert!(Bounded::<u8, 4>::try_new(16).is_none());
+/// ```
+///
+/// Non-constant expressions can be validated at build-time thanks to compiler optimizations. This
+/// should be used with caution, on simple expressions only.
+///
+/// ```
+/// use kernel::num::Bounded;
+/// # fn some_number() -> u32 { 0xffffffff }
+///
+/// // Here the compiler can infer from the mask that the type invariants are not violated, even
+/// // though the value returned by `some_number` is not statically known.
+/// let v = Bounded::<u32, 4>::from_expr(some_number() & 0xf);
+/// ```
+///
+/// Comparison and arithmetic operations are supported on [`Bounded`]s with a compatible backing
+/// type, regardless of their number of valid bits.
+///
+/// ```
+/// use kernel::num::Bounded;
+///
+/// let v1 = Bounded::<u32, 8>::new::<4>();
+/// let v2 = Bounded::<u32, 4>::new::<15>();
+///
+/// assert!(v1 != v2);
+/// assert!(v1 < v2);
+/// assert_eq!(v1 + v2, 19);
+/// assert_eq!(v2 % v1, 3);
+/// ```
+///
+/// These operations are also supported between a [`Bounded`] and its backing type.
+///
+/// ```
+/// use kernel::num::Bounded;
+///
+/// let v = Bounded::<u8, 4>::new::<15>();
+///
+/// assert!(v == 15);
+/// assert!(v > 12);
+/// assert_eq!(v + 5, 20);
+/// assert_eq!(v / 3, 5);
+/// ```
+///
+/// A change of backing types is possible using [`Bounded::cast`], and the number of valid bits can
+/// be extended or reduced with [`Bounded::extend`] and [`Bounded::try_shrink`].
+///
+/// ```
+/// use kernel::num::Bounded;
+///
+/// let v = Bounded::<u32, 12>::new::<127>();
+///
+/// // Changes backing type from `u32` to `u16`.
+/// let _: Bounded<u16, 12> = v.cast();
+///
+/// // This does not build, as `u8` is smaller than 12 bits.
+/// // let _: Bounded<u8, 12> = v.cast();
+///
+/// // We can safely extend the number of bits...
+/// let _ = v.extend::<15>();
+///
+/// // ... to the limits of the backing type. This doesn't build as a `u32` cannot contain 33 bits.
+/// // let _ = v.extend::<33>();
+///
+/// // Reducing the number of bits is validated at runtime. This works because `127` can be
+/// // represented with 8 bits.
+/// assert!(v.try_shrink::<8>().is_some());
+///
+/// // ... but not with 6, so this fails.
+/// assert!(v.try_shrink::<6>().is_none());
+/// ```
+///
+/// Infallible conversions from a primitive integer to a large-enough [`Bounded`] are supported.
+///
+/// ```
+/// use kernel::num::Bounded;
+///
+/// // This unsigned `Bounded` has 8 bits, so it can represent any `u8`.
+/// let v = Bounded::<u32, 8>::from(128u8);
+/// assert_eq!(v.get(), 128);
+///
+/// // This signed `Bounded` has 8 bits, so it can represent any `i8`.
+/// let v = Bounded::<i32, 8>::from(-128i8);
+/// assert_eq!(v.get(), -128);
+///
+/// // This doesn't build, as this 6-bit `Bounded` does not have enough capacity to represent a
+/// // `u8` (regardless of the passed value).
+/// // let _ = Bounded::<u32, 6>::from(10u8);
+///
+/// // Booleans can be converted into single-bit `Bounded`s.
+///
+/// let v = Bounded::<u64, 1>::from(false);
+/// assert_eq!(v.get(), 0);
+///
+/// let v = Bounded::<u64, 1>::from(true);
+/// assert_eq!(v.get(), 1);
+/// ```
+///
+/// Infallible conversions from a [`Bounded`] to a primitive integer are also supported, and
+/// dependent on the number of bits used for value representation, not on the backing type.
+///
+/// ```
+/// use kernel::num::Bounded;
+///
+/// // Even though its backing type is `u32`, this `Bounded` only uses 6 bits and thus can safely
+/// // be converted to a `u8`.
+/// let v = Bounded::<u32, 6>::new::<63>();
+/// assert_eq!(u8::from(v), 63);
+///
+/// // Same using signed values.
+/// let v = Bounded::<i32, 8>::new::<-128>();
+/// assert_eq!(i8::from(v), -128);
+///
+/// // This however does not build, as 10 bits won't fit into a `u8` (regardless of the actually
+/// // contained value).
+/// let _v = Bounded::<u32, 10>::new::<10>();
+/// // assert_eq!(u8::from(_v), 10);
+///
+/// // Single-bit `Bounded`s can be converted into a boolean.
+/// let v = Bounded::<u8, 1>::new::<1>();
+/// assert_eq!(bool::from(v), true);
+///
+/// let v = Bounded::<u8, 1>::new::<0>();
+/// assert_eq!(bool::from(v), false);
+/// ```
+///
+/// Fallible conversions from any primitive integer to any [`Bounded`] are also supported using the
+/// [`TryIntoBounded`] trait.
+///
+/// ```
+/// use kernel::num::{Bounded, TryIntoBounded};
+///
+/// // Succeeds because `128` fits into 8 bits.
+/// let v: Option<Bounded<u16, 8>> = 128u32.try_into_bounded();
+/// assert_eq!(v.as_deref().copied(), Some(128));
+///
+/// // Fails because `128` doesn't fits into 6 bits.
+/// let v: Option<Bounded<u16, 6>> = 128u32.try_into_bounded();
+/// assert_eq!(v, None);
+/// ```
+#[repr(transparent)]
+#[derive(Clone, Copy, Debug, Default, Hash)]
+pub struct Bounded<T: Integer, const N: u32>(T);
+
+/// Validating the value as a const expression cannot be done as a regular method, as the
+/// arithmetic operations we rely on to check the bounds are not const. Thus, implement
+/// [`Bounded::new`] using a macro.
+macro_rules! impl_const_new {
+ ($($type:ty)*) => {
+ $(
+ impl<const N: u32> Bounded<$type, N> {
+ /// Creates a [`Bounded`] for the constant `VALUE`.
+ ///
+ /// Fails at build time if `VALUE` cannot be represented with `N` bits.
+ ///
+ /// This method should be preferred to [`Self::from_expr`] whenever possible.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use kernel::num::Bounded;
+ ///
+ #[doc = ::core::concat!(
+ "let v = Bounded::<",
+ ::core::stringify!($type),
+ ", 4>::new::<7>();")]
+ /// assert_eq!(v.get(), 7);
+ /// ```
+ pub const fn new<const VALUE: $type>() -> Self {
+ // Statically assert that `VALUE` fits within the set number of bits.
+ const {
+ assert!(fits_within!(VALUE, $type, N));
+ }
+
+ // INVARIANT: `fits_within` confirmed that `VALUE` can be represented within
+ // `N` bits.
+ Self::__new(VALUE)
+ }
+ }
+ )*
+ };
+}
+
+impl_const_new!(
+ u8 u16 u32 u64 usize
+ i8 i16 i32 i64 isize
+);
+
+impl<T, const N: u32> Bounded<T, N>
+where
+ T: Integer,
+{
+ /// Private constructor enforcing the type invariants.
+ ///
+ /// All instances of [`Bounded`] must be created through this method as it enforces most of the
+ /// type invariants.
+ ///
+ /// The caller remains responsible for checking, either statically or dynamically, that `value`
+ /// can be represented as a `T` using at most `N` bits.
+ const fn __new(value: T) -> Self {
+ // Enforce the type invariants.
+ const {
+ // `N` cannot be zero.
+ assert!(N != 0);
+ // The backing type is at least as large as `N` bits.
+ assert!(N <= T::BITS);
+ }
+
+ Self(value)
+ }
+
+ /// Attempts to turn `value` into a `Bounded` using `N` bits.
+ ///
+ /// Returns [`None`] if `value` doesn't fit within `N` bits.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use kernel::num::Bounded;
+ ///
+ /// let v = Bounded::<u8, 1>::try_new(1);
+ /// assert_eq!(v.as_deref().copied(), Some(1));
+ ///
+ /// let v = Bounded::<i8, 4>::try_new(-2);
+ /// assert_eq!(v.as_deref().copied(), Some(-2));
+ ///
+ /// // `0x1ff` doesn't fit into 8 unsigned bits.
+ /// let v = Bounded::<u32, 8>::try_new(0x1ff);
+ /// assert_eq!(v, None);
+ ///
+ /// // The range of values representable with 4 bits is `[-8..=7]`. The following tests these
+ /// // limits.
+ /// let v = Bounded::<i8, 4>::try_new(-8);
+ /// assert_eq!(v.map(Bounded::get), Some(-8));
+ /// let v = Bounded::<i8, 4>::try_new(-9);
+ /// assert_eq!(v, None);
+ /// let v = Bounded::<i8, 4>::try_new(7);
+ /// assert_eq!(v.map(Bounded::get), Some(7));
+ /// let v = Bounded::<i8, 4>::try_new(8);
+ /// assert_eq!(v, None);
+ /// ```
+ pub fn try_new(value: T) -> Option<Self> {
+ fits_within(value, N).then(|| {
+ // INVARIANT: `fits_within` confirmed that `value` can be represented within `N` bits.
+ Self::__new(value)
+ })
+ }
+
+ /// Checks that `expr` is valid for this type at compile-time and build a new value.
+ ///
+ /// This relies on [`build_assert!`] and guaranteed optimization to perform validation at
+ /// compile-time. If `expr` cannot be proved to be within the requested bounds at compile-time,
+ /// use the fallible [`Self::try_new`] instead.
+ ///
+ /// Limit this to simple, easily provable expressions, and prefer one of the [`Self::new`]
+ /// constructors whenever possible as they statically validate the value instead of relying on
+ /// compiler optimizations.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use kernel::num::Bounded;
+ /// # fn some_number() -> u32 { 0xffffffff }
+ ///
+ /// // Some undefined number.
+ /// let v: u32 = some_number();
+ ///
+ /// // Triggers a build error as `v` cannot be asserted to fit within 4 bits...
+ /// // let _ = Bounded::<u32, 4>::from_expr(v);
+ ///
+ /// // ... but this works as the compiler can assert the range from the mask.
+ /// let _ = Bounded::<u32, 4>::from_expr(v & 0xf);
+ ///
+ /// // These expressions are simple enough to be proven correct, but since they are static the
+ /// // `new` constructor should be preferred.
+ /// assert_eq!(Bounded::<u8, 1>::from_expr(1).get(), 1);
+ /// assert_eq!(Bounded::<u16, 8>::from_expr(0xff).get(), 0xff);
+ /// ```
+ #[inline(always)]
+ pub fn from_expr(expr: T) -> Self {
+ crate::build_assert!(
+ fits_within(expr, N),
+ "Requested value larger than maximal representable value."
+ );
+
+ // INVARIANT: `fits_within` confirmed that `expr` can be represented within `N` bits.
+ Self::__new(expr)
+ }
+
+ /// Returns the wrapped value as the backing type.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use kernel::num::Bounded;
+ ///
+ /// let v = Bounded::<u32, 4>::new::<7>();
+ /// assert_eq!(v.get(), 7u32);
+ /// ```
+ pub fn get(self) -> T {
+ *self.deref()
+ }
+
+ /// Increases the number of bits usable for `self`.
+ ///
+ /// This operation cannot fail.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use kernel::num::Bounded;
+ ///
+ /// let v = Bounded::<u32, 4>::new::<7>();
+ /// let larger_v = v.extend::<12>();
+ /// // The contained values are equal even though `larger_v` has a bigger capacity.
+ /// assert_eq!(larger_v, v);
+ /// ```
+ pub const fn extend<const M: u32>(self) -> Bounded<T, M> {
+ const {
+ assert!(
+ M >= N,
+ "Requested number of bits is less than the current representation."
+ );
+ }
+
+ // INVARIANT: The value did fit within `N` bits, so it will all the more fit within
+ // the larger `M` bits.
+ Bounded::__new(self.0)
+ }
+
+ /// Attempts to shrink the number of bits usable for `self`.
+ ///
+ /// Returns [`None`] if the value of `self` cannot be represented within `M` bits.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use kernel::num::Bounded;
+ ///
+ /// let v = Bounded::<u32, 12>::new::<7>();
+ ///
+ /// // `7` can be represented using 3 unsigned bits...
+ /// let smaller_v = v.try_shrink::<3>();
+ /// assert_eq!(smaller_v.as_deref().copied(), Some(7));
+ ///
+ /// // ... but doesn't fit within `2` bits.
+ /// assert_eq!(v.try_shrink::<2>(), None);
+ /// ```
+ pub fn try_shrink<const M: u32>(self) -> Option<Bounded<T, M>> {
+ Bounded::<T, M>::try_new(self.get())
+ }
+
+ /// Casts `self` into a [`Bounded`] backed by a different storage type, but using the same
+ /// number of valid bits.
+ ///
+ /// Both `T` and `U` must be of same signedness, and `U` must be at least as large as
+ /// `N` bits, or a build error will occur.
+ ///
+ /// # Examples
+ ///
+ /// ```
+ /// use kernel::num::Bounded;
+ ///
+ /// let v = Bounded::<u32, 12>::new::<127>();
+ ///
+ /// let u16_v: Bounded<u16, 12> = v.cast();
+ /// assert_eq!(u16_v.get(), 127);
+ ///
+ /// // This won't build: a `u8` is smaller than the required 12 bits.
+ /// // let _: Bounded<u8, 12> = v.cast();
+ /// ```
+ pub fn cast<U>(self) -> Bounded<U, N>
+ where
+ U: TryFrom<T> + Integer,
+ T: Integer,
+ U: Integer<Signedness = T::Signedness>,
+ {
+ // SAFETY: The converted value is represented using `N` bits, `U` can contain `N` bits, and
+ // `U` and `T` have the same sign, hence this conversion cannot fail.
+ let value = unsafe { U::try_from(self.get()).unwrap_unchecked() };
+
+ // INVARIANT: Although the backing type has changed, the value is still represented within
+ // `N` bits, and with the same signedness.
+ Bounded::__new(value)
+ }
+}
+
+impl<T, const N: u32> Deref for Bounded<T, N>
+where
+ T: Integer,
+{
+ type Target = T;
+
+ fn deref(&self) -> &Self::Target {
+ // Enforce the invariant to inform the compiler of the bounds of the value.
+ if !fits_within(self.0, N) {
+ // SAFETY: Per the `Bounded` invariants, `fits_within` can never return `false` on the
+ // value of a valid instance.
+ unsafe { core::hint::unreachable_unchecked() }
+ }
+
+ &self.0
+ }
+}
+
+/// Trait similar to [`TryInto`] but for [`Bounded`], to avoid conflicting implementations.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::num::{Bounded, TryIntoBounded};
+///
+/// // Succeeds because `128` fits into 8 bits.
+/// let v: Option<Bounded<u16, 8>> = 128u32.try_into_bounded();
+/// assert_eq!(v.as_deref().copied(), Some(128));
+///
+/// // Fails because `128` doesn't fits into 6 bits.
+/// let v: Option<Bounded<u16, 6>> = 128u32.try_into_bounded();
+/// assert_eq!(v, None);
+/// ```
+pub trait TryIntoBounded<T: Integer, const N: u32> {
+ /// Attempts to convert `self` into a [`Bounded`] using `N` bits.
+ ///
+ /// Returns [`None`] if `self` does not fit into the target type.
+ fn try_into_bounded(self) -> Option<Bounded<T, N>>;
+}
+
+/// Any integer value can be attempted to be converted into a [`Bounded`] of any size.
+impl<T, U, const N: u32> TryIntoBounded<T, N> for U
+where
+ T: Integer,
+ U: TryInto<T>,
+{
+ fn try_into_bounded(self) -> Option<Bounded<T, N>> {
+ self.try_into().ok().and_then(Bounded::try_new)
+ }
+}
+
+// Comparisons between `Bounded`s.
+
+impl<T, U, const N: u32, const M: u32> PartialEq<Bounded<U, M>> for Bounded<T, N>
+where
+ T: Integer,
+ U: Integer,
+ T: PartialEq<U>,
+{
+ fn eq(&self, other: &Bounded<U, M>) -> bool {
+ self.get() == other.get()
+ }
+}
+
+impl<T, const N: u32> Eq for Bounded<T, N> where T: Integer {}
+
+impl<T, U, const N: u32, const M: u32> PartialOrd<Bounded<U, M>> for Bounded<T, N>
+where
+ T: Integer,
+ U: Integer,
+ T: PartialOrd<U>,
+{
+ fn partial_cmp(&self, other: &Bounded<U, M>) -> Option<cmp::Ordering> {
+ self.get().partial_cmp(&other.get())
+ }
+}
+
+impl<T, const N: u32> Ord for Bounded<T, N>
+where
+ T: Integer,
+ T: Ord,
+{
+ fn cmp(&self, other: &Self) -> cmp::Ordering {
+ self.get().cmp(&other.get())
+ }
+}
+
+// Comparisons between a `Bounded` and its backing type.
+
+impl<T, const N: u32> PartialEq<T> for Bounded<T, N>
+where
+ T: Integer,
+ T: PartialEq,
+{
+ fn eq(&self, other: &T) -> bool {
+ self.get() == *other
+ }
+}
+
+impl<T, const N: u32> PartialOrd<T> for Bounded<T, N>
+where
+ T: Integer,
+ T: PartialOrd,
+{
+ fn partial_cmp(&self, other: &T) -> Option<cmp::Ordering> {
+ self.get().partial_cmp(other)
+ }
+}
+
+// Implementations of `core::ops` for two `Bounded` with the same backing type.
+
+impl<T, const N: u32, const M: u32> ops::Add<Bounded<T, M>> for Bounded<T, N>
+where
+ T: Integer,
+ T: ops::Add<Output = T>,
+{
+ type Output = T;
+
+ fn add(self, rhs: Bounded<T, M>) -> Self::Output {
+ self.get() + rhs.get()
+ }
+}
+
+impl<T, const N: u32, const M: u32> ops::BitAnd<Bounded<T, M>> for Bounded<T, N>
+where
+ T: Integer,
+ T: ops::BitAnd<Output = T>,
+{
+ type Output = T;
+
+ fn bitand(self, rhs: Bounded<T, M>) -> Self::Output {
+ self.get() & rhs.get()
+ }
+}
+
+impl<T, const N: u32, const M: u32> ops::BitOr<Bounded<T, M>> for Bounded<T, N>
+where
+ T: Integer,
+ T: ops::BitOr<Output = T>,
+{
+ type Output = T;
+
+ fn bitor(self, rhs: Bounded<T, M>) -> Self::Output {
+ self.get() | rhs.get()
+ }
+}
+
+impl<T, const N: u32, const M: u32> ops::BitXor<Bounded<T, M>> for Bounded<T, N>
+where
+ T: Integer,
+ T: ops::BitXor<Output = T>,
+{
+ type Output = T;
+
+ fn bitxor(self, rhs: Bounded<T, M>) -> Self::Output {
+ self.get() ^ rhs.get()
+ }
+}
+
+impl<T, const N: u32, const M: u32> ops::Div<Bounded<T, M>> for Bounded<T, N>
+where
+ T: Integer,
+ T: ops::Div<Output = T>,
+{
+ type Output = T;
+
+ fn div(self, rhs: Bounded<T, M>) -> Self::Output {
+ self.get() / rhs.get()
+ }
+}
+
+impl<T, const N: u32, const M: u32> ops::Mul<Bounded<T, M>> for Bounded<T, N>
+where
+ T: Integer,
+ T: ops::Mul<Output = T>,
+{
+ type Output = T;
+
+ fn mul(self, rhs: Bounded<T, M>) -> Self::Output {
+ self.get() * rhs.get()
+ }
+}
+
+impl<T, const N: u32, const M: u32> ops::Rem<Bounded<T, M>> for Bounded<T, N>
+where
+ T: Integer,
+ T: ops::Rem<Output = T>,
+{
+ type Output = T;
+
+ fn rem(self, rhs: Bounded<T, M>) -> Self::Output {
+ self.get() % rhs.get()
+ }
+}
+
+impl<T, const N: u32, const M: u32> ops::Sub<Bounded<T, M>> for Bounded<T, N>
+where
+ T: Integer,
+ T: ops::Sub<Output = T>,
+{
+ type Output = T;
+
+ fn sub(self, rhs: Bounded<T, M>) -> Self::Output {
+ self.get() - rhs.get()
+ }
+}
+
+// Implementations of `core::ops` between a `Bounded` and its backing type.
+
+impl<T, const N: u32> ops::Add<T> for Bounded<T, N>
+where
+ T: Integer,
+ T: ops::Add<Output = T>,
+{
+ type Output = T;
+
+ fn add(self, rhs: T) -> Self::Output {
+ self.get() + rhs
+ }
+}
+
+impl<T, const N: u32> ops::BitAnd<T> for Bounded<T, N>
+where
+ T: Integer,
+ T: ops::BitAnd<Output = T>,
+{
+ type Output = T;
+
+ fn bitand(self, rhs: T) -> Self::Output {
+ self.get() & rhs
+ }
+}
+
+impl<T, const N: u32> ops::BitOr<T> for Bounded<T, N>
+where
+ T: Integer,
+ T: ops::BitOr<Output = T>,
+{
+ type Output = T;
+
+ fn bitor(self, rhs: T) -> Self::Output {
+ self.get() | rhs
+ }
+}
+
+impl<T, const N: u32> ops::BitXor<T> for Bounded<T, N>
+where
+ T: Integer,
+ T: ops::BitXor<Output = T>,
+{
+ type Output = T;
+
+ fn bitxor(self, rhs: T) -> Self::Output {
+ self.get() ^ rhs
+ }
+}
+
+impl<T, const N: u32> ops::Div<T> for Bounded<T, N>
+where
+ T: Integer,
+ T: ops::Div<Output = T>,
+{
+ type Output = T;
+
+ fn div(self, rhs: T) -> Self::Output {
+ self.get() / rhs
+ }
+}
+
+impl<T, const N: u32> ops::Mul<T> for Bounded<T, N>
+where
+ T: Integer,
+ T: ops::Mul<Output = T>,
+{
+ type Output = T;
+
+ fn mul(self, rhs: T) -> Self::Output {
+ self.get() * rhs
+ }
+}
+
+impl<T, const N: u32> ops::Neg for Bounded<T, N>
+where
+ T: Integer,
+ T: ops::Neg<Output = T>,
+{
+ type Output = T;
+
+ fn neg(self) -> Self::Output {
+ -self.get()
+ }
+}
+
+impl<T, const N: u32> ops::Not for Bounded<T, N>
+where
+ T: Integer,
+ T: ops::Not<Output = T>,
+{
+ type Output = T;
+
+ fn not(self) -> Self::Output {
+ !self.get()
+ }
+}
+
+impl<T, const N: u32> ops::Rem<T> for Bounded<T, N>
+where
+ T: Integer,
+ T: ops::Rem<Output = T>,
+{
+ type Output = T;
+
+ fn rem(self, rhs: T) -> Self::Output {
+ self.get() % rhs
+ }
+}
+
+impl<T, const N: u32> ops::Sub<T> for Bounded<T, N>
+where
+ T: Integer,
+ T: ops::Sub<Output = T>,
+{
+ type Output = T;
+
+ fn sub(self, rhs: T) -> Self::Output {
+ self.get() - rhs
+ }
+}
+
+// Proxy implementations of `core::fmt`.
+
+impl<T, const N: u32> fmt::Display for Bounded<T, N>
+where
+ T: Integer,
+ T: fmt::Display,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.get().fmt(f)
+ }
+}
+
+impl<T, const N: u32> fmt::Binary for Bounded<T, N>
+where
+ T: Integer,
+ T: fmt::Binary,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.get().fmt(f)
+ }
+}
+
+impl<T, const N: u32> fmt::LowerExp for Bounded<T, N>
+where
+ T: Integer,
+ T: fmt::LowerExp,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.get().fmt(f)
+ }
+}
+
+impl<T, const N: u32> fmt::LowerHex for Bounded<T, N>
+where
+ T: Integer,
+ T: fmt::LowerHex,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.get().fmt(f)
+ }
+}
+
+impl<T, const N: u32> fmt::Octal for Bounded<T, N>
+where
+ T: Integer,
+ T: fmt::Octal,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.get().fmt(f)
+ }
+}
+
+impl<T, const N: u32> fmt::UpperExp for Bounded<T, N>
+where
+ T: Integer,
+ T: fmt::UpperExp,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.get().fmt(f)
+ }
+}
+
+impl<T, const N: u32> fmt::UpperHex for Bounded<T, N>
+where
+ T: Integer,
+ T: fmt::UpperHex,
+{
+ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+ self.get().fmt(f)
+ }
+}
+
+/// Implements `$trait` for all [`Bounded`] types represented using `$num_bits`.
+///
+/// This is used to declare size properties as traits that we can constrain against in impl blocks.
+macro_rules! impl_size_rule {
+ ($trait:ty, $($num_bits:literal)*) => {
+ $(
+ impl<T> $trait for Bounded<T, $num_bits> where T: Integer {}
+ )*
+ };
+}
+
+/// Local trait expressing the fact that a given [`Bounded`] has at least `N` bits used for value
+/// representation.
+trait AtLeastXBits<const N: usize> {}
+
+/// Implementations for infallibly converting a primitive type into a [`Bounded`] that can contain
+/// it.
+///
+/// Put into their own module for readability, and to avoid cluttering the rustdoc of the parent
+/// module.
+mod atleast_impls {
+ use super::*;
+
+ // Number of bits at least as large as 64.
+ impl_size_rule!(AtLeastXBits<64>, 64);
+
+ // Anything 64 bits or more is also larger than 32.
+ impl<T> AtLeastXBits<32> for T where T: AtLeastXBits<64> {}
+ // Other numbers of bits at least as large as 32.
+ impl_size_rule!(AtLeastXBits<32>,
+ 32 33 34 35 36 37 38 39
+ 40 41 42 43 44 45 46 47
+ 48 49 50 51 52 53 54 55
+ 56 57 58 59 60 61 62 63
+ );
+
+ // Anything 32 bits or more is also larger than 16.
+ impl<T> AtLeastXBits<16> for T where T: AtLeastXBits<32> {}
+ // Other numbers of bits at least as large as 16.
+ impl_size_rule!(AtLeastXBits<16>,
+ 16 17 18 19 20 21 22 23
+ 24 25 26 27 28 29 30 31
+ );
+
+ // Anything 16 bits or more is also larger than 8.
+ impl<T> AtLeastXBits<8> for T where T: AtLeastXBits<16> {}
+ // Other numbers of bits at least as large as 8.
+ impl_size_rule!(AtLeastXBits<8>, 8 9 10 11 12 13 14 15);
+}
+
+/// Generates `From` implementations from a primitive type into a [`Bounded`] with
+/// enough bits to store any value of that type.
+///
+/// Note: The only reason for having this macro is that if we pass `$type` as a generic
+/// parameter, we cannot use it in the const context of [`AtLeastXBits`]'s generic parameter. This
+/// can be fixed once the `generic_const_exprs` feature is usable, and this macro replaced by a
+/// regular `impl` block.
+macro_rules! impl_from_primitive {
+ ($($type:ty)*) => {
+ $(
+ #[doc = ::core::concat!(
+ "Conversion from a [`",
+ ::core::stringify!($type),
+ "`] into a [`Bounded`] of same signedness with enough bits to store it.")]
+ impl<T, const N: u32> From<$type> for Bounded<T, N>
+ where
+ $type: Integer,
+ T: Integer<Signedness = <$type as Integer>::Signedness> + From<$type>,
+ Self: AtLeastXBits<{ <$type as Integer>::BITS as usize }>,
+ {
+ fn from(value: $type) -> Self {
+ // INVARIANT: The trait bound on `Self` guarantees that `N` bits is
+ // enough to hold any value of the source type.
+ Self::__new(T::from(value))
+ }
+ }
+ )*
+ }
+}
+
+impl_from_primitive!(
+ u8 u16 u32 u64 usize
+ i8 i16 i32 i64 isize
+);
+
+/// Local trait expressing the fact that a given [`Bounded`] fits into a primitive type of `N` bits,
+/// provided they have the same signedness.
+trait FitsInXBits<const N: usize> {}
+
+/// Implementations for infallibly converting a [`Bounded`] into a primitive type that can contain
+/// it.
+///
+/// Put into their own module for readability, and to avoid cluttering the rustdoc of the parent
+/// module.
+mod fits_impls {
+ use super::*;
+
+ // Number of bits that fit into a 8-bits primitive.
+ impl_size_rule!(FitsInXBits<8>, 1 2 3 4 5 6 7 8);
+
+ // Anything that fits into 8 bits also fits into 16.
+ impl<T> FitsInXBits<16> for T where T: FitsInXBits<8> {}
+ // Other number of bits that fit into a 16-bits primitive.
+ impl_size_rule!(FitsInXBits<16>, 9 10 11 12 13 14 15 16);
+
+ // Anything that fits into 16 bits also fits into 32.
+ impl<T> FitsInXBits<32> for T where T: FitsInXBits<16> {}
+ // Other number of bits that fit into a 32-bits primitive.
+ impl_size_rule!(FitsInXBits<32>,
+ 17 18 19 20 21 22 23 24
+ 25 26 27 28 29 30 31 32
+ );
+
+ // Anything that fits into 32 bits also fits into 64.
+ impl<T> FitsInXBits<64> for T where T: FitsInXBits<32> {}
+ // Other number of bits that fit into a 64-bits primitive.
+ impl_size_rule!(FitsInXBits<64>,
+ 33 34 35 36 37 38 39 40
+ 41 42 43 44 45 46 47 48
+ 49 50 51 52 53 54 55 56
+ 57 58 59 60 61 62 63 64
+ );
+}
+
+/// Generates [`From`] implementations from a [`Bounded`] into a primitive type that is
+/// guaranteed to contain it.
+///
+/// Note: The only reason for having this macro is that if we pass `$type` as a generic
+/// parameter, we cannot use it in the const context of `AtLeastXBits`'s generic parameter. This
+/// can be fixed once the `generic_const_exprs` feature is usable, and this macro replaced by a
+/// regular `impl` block.
+macro_rules! impl_into_primitive {
+ ($($type:ty)*) => {
+ $(
+ #[doc = ::core::concat!(
+ "Conversion from a [`Bounded`] with no more bits than a [`",
+ ::core::stringify!($type),
+ "`] and of same signedness into [`",
+ ::core::stringify!($type),
+ "`]")]
+ impl<T, const N: u32> From<Bounded<T, N>> for $type
+ where
+ $type: Integer + TryFrom<T>,
+ T: Integer<Signedness = <$type as Integer>::Signedness>,
+ Bounded<T, N>: FitsInXBits<{ <$type as Integer>::BITS as usize }>,
+ {
+ fn from(value: Bounded<T, N>) -> $type {
+ // SAFETY: The trait bound on `Bounded` ensures that any value it holds (which
+ // is constrained to `N` bits) can fit into the destination type, so this
+ // conversion cannot fail.
+ unsafe { <$type>::try_from(value.get()).unwrap_unchecked() }
+ }
+ }
+ )*
+ }
+}
+
+impl_into_primitive!(
+ u8 u16 u32 u64 usize
+ i8 i16 i32 i64 isize
+);
+
+// Single-bit `Bounded`s can be converted from/to a boolean.
+
+impl<T> From<Bounded<T, 1>> for bool
+where
+ T: Integer + Zeroable,
+{
+ fn from(value: Bounded<T, 1>) -> Self {
+ value.get() != Zeroable::zeroed()
+ }
+}
+
+impl<T, const N: u32> From<bool> for Bounded<T, N>
+where
+ T: Integer + From<bool>,
+{
+ fn from(value: bool) -> Self {
+ // INVARIANT: A boolean can be represented using a single bit, and thus fits within any
+ // integer type for any `N` > 0.
+ Self::__new(T::from(value))
+ }
+}
diff --git a/rust/kernel/opp.rs b/rust/kernel/opp.rs
index f9641c639fff..a760fac28765 100644
--- a/rust/kernel/opp.rs
+++ b/rust/kernel/opp.rs
@@ -13,7 +13,7 @@ use crate::{
cpumask::{Cpumask, CpumaskVar},
device::Device,
error::{code::*, from_err_ptr, from_result, to_result, Result, VTABLE_DEFAULT_ERROR},
- ffi::c_ulong,
+ ffi::{c_char, c_ulong},
prelude::*,
str::CString,
sync::aref::{ARef, AlwaysRefCounted},
@@ -88,12 +88,12 @@ use core::{marker::PhantomData, ptr};
use macros::vtable;
/// Creates a null-terminated slice of pointers to [`CString`]s.
-fn to_c_str_array(names: &[CString]) -> Result<KVec<*const u8>> {
+fn to_c_str_array(names: &[CString]) -> Result<KVec<*const c_char>> {
// Allocated a null-terminated vector of pointers.
let mut list = KVec::with_capacity(names.len() + 1, GFP_KERNEL)?;
for name in names.iter() {
- list.push(name.as_ptr().cast(), GFP_KERNEL)?;
+ list.push(name.as_char_ptr(), GFP_KERNEL)?;
}
list.push(ptr::null(), GFP_KERNEL)?;
diff --git a/rust/kernel/pci/id.rs b/rust/kernel/pci/id.rs
index 7f2a7f57507f..5f5d59ff49fc 100644
--- a/rust/kernel/pci/id.rs
+++ b/rust/kernel/pci/id.rs
@@ -4,8 +4,7 @@
//!
//! This module contains PCI class codes, Vendor IDs, and supporting types.
-use crate::{bindings, error::code::EINVAL, error::Error, prelude::*};
-use core::fmt;
+use crate::{bindings, error::code::EINVAL, error::Error, fmt, prelude::*};
/// PCI device class codes.
///
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index 198d09a31449..33fa8404c5c6 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -19,13 +19,13 @@ pub use core::{
pub use ::ffi::{
c_char, c_int, c_long, c_longlong, c_schar, c_short, c_uchar, c_uint, c_ulong, c_ulonglong,
- c_ushort, c_void,
+ c_ushort, c_void, CStr,
};
pub use crate::alloc::{flags::*, Box, KBox, KVBox, KVVec, KVec, VBox, VVec, Vec};
#[doc(no_inline)]
-pub use macros::{export, kunit_tests, module, vtable};
+pub use macros::{export, fmt, kunit_tests, module, vtable};
pub use pin_init::{init, pin_data, pin_init, pinned_drop, InPlaceWrite, Init, PinInit, Zeroable};
@@ -36,7 +36,6 @@ pub use super::{build_assert, build_error};
pub use super::dbg;
pub use super::{dev_alert, dev_crit, dev_dbg, dev_emerg, dev_err, dev_info, dev_notice, dev_warn};
pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};
-pub use core::format_args as fmt;
pub use super::{try_init, try_pin_init};
@@ -44,7 +43,7 @@ pub use super::static_assert;
pub use super::error::{code::*, Error, Result};
-pub use super::{str::CStr, ThisModule};
+pub use super::{str::CStrExt as _, ThisModule};
pub use super::init::InPlaceInit;
diff --git a/rust/kernel/ptr.rs b/rust/kernel/ptr.rs
index 2e5e2a090480..e3893ed04049 100644
--- a/rust/kernel/ptr.rs
+++ b/rust/kernel/ptr.rs
@@ -2,7 +2,6 @@
//! Types and functions to work with pointers and addresses.
-use core::fmt::Debug;
use core::mem::align_of;
use core::num::NonZero;
diff --git a/rust/kernel/rbtree.rs b/rust/kernel/rbtree.rs
index b8fe6be6fcc4..4729eb56827a 100644
--- a/rust/kernel/rbtree.rs
+++ b/rust/kernel/rbtree.rs
@@ -243,34 +243,64 @@ impl<K, V> RBTree<K, V> {
}
/// Returns a cursor over the tree nodes, starting with the smallest key.
- pub fn cursor_front(&mut self) -> Option<Cursor<'_, K, V>> {
+ pub fn cursor_front_mut(&mut self) -> Option<CursorMut<'_, K, V>> {
let root = addr_of_mut!(self.root);
- // SAFETY: `self.root` is always a valid root node
+ // SAFETY: `self.root` is always a valid root node.
let current = unsafe { bindings::rb_first(root) };
NonNull::new(current).map(|current| {
// INVARIANT:
// - `current` is a valid node in the [`RBTree`] pointed to by `self`.
- Cursor {
+ CursorMut {
current,
tree: self,
}
})
}
+ /// Returns an immutable cursor over the tree nodes, starting with the smallest key.
+ pub fn cursor_front(&self) -> Option<Cursor<'_, K, V>> {
+ let root = &raw const self.root;
+ // SAFETY: `self.root` is always a valid root node.
+ let current = unsafe { bindings::rb_first(root) };
+ NonNull::new(current).map(|current| {
+ // INVARIANT:
+ // - `current` is a valid node in the [`RBTree`] pointed to by `self`.
+ Cursor {
+ current,
+ _tree: PhantomData,
+ }
+ })
+ }
+
/// Returns a cursor over the tree nodes, starting with the largest key.
- pub fn cursor_back(&mut self) -> Option<Cursor<'_, K, V>> {
+ pub fn cursor_back_mut(&mut self) -> Option<CursorMut<'_, K, V>> {
let root = addr_of_mut!(self.root);
- // SAFETY: `self.root` is always a valid root node
+ // SAFETY: `self.root` is always a valid root node.
let current = unsafe { bindings::rb_last(root) };
NonNull::new(current).map(|current| {
// INVARIANT:
// - `current` is a valid node in the [`RBTree`] pointed to by `self`.
- Cursor {
+ CursorMut {
current,
tree: self,
}
})
}
+
+ /// Returns a cursor over the tree nodes, starting with the largest key.
+ pub fn cursor_back(&self) -> Option<Cursor<'_, K, V>> {
+ let root = &raw const self.root;
+ // SAFETY: `self.root` is always a valid root node.
+ let current = unsafe { bindings::rb_last(root) };
+ NonNull::new(current).map(|current| {
+ // INVARIANT:
+ // - `current` is a valid node in the [`RBTree`] pointed to by `self`.
+ Cursor {
+ current,
+ _tree: PhantomData,
+ }
+ })
+ }
}
impl<K, V> RBTree<K, V>
@@ -421,12 +451,47 @@ where
/// If the given key exists, the cursor starts there.
/// Otherwise it starts with the first larger key in sort order.
/// If there is no larger key, it returns [`None`].
- pub fn cursor_lower_bound(&mut self, key: &K) -> Option<Cursor<'_, K, V>>
+ pub fn cursor_lower_bound_mut(&mut self, key: &K) -> Option<CursorMut<'_, K, V>>
+ where
+ K: Ord,
+ {
+ let best = self.find_best_match(key)?;
+
+ NonNull::new(best.as_ptr()).map(|current| {
+ // INVARIANT:
+ // - `current` is a valid node in the [`RBTree`] pointed to by `self`.
+ CursorMut {
+ current,
+ tree: self,
+ }
+ })
+ }
+
+ /// Returns a cursor over the tree nodes based on the given key.
+ ///
+ /// If the given key exists, the cursor starts there.
+ /// Otherwise it starts with the first larger key in sort order.
+ /// If there is no larger key, it returns [`None`].
+ pub fn cursor_lower_bound(&self, key: &K) -> Option<Cursor<'_, K, V>>
where
K: Ord,
{
+ let best = self.find_best_match(key)?;
+
+ NonNull::new(best.as_ptr()).map(|current| {
+ // INVARIANT:
+ // - `current` is a valid node in the [`RBTree`] pointed to by `self`.
+ Cursor {
+ current,
+ _tree: PhantomData,
+ }
+ })
+ }
+
+ fn find_best_match(&self, key: &K) -> Option<NonNull<bindings::rb_node>> {
let mut node = self.root.rb_node;
- let mut best_match: Option<NonNull<Node<K, V>>> = None;
+ let mut best_key: Option<&K> = None;
+ let mut best_links: Option<NonNull<bindings::rb_node>> = None;
while !node.is_null() {
// SAFETY: By the type invariant of `Self`, all non-null `rb_node` pointers stored in `self`
// point to the links field of `Node<K, V>` objects.
@@ -439,42 +504,28 @@ where
let right_child = unsafe { (*node).rb_right };
match key.cmp(this_key) {
Ordering::Equal => {
- best_match = NonNull::new(this);
+ // SAFETY: `this` is a non-null node so it is valid by the type invariants.
+ best_links = Some(unsafe { NonNull::new_unchecked(&mut (*this).links) });
break;
}
Ordering::Greater => {
node = right_child;
}
Ordering::Less => {
- let is_better_match = match best_match {
+ let is_better_match = match best_key {
None => true,
- Some(best) => {
- // SAFETY: `best` is a non-null node so it is valid by the type invariants.
- let best_key = unsafe { &(*best.as_ptr()).key };
- best_key > this_key
- }
+ Some(best) => best > this_key,
};
if is_better_match {
- best_match = NonNull::new(this);
+ best_key = Some(this_key);
+ // SAFETY: `this` is a non-null node so it is valid by the type invariants.
+ best_links = Some(unsafe { NonNull::new_unchecked(&mut (*this).links) });
}
node = left_child;
}
};
}
-
- let best = best_match?;
-
- // SAFETY: `best` is a non-null node so it is valid by the type invariants.
- let links = unsafe { addr_of_mut!((*best.as_ptr()).links) };
-
- NonNull::new(links).map(|current| {
- // INVARIANT:
- // - `current` is a valid node in the [`RBTree`] pointed to by `self`.
- Cursor {
- current,
- tree: self,
- }
- })
+ best_links
}
}
@@ -507,7 +558,7 @@ impl<K, V> Drop for RBTree<K, V> {
}
}
-/// A bidirectional cursor over the tree nodes, sorted by key.
+/// A bidirectional mutable cursor over the tree nodes, sorted by key.
///
/// # Examples
///
@@ -526,7 +577,7 @@ impl<K, V> Drop for RBTree<K, V> {
/// tree.try_create_and_insert(30, 300, flags::GFP_KERNEL)?;
///
/// // Get a cursor to the first element.
-/// let mut cursor = tree.cursor_front().unwrap();
+/// let mut cursor = tree.cursor_front_mut().unwrap();
/// let mut current = cursor.current();
/// assert_eq!(current, (&10, &100));
///
@@ -564,7 +615,7 @@ impl<K, V> Drop for RBTree<K, V> {
/// tree.try_create_and_insert(20, 200, flags::GFP_KERNEL)?;
/// tree.try_create_and_insert(30, 300, flags::GFP_KERNEL)?;
///
-/// let mut cursor = tree.cursor_back().unwrap();
+/// let mut cursor = tree.cursor_back_mut().unwrap();
/// let current = cursor.current();
/// assert_eq!(current, (&30, &300));
///
@@ -577,7 +628,7 @@ impl<K, V> Drop for RBTree<K, V> {
/// use kernel::rbtree::RBTree;
///
/// let mut tree: RBTree<u16, u16> = RBTree::new();
-/// assert!(tree.cursor_front().is_none());
+/// assert!(tree.cursor_front_mut().is_none());
///
/// # Ok::<(), Error>(())
/// ```
@@ -628,7 +679,7 @@ impl<K, V> Drop for RBTree<K, V> {
/// tree.try_create_and_insert(30, 300, flags::GFP_KERNEL)?;
///
/// // Retrieve a cursor.
-/// let mut cursor = tree.cursor_front().unwrap();
+/// let mut cursor = tree.cursor_front_mut().unwrap();
///
/// // Get a mutable reference to the current value.
/// let (k, v) = cursor.current_mut();
@@ -655,7 +706,7 @@ impl<K, V> Drop for RBTree<K, V> {
/// tree.try_create_and_insert(30, 300, flags::GFP_KERNEL)?;
///
/// // Remove the first element.
-/// let mut cursor = tree.cursor_front().unwrap();
+/// let mut cursor = tree.cursor_front_mut().unwrap();
/// let mut current = cursor.current();
/// assert_eq!(current, (&10, &100));
/// cursor = cursor.remove_current().0.unwrap();
@@ -665,7 +716,7 @@ impl<K, V> Drop for RBTree<K, V> {
/// assert_eq!(current, (&20, &200));
///
/// // Get a cursor to the last element, and remove it.
-/// cursor = tree.cursor_back().unwrap();
+/// cursor = tree.cursor_back_mut().unwrap();
/// current = cursor.current();
/// assert_eq!(current, (&30, &300));
///
@@ -694,7 +745,7 @@ impl<K, V> Drop for RBTree<K, V> {
/// tree.try_create_and_insert(30, 300, flags::GFP_KERNEL)?;
///
/// // Get a cursor to the first element.
-/// let mut cursor = tree.cursor_front().unwrap();
+/// let mut cursor = tree.cursor_front_mut().unwrap();
/// let mut current = cursor.current();
/// assert_eq!(current, (&10, &100));
///
@@ -702,7 +753,7 @@ impl<K, V> Drop for RBTree<K, V> {
/// assert!(cursor.remove_prev().is_none());
///
/// // Get a cursor to the last element.
-/// cursor = tree.cursor_back().unwrap();
+/// cursor = tree.cursor_back_mut().unwrap();
/// current = cursor.current();
/// assert_eq!(current, (&30, &300));
///
@@ -726,18 +777,48 @@ impl<K, V> Drop for RBTree<K, V> {
///
/// # Invariants
/// - `current` points to a node that is in the same [`RBTree`] as `tree`.
-pub struct Cursor<'a, K, V> {
+pub struct CursorMut<'a, K, V> {
tree: &'a mut RBTree<K, V>,
current: NonNull<bindings::rb_node>,
}
-// SAFETY: The [`Cursor`] has exclusive access to both `K` and `V`, so it is sufficient to require them to be `Send`.
-// The cursor only gives out immutable references to the keys, but since it has excusive access to those same
-// keys, `Send` is sufficient. `Sync` would be okay, but it is more restrictive to the user.
-unsafe impl<'a, K: Send, V: Send> Send for Cursor<'a, K, V> {}
+/// A bidirectional immutable cursor over the tree nodes, sorted by key. This is a simpler
+/// variant of [`CursorMut`] that is basically providing read only access.
+///
+/// # Examples
+///
+/// In the following example, we obtain a cursor to the first element in the tree.
+/// The cursor allows us to iterate bidirectionally over key/value pairs in the tree.
+///
+/// ```
+/// use kernel::{alloc::flags, rbtree::RBTree};
+///
+/// // Create a new tree.
+/// let mut tree = RBTree::new();
+///
+/// // Insert three elements.
+/// tree.try_create_and_insert(10, 100, flags::GFP_KERNEL)?;
+/// tree.try_create_and_insert(20, 200, flags::GFP_KERNEL)?;
+/// tree.try_create_and_insert(30, 300, flags::GFP_KERNEL)?;
+///
+/// // Get a cursor to the first element.
+/// let cursor = tree.cursor_front().unwrap();
+/// let current = cursor.current();
+/// assert_eq!(current, (&10, &100));
+///
+/// # Ok::<(), Error>(())
+/// ```
+pub struct Cursor<'a, K, V> {
+ _tree: PhantomData<&'a RBTree<K, V>>,
+ current: NonNull<bindings::rb_node>,
+}
-// SAFETY: The [`Cursor`] gives out immutable references to K and mutable references to V,
-// so it has the same thread safety requirements as mutable references.
+// SAFETY: The immutable cursor gives out shared access to `K` and `V` so if `K` and `V` can be
+// shared across threads, then it's safe to share the cursor.
+unsafe impl<'a, K: Sync, V: Sync> Send for Cursor<'a, K, V> {}
+
+// SAFETY: The immutable cursor gives out shared access to `K` and `V` so if `K` and `V` can be
+// shared across threads, then it's safe to share the cursor.
unsafe impl<'a, K: Sync, V: Sync> Sync for Cursor<'a, K, V> {}
impl<'a, K, V> Cursor<'a, K, V> {
@@ -749,6 +830,75 @@ impl<'a, K, V> Cursor<'a, K, V> {
unsafe { Self::to_key_value(self.current) }
}
+ /// # Safety
+ ///
+ /// - `node` must be a valid pointer to a node in an [`RBTree`].
+ /// - The caller has immutable access to `node` for the duration of `'b`.
+ unsafe fn to_key_value<'b>(node: NonNull<bindings::rb_node>) -> (&'b K, &'b V) {
+ // SAFETY: By the type invariant of `Self`, all non-null `rb_node` pointers stored in `self`
+ // point to the links field of `Node<K, V>` objects.
+ let this = unsafe { container_of!(node.as_ptr(), Node<K, V>, links) };
+ // SAFETY: The passed `node` is the current node or a non-null neighbor,
+ // thus `this` is valid by the type invariants.
+ let k = unsafe { &(*this).key };
+ // SAFETY: The passed `node` is the current node or a non-null neighbor,
+ // thus `this` is valid by the type invariants.
+ let v = unsafe { &(*this).value };
+ (k, v)
+ }
+
+ /// Access the previous node without moving the cursor.
+ pub fn peek_prev(&self) -> Option<(&K, &V)> {
+ self.peek(Direction::Prev)
+ }
+
+ /// Access the next node without moving the cursor.
+ pub fn peek_next(&self) -> Option<(&K, &V)> {
+ self.peek(Direction::Next)
+ }
+
+ fn peek(&self, direction: Direction) -> Option<(&K, &V)> {
+ self.get_neighbor_raw(direction).map(|neighbor| {
+ // SAFETY:
+ // - `neighbor` is a valid tree node.
+ // - By the function signature, we have an immutable reference to `self`.
+ unsafe { Self::to_key_value(neighbor) }
+ })
+ }
+
+ fn get_neighbor_raw(&self, direction: Direction) -> Option<NonNull<bindings::rb_node>> {
+ // SAFETY: `self.current` is valid by the type invariants.
+ let neighbor = unsafe {
+ match direction {
+ Direction::Prev => bindings::rb_prev(self.current.as_ptr()),
+ Direction::Next => bindings::rb_next(self.current.as_ptr()),
+ }
+ };
+
+ NonNull::new(neighbor)
+ }
+}
+
+// SAFETY: The [`CursorMut`] has exclusive access to both `K` and `V`, so it is sufficient to
+// require them to be `Send`.
+// The cursor only gives out immutable references to the keys, but since it has exclusive access to
+// those same keys, `Send` is sufficient. `Sync` would be okay, but it is more restrictive to the
+// user.
+unsafe impl<'a, K: Send, V: Send> Send for CursorMut<'a, K, V> {}
+
+// SAFETY: The [`CursorMut`] gives out immutable references to `K` and mutable references to `V`,
+// so it has the same thread safety requirements as mutable references.
+unsafe impl<'a, K: Sync, V: Sync> Sync for CursorMut<'a, K, V> {}
+
+impl<'a, K, V> CursorMut<'a, K, V> {
+ /// The current node.
+ pub fn current(&self) -> (&K, &V) {
+ // SAFETY:
+ // - `self.current` is a valid node by the type invariants.
+ // - We have an immutable reference by the function signature.
+ unsafe { Self::to_key_value(self.current) }
+ }
+
/// The current node, with a mutable value
pub fn current_mut(&mut self) -> (&K, &mut V) {
// SAFETY:
@@ -920,7 +1070,7 @@ impl<'a, K, V> Cursor<'a, K, V> {
}
}
-/// Direction for [`Cursor`] operations.
+/// Direction for [`Cursor`] and [`CursorMut`] operations.
enum Direction {
/// the node immediately before, in sort order
Prev,
diff --git a/rust/kernel/regulator.rs b/rust/kernel/regulator.rs
index b55a201e5029..2c44827ad0b7 100644
--- a/rust/kernel/regulator.rs
+++ b/rust/kernel/regulator.rs
@@ -84,7 +84,7 @@ pub struct Error<State: RegulatorState> {
pub fn devm_enable(dev: &Device<Bound>, name: &CStr) -> Result {
// SAFETY: `dev` is a valid and bound device, while `name` is a valid C
// string.
- to_result(unsafe { bindings::devm_regulator_get_enable(dev.as_raw(), name.as_ptr()) })
+ to_result(unsafe { bindings::devm_regulator_get_enable(dev.as_raw(), name.as_char_ptr()) })
}
/// Same as [`devm_enable`], but calls `devm_regulator_get_enable_optional`
@@ -102,7 +102,9 @@ pub fn devm_enable(dev: &Device<Bound>, name: &CStr) -> Result {
pub fn devm_enable_optional(dev: &Device<Bound>, name: &CStr) -> Result {
// SAFETY: `dev` is a valid and bound device, while `name` is a valid C
// string.
- to_result(unsafe { bindings::devm_regulator_get_enable_optional(dev.as_raw(), name.as_ptr()) })
+ to_result(unsafe {
+ bindings::devm_regulator_get_enable_optional(dev.as_raw(), name.as_char_ptr())
+ })
}
/// A `struct regulator` abstraction.
@@ -266,9 +268,10 @@ impl<T: RegulatorState> Regulator<T> {
}
fn get_internal(dev: &Device, name: &CStr) -> Result<Regulator<T>> {
- // SAFETY: It is safe to call `regulator_get()`, on a device pointer
- // received from the C code.
- let inner = from_err_ptr(unsafe { bindings::regulator_get(dev.as_raw(), name.as_ptr()) })?;
+ let inner =
+ // SAFETY: It is safe to call `regulator_get()`, on a device pointer
+ // received from the C code.
+ from_err_ptr(unsafe { bindings::regulator_get(dev.as_raw(), name.as_char_ptr()) })?;
// SAFETY: We can safely trust `inner` to be a pointer to a valid
// regulator if `ERR_PTR` was not returned.
diff --git a/rust/kernel/seq_file.rs b/rust/kernel/seq_file.rs
index 59fbfc2473f8..855e533813a6 100644
--- a/rust/kernel/seq_file.rs
+++ b/rust/kernel/seq_file.rs
@@ -4,7 +4,7 @@
//!
//! C header: [`include/linux/seq_file.h`](srctree/include/linux/seq_file.h)
-use crate::{bindings, c_str, fmt, types::NotThreadSafe, types::Opaque};
+use crate::{bindings, c_str, fmt, str::CStrExt as _, types::NotThreadSafe, types::Opaque};
/// A utility for generating the contents of a seq file.
#[repr(transparent)]
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index 5c74e5f77601..6fcc9d47f12e 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -10,9 +10,11 @@ use crate::{
};
use core::{
marker::PhantomData,
- ops::{self, Deref, DerefMut, Index},
+ ops::{Deref, DerefMut, Index},
};
+pub use crate::prelude::CStr;
+
/// Byte string without UTF-8 validity guarantee.
#[repr(transparent)]
pub struct BStr([u8]);
@@ -186,58 +188,17 @@ macro_rules! b_str {
// - error[E0379]: functions in trait impls cannot be declared const
#[inline]
pub const fn as_char_ptr_in_const_context(c_str: &CStr) -> *const c_char {
- c_str.0.as_ptr()
+ c_str.as_ptr().cast()
}
-/// Possible errors when using conversion functions in [`CStr`].
-#[derive(Debug, Clone, Copy)]
-pub enum CStrConvertError {
- /// Supplied bytes contain an interior `NUL`.
- InteriorNul,
-
- /// Supplied bytes are not terminated by `NUL`.
- NotNulTerminated,
-}
+mod private {
+ pub trait Sealed {}
-impl From<CStrConvertError> for Error {
- #[inline]
- fn from(_: CStrConvertError) -> Error {
- EINVAL
- }
+ impl Sealed for super::CStr {}
}
-/// A string that is guaranteed to have exactly one `NUL` byte, which is at the
-/// end.
-///
-/// Used for interoperability with kernel APIs that take C strings.
-#[repr(transparent)]
-pub struct CStr([u8]);
-
-impl CStr {
- /// Returns the length of this string excluding `NUL`.
- #[inline]
- pub const fn len(&self) -> usize {
- self.len_with_nul() - 1
- }
-
- /// Returns the length of this string with `NUL`.
- #[inline]
- pub const fn len_with_nul(&self) -> usize {
- if self.0.is_empty() {
- // SAFETY: This is one of the invariant of `CStr`.
- // We add a `unreachable_unchecked` here to hint the optimizer that
- // the value returned from this function is non-zero.
- unsafe { core::hint::unreachable_unchecked() };
- }
- self.0.len()
- }
-
- /// Returns `true` if the string only includes `NUL`.
- #[inline]
- pub const fn is_empty(&self) -> bool {
- self.len() == 0
- }
-
+/// Extensions to [`CStr`].
+pub trait CStrExt: private::Sealed {
/// Wraps a raw C string pointer.
///
/// # Safety
@@ -245,54 +206,9 @@ impl CStr {
/// `ptr` must be a valid pointer to a `NUL`-terminated C string, and it must
/// last at least `'a`. When `CStr` is alive, the memory pointed by `ptr`
/// must not be mutated.
- #[inline]
- pub unsafe fn from_char_ptr<'a>(ptr: *const c_char) -> &'a Self {
- // SAFETY: The safety precondition guarantees `ptr` is a valid pointer
- // to a `NUL`-terminated C string.
- let len = unsafe { bindings::strlen(ptr) } + 1;
- // SAFETY: Lifetime guaranteed by the safety precondition.
- let bytes = unsafe { core::slice::from_raw_parts(ptr.cast(), len) };
- // SAFETY: As `len` is returned by `strlen`, `bytes` does not contain interior `NUL`.
- // As we have added 1 to `len`, the last byte is known to be `NUL`.
- unsafe { Self::from_bytes_with_nul_unchecked(bytes) }
- }
-
- /// Creates a [`CStr`] from a `[u8]`.
- ///
- /// The provided slice must be `NUL`-terminated, does not contain any
- /// interior `NUL` bytes.
- pub const fn from_bytes_with_nul(bytes: &[u8]) -> Result<&Self, CStrConvertError> {
- if bytes.is_empty() {
- return Err(CStrConvertError::NotNulTerminated);
- }
- if bytes[bytes.len() - 1] != 0 {
- return Err(CStrConvertError::NotNulTerminated);
- }
- let mut i = 0;
- // `i + 1 < bytes.len()` allows LLVM to optimize away bounds checking,
- // while it couldn't optimize away bounds checks for `i < bytes.len() - 1`.
- while i + 1 < bytes.len() {
- if bytes[i] == 0 {
- return Err(CStrConvertError::InteriorNul);
- }
- i += 1;
- }
- // SAFETY: We just checked that all properties hold.
- Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
- }
-
- /// Creates a [`CStr`] from a `[u8]` without performing any additional
- /// checks.
- ///
- /// # Safety
- ///
- /// `bytes` *must* end with a `NUL` byte, and should only have a single
- /// `NUL` byte (or the string will be truncated).
- #[inline]
- pub const unsafe fn from_bytes_with_nul_unchecked(bytes: &[u8]) -> &CStr {
- // SAFETY: Properties of `bytes` guaranteed by the safety precondition.
- unsafe { core::mem::transmute(bytes) }
- }
+ // This function exists to paper over the fact that `CStr::from_ptr` takes a `*const
+ // core::ffi::c_char` rather than a `*const crate::ffi::c_char`.
+ unsafe fn from_char_ptr<'a>(ptr: *const c_char) -> &'a Self;
/// Creates a mutable [`CStr`] from a `[u8]` without performing any
/// additional checks.
@@ -301,99 +217,16 @@ impl CStr {
///
/// `bytes` *must* end with a `NUL` byte, and should only have a single
/// `NUL` byte (or the string will be truncated).
- #[inline]
- pub unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut CStr {
- // SAFETY: Properties of `bytes` guaranteed by the safety precondition.
- unsafe { &mut *(core::ptr::from_mut(bytes) as *mut CStr) }
- }
+ unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut Self;
/// Returns a C pointer to the string.
- ///
- /// Using this function in a const context is deprecated in favor of
- /// [`as_char_ptr_in_const_context`] in preparation for replacing `CStr` with `core::ffi::CStr`
- /// which does not have this method.
- #[inline]
- pub const fn as_char_ptr(&self) -> *const c_char {
- as_char_ptr_in_const_context(self)
- }
-
- /// Convert the string to a byte slice without the trailing `NUL` byte.
- #[inline]
- pub fn to_bytes(&self) -> &[u8] {
- &self.0[..self.len()]
- }
-
- /// Convert the string to a byte slice without the trailing `NUL` byte.
- ///
- /// This function is deprecated in favor of [`Self::to_bytes`] in preparation for replacing
- /// `CStr` with `core::ffi::CStr` which does not have this method.
- #[inline]
- pub fn as_bytes(&self) -> &[u8] {
- self.to_bytes()
- }
-
- /// Convert the string to a byte slice containing the trailing `NUL` byte.
- #[inline]
- pub const fn to_bytes_with_nul(&self) -> &[u8] {
- &self.0
- }
-
- /// Convert the string to a byte slice containing the trailing `NUL` byte.
- ///
- /// This function is deprecated in favor of [`Self::to_bytes_with_nul`] in preparation for
- /// replacing `CStr` with `core::ffi::CStr` which does not have this method.
- #[inline]
- pub const fn as_bytes_with_nul(&self) -> &[u8] {
- self.to_bytes_with_nul()
- }
-
- /// Yields a [`&str`] slice if the [`CStr`] contains valid UTF-8.
- ///
- /// If the contents of the [`CStr`] are valid UTF-8 data, this
- /// function will return the corresponding [`&str`] slice. Otherwise,
- /// it will return an error with details of where UTF-8 validation failed.
- ///
- /// # Examples
- ///
- /// ```
- /// # use kernel::str::CStr;
- /// let cstr = CStr::from_bytes_with_nul(b"foo\0")?;
- /// assert_eq!(cstr.to_str(), Ok("foo"));
- /// # Ok::<(), kernel::error::Error>(())
- /// ```
- #[inline]
- pub fn to_str(&self) -> Result<&str, core::str::Utf8Error> {
- core::str::from_utf8(self.as_bytes())
- }
-
- /// Unsafely convert this [`CStr`] into a [`&str`], without checking for
- /// valid UTF-8.
- ///
- /// # Safety
- ///
- /// The contents must be valid UTF-8.
- ///
- /// # Examples
- ///
- /// ```
- /// # use kernel::c_str;
- /// # use kernel::str::CStr;
- /// let bar = c_str!("ツ");
- /// // SAFETY: String literals are guaranteed to be valid UTF-8
- /// // by the Rust compiler.
- /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ");
- /// ```
- #[inline]
- pub unsafe fn as_str_unchecked(&self) -> &str {
- // SAFETY: TODO.
- unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
- }
+ // This function exists to paper over the fact that `CStr::as_ptr` returns a `*const
+ // core::ffi::c_char` rather than a `*const crate::ffi::c_char`.
+ fn as_char_ptr(&self) -> *const c_char;
/// Convert this [`CStr`] into a [`CString`] by allocating memory and
/// copying over the string data.
- pub fn to_cstring(&self) -> Result<CString, AllocError> {
- CString::try_from(self)
- }
+ fn to_cstring(&self) -> Result<CString, AllocError>;
/// Converts this [`CStr`] to its ASCII lower case equivalent in-place.
///
@@ -404,11 +237,7 @@ impl CStr {
/// [`to_ascii_lowercase()`].
///
/// [`to_ascii_lowercase()`]: #method.to_ascii_lowercase
- pub fn make_ascii_lowercase(&mut self) {
- // INVARIANT: This doesn't introduce or remove NUL bytes in the C
- // string.
- self.0.make_ascii_lowercase();
- }
+ fn make_ascii_lowercase(&mut self);
/// Converts this [`CStr`] to its ASCII upper case equivalent in-place.
///
@@ -419,11 +248,7 @@ impl CStr {
/// [`to_ascii_uppercase()`].
///
/// [`to_ascii_uppercase()`]: #method.to_ascii_uppercase
- pub fn make_ascii_uppercase(&mut self) {
- // INVARIANT: This doesn't introduce or remove NUL bytes in the C
- // string.
- self.0.make_ascii_uppercase();
- }
+ fn make_ascii_uppercase(&mut self);
/// Returns a copy of this [`CString`] where each character is mapped to its
/// ASCII lower case equivalent.
@@ -434,13 +259,7 @@ impl CStr {
/// To lowercase the value in-place, use [`make_ascii_lowercase`].
///
/// [`make_ascii_lowercase`]: str::make_ascii_lowercase
- pub fn to_ascii_lowercase(&self) -> Result<CString, AllocError> {
- let mut s = self.to_cstring()?;
-
- s.make_ascii_lowercase();
-
- Ok(s)
- }
+ fn to_ascii_lowercase(&self) -> Result<CString, AllocError>;
/// Returns a copy of this [`CString`] where each character is mapped to its
/// ASCII upper case equivalent.
@@ -451,28 +270,21 @@ impl CStr {
/// To uppercase the value in-place, use [`make_ascii_uppercase`].
///
/// [`make_ascii_uppercase`]: str::make_ascii_uppercase
- pub fn to_ascii_uppercase(&self) -> Result<CString, AllocError> {
- let mut s = self.to_cstring()?;
-
- s.make_ascii_uppercase();
-
- Ok(s)
- }
+ fn to_ascii_uppercase(&self) -> Result<CString, AllocError>;
}
impl fmt::Display for CStr {
/// Formats printable ASCII characters, escaping the rest.
///
/// ```
- /// # use kernel::c_str;
/// # use kernel::prelude::fmt;
/// # use kernel::str::CStr;
/// # use kernel::str::CString;
- /// let penguin = c_str!("🐧");
+ /// let penguin = c"🐧";
/// let s = CString::try_from_fmt(fmt!("{penguin}"))?;
/// assert_eq!(s.to_bytes_with_nul(), "\\xf0\\x9f\\x90\\xa7\0".as_bytes());
///
- /// let ascii = c_str!("so \"cool\"");
+ /// let ascii = c"so \"cool\"";
/// let s = CString::try_from_fmt(fmt!("{ascii}"))?;
/// assert_eq!(s.to_bytes_with_nul(), "so \"cool\"\0".as_bytes());
/// # Ok::<(), kernel::error::Error>(())
@@ -490,98 +302,75 @@ impl fmt::Display for CStr {
}
}
-impl fmt::Debug for CStr {
- /// Formats printable ASCII characters with a double quote on either end, escaping the rest.
- ///
- /// ```
- /// # use kernel::c_str;
- /// # use kernel::prelude::fmt;
- /// # use kernel::str::CStr;
- /// # use kernel::str::CString;
- /// let penguin = c_str!("🐧");
- /// let s = CString::try_from_fmt(fmt!("{penguin:?}"))?;
- /// assert_eq!(s.as_bytes_with_nul(), "\"\\xf0\\x9f\\x90\\xa7\"\0".as_bytes());
- ///
- /// // Embedded double quotes are escaped.
- /// let ascii = c_str!("so \"cool\"");
- /// let s = CString::try_from_fmt(fmt!("{ascii:?}"))?;
- /// assert_eq!(s.as_bytes_with_nul(), "\"so \\\"cool\\\"\"\0".as_bytes());
- /// # Ok::<(), kernel::error::Error>(())
- /// ```
- fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
- f.write_str("\"")?;
- for &c in self.as_bytes() {
- match c {
- // Printable characters.
- b'\"' => f.write_str("\\\"")?,
- 0x20..=0x7e => f.write_char(c as char)?,
- _ => write!(f, "\\x{c:02x}")?,
- }
- }
- f.write_str("\"")
- }
+/// Converts a mutable C string to a mutable byte slice.
+///
+/// # Safety
+///
+/// The caller must ensure that the slice ends in a NUL byte and contains no other NUL bytes before
+/// the borrow ends and the underlying [`CStr`] is used.
+unsafe fn to_bytes_mut(s: &mut CStr) -> &mut [u8] {
+ // SAFETY: the cast from `&CStr` to `&[u8]` is safe since `CStr` has the same layout as `&[u8]`
+ // (this is technically not guaranteed, but we rely on it here). The pointer dereference is
+ // safe since it comes from a mutable reference which is guaranteed to be valid for writes.
+ unsafe { &mut *(core::ptr::from_mut(s) as *mut [u8]) }
}
-impl AsRef<BStr> for CStr {
+impl CStrExt for CStr {
#[inline]
- fn as_ref(&self) -> &BStr {
- BStr::from_bytes(self.as_bytes())
+ unsafe fn from_char_ptr<'a>(ptr: *const c_char) -> &'a Self {
+ // SAFETY: The safety preconditions are the same as for `CStr::from_ptr`.
+ unsafe { CStr::from_ptr(ptr.cast()) }
}
-}
-impl Deref for CStr {
- type Target = BStr;
+ #[inline]
+ unsafe fn from_bytes_with_nul_unchecked_mut(bytes: &mut [u8]) -> &mut Self {
+ // SAFETY: the cast from `&[u8]` to `&CStr` is safe since the properties of `bytes` are
+ // guaranteed by the safety precondition and `CStr` has the same layout as `&[u8]` (this is
+ // technically not guaranteed, but we rely on it here). The pointer dereference is safe
+ // since it comes from a mutable reference which is guaranteed to be valid for writes.
+ unsafe { &mut *(core::ptr::from_mut(bytes) as *mut CStr) }
+ }
#[inline]
- fn deref(&self) -> &Self::Target {
- self.as_ref()
+ fn as_char_ptr(&self) -> *const c_char {
+ self.as_ptr().cast()
+ }
+
+ fn to_cstring(&self) -> Result<CString, AllocError> {
+ CString::try_from(self)
}
-}
-impl Index<ops::RangeFrom<usize>> for CStr {
- type Output = CStr;
+ fn make_ascii_lowercase(&mut self) {
+ // SAFETY: This doesn't introduce or remove NUL bytes in the C string.
+ unsafe { to_bytes_mut(self) }.make_ascii_lowercase();
+ }
- #[inline]
- fn index(&self, index: ops::RangeFrom<usize>) -> &Self::Output {
- // Delegate bounds checking to slice.
- // Assign to _ to mute clippy's unnecessary operation warning.
- let _ = &self.as_bytes()[index.start..];
- // SAFETY: We just checked the bounds.
- unsafe { Self::from_bytes_with_nul_unchecked(&self.0[index.start..]) }
+ fn make_ascii_uppercase(&mut self) {
+ // SAFETY: This doesn't introduce or remove NUL bytes in the C string.
+ unsafe { to_bytes_mut(self) }.make_ascii_uppercase();
}
-}
-impl Index<ops::RangeFull> for CStr {
- type Output = CStr;
+ fn to_ascii_lowercase(&self) -> Result<CString, AllocError> {
+ let mut s = self.to_cstring()?;
+
+ s.make_ascii_lowercase();
- #[inline]
- fn index(&self, _index: ops::RangeFull) -> &Self::Output {
- self
+ Ok(s)
}
-}
-mod private {
- use core::ops;
+ fn to_ascii_uppercase(&self) -> Result<CString, AllocError> {
+ let mut s = self.to_cstring()?;
- // Marker trait for index types that can be forward to `BStr`.
- pub trait CStrIndex {}
+ s.make_ascii_uppercase();
- impl CStrIndex for usize {}
- impl CStrIndex for ops::Range<usize> {}
- impl CStrIndex for ops::RangeInclusive<usize> {}
- impl CStrIndex for ops::RangeToInclusive<usize> {}
+ Ok(s)
+ }
}
-impl<Idx> Index<Idx> for CStr
-where
- Idx: private::CStrIndex,
- BStr: Index<Idx>,
-{
- type Output = <BStr as Index<Idx>>::Output;
-
+impl AsRef<BStr> for CStr {
#[inline]
- fn index(&self, index: Idx) -> &Self::Output {
- &self.as_ref()[index]
+ fn as_ref(&self) -> &BStr {
+ BStr::from_bytes(self.to_bytes())
}
}
@@ -612,6 +401,13 @@ macro_rules! c_str {
mod tests {
use super::*;
+ impl From<core::ffi::FromBytesWithNulError> for Error {
+ #[inline]
+ fn from(_: core::ffi::FromBytesWithNulError) -> Error {
+ EINVAL
+ }
+ }
+
macro_rules! format {
($($f:tt)*) => ({
CString::try_from_fmt(fmt!($($f)*))?.to_str()?
@@ -634,40 +430,28 @@ mod tests {
#[test]
fn test_cstr_to_str() -> Result {
- let good_bytes = b"\xf0\x9f\xa6\x80\0";
- let checked_cstr = CStr::from_bytes_with_nul(good_bytes)?;
- let checked_str = checked_cstr.to_str()?;
+ let cstr = c"\xf0\x9f\xa6\x80";
+ let checked_str = cstr.to_str()?;
assert_eq!(checked_str, "🦀");
Ok(())
}
#[test]
fn test_cstr_to_str_invalid_utf8() -> Result {
- let bad_bytes = b"\xc3\x28\0";
- let checked_cstr = CStr::from_bytes_with_nul(bad_bytes)?;
- assert!(checked_cstr.to_str().is_err());
- Ok(())
- }
-
- #[test]
- fn test_cstr_as_str_unchecked() -> Result {
- let good_bytes = b"\xf0\x9f\x90\xA7\0";
- let checked_cstr = CStr::from_bytes_with_nul(good_bytes)?;
- // SAFETY: The contents come from a string literal which contains valid UTF-8.
- let unchecked_str = unsafe { checked_cstr.as_str_unchecked() };
- assert_eq!(unchecked_str, "🐧");
+ let cstr = c"\xc3\x28";
+ assert!(cstr.to_str().is_err());
Ok(())
}
#[test]
fn test_cstr_display() -> Result {
- let hello_world = CStr::from_bytes_with_nul(b"hello, world!\0")?;
+ let hello_world = c"hello, world!";
assert_eq!(format!("{hello_world}"), "hello, world!");
- let non_printables = CStr::from_bytes_with_nul(b"\x01\x09\x0a\0")?;
+ let non_printables = c"\x01\x09\x0a";
assert_eq!(format!("{non_printables}"), "\\x01\\x09\\x0a");
- let non_ascii = CStr::from_bytes_with_nul(b"d\xe9j\xe0 vu\0")?;
+ let non_ascii = c"d\xe9j\xe0 vu";
assert_eq!(format!("{non_ascii}"), "d\\xe9j\\xe0 vu");
- let good_bytes = CStr::from_bytes_with_nul(b"\xf0\x9f\xa6\x80\0")?;
+ let good_bytes = c"\xf0\x9f\xa6\x80";
assert_eq!(format!("{good_bytes}"), "\\xf0\\x9f\\xa6\\x80");
Ok(())
}
@@ -686,14 +470,12 @@ mod tests {
#[test]
fn test_cstr_debug() -> Result {
- let hello_world = CStr::from_bytes_with_nul(b"hello, world!\0")?;
+ let hello_world = c"hello, world!";
assert_eq!(format!("{hello_world:?}"), "\"hello, world!\"");
- let non_printables = CStr::from_bytes_with_nul(b"\x01\x09\x0a\0")?;
- assert_eq!(format!("{non_printables:?}"), "\"\\x01\\x09\\x0a\"");
- let non_ascii = CStr::from_bytes_with_nul(b"d\xe9j\xe0 vu\0")?;
+ let non_printables = c"\x01\x09\x0a";
+ assert_eq!(format!("{non_printables:?}"), "\"\\x01\\t\\n\"");
+ let non_ascii = c"d\xe9j\xe0 vu";
assert_eq!(format!("{non_ascii:?}"), "\"d\\xe9j\\xe0 vu\"");
- let good_bytes = CStr::from_bytes_with_nul(b"\xf0\x9f\xa6\x80\0")?;
- assert_eq!(format!("{good_bytes:?}"), "\"\\xf0\\x9f\\xa6\\x80\"");
Ok(())
}
@@ -941,43 +723,43 @@ unsafe fn kstrtobool_raw(string: *const u8) -> Result<bool> {
/// # Examples
///
/// ```
-/// # use kernel::{c_str, str::kstrtobool};
+/// # use kernel::str::kstrtobool;
///
/// // Lowercase
-/// assert_eq!(kstrtobool(c_str!("true")), Ok(true));
-/// assert_eq!(kstrtobool(c_str!("tr")), Ok(true));
-/// assert_eq!(kstrtobool(c_str!("t")), Ok(true));
-/// assert_eq!(kstrtobool(c_str!("twrong")), Ok(true));
-/// assert_eq!(kstrtobool(c_str!("false")), Ok(false));
-/// assert_eq!(kstrtobool(c_str!("f")), Ok(false));
-/// assert_eq!(kstrtobool(c_str!("yes")), Ok(true));
-/// assert_eq!(kstrtobool(c_str!("no")), Ok(false));
-/// assert_eq!(kstrtobool(c_str!("on")), Ok(true));
-/// assert_eq!(kstrtobool(c_str!("off")), Ok(false));
+/// assert_eq!(kstrtobool(c"true"), Ok(true));
+/// assert_eq!(kstrtobool(c"tr"), Ok(true));
+/// assert_eq!(kstrtobool(c"t"), Ok(true));
+/// assert_eq!(kstrtobool(c"twrong"), Ok(true));
+/// assert_eq!(kstrtobool(c"false"), Ok(false));
+/// assert_eq!(kstrtobool(c"f"), Ok(false));
+/// assert_eq!(kstrtobool(c"yes"), Ok(true));
+/// assert_eq!(kstrtobool(c"no"), Ok(false));
+/// assert_eq!(kstrtobool(c"on"), Ok(true));
+/// assert_eq!(kstrtobool(c"off"), Ok(false));
///
/// // Camel case
-/// assert_eq!(kstrtobool(c_str!("True")), Ok(true));
-/// assert_eq!(kstrtobool(c_str!("False")), Ok(false));
-/// assert_eq!(kstrtobool(c_str!("Yes")), Ok(true));
-/// assert_eq!(kstrtobool(c_str!("No")), Ok(false));
-/// assert_eq!(kstrtobool(c_str!("On")), Ok(true));
-/// assert_eq!(kstrtobool(c_str!("Off")), Ok(false));
+/// assert_eq!(kstrtobool(c"True"), Ok(true));
+/// assert_eq!(kstrtobool(c"False"), Ok(false));
+/// assert_eq!(kstrtobool(c"Yes"), Ok(true));
+/// assert_eq!(kstrtobool(c"No"), Ok(false));
+/// assert_eq!(kstrtobool(c"On"), Ok(true));
+/// assert_eq!(kstrtobool(c"Off"), Ok(false));
///
/// // All caps
-/// assert_eq!(kstrtobool(c_str!("TRUE")), Ok(true));
-/// assert_eq!(kstrtobool(c_str!("FALSE")), Ok(false));
-/// assert_eq!(kstrtobool(c_str!("YES")), Ok(true));
-/// assert_eq!(kstrtobool(c_str!("NO")), Ok(false));
-/// assert_eq!(kstrtobool(c_str!("ON")), Ok(true));
-/// assert_eq!(kstrtobool(c_str!("OFF")), Ok(false));
+/// assert_eq!(kstrtobool(c"TRUE"), Ok(true));
+/// assert_eq!(kstrtobool(c"FALSE"), Ok(false));
+/// assert_eq!(kstrtobool(c"YES"), Ok(true));
+/// assert_eq!(kstrtobool(c"NO"), Ok(false));
+/// assert_eq!(kstrtobool(c"ON"), Ok(true));
+/// assert_eq!(kstrtobool(c"OFF"), Ok(false));
///
/// // Numeric
-/// assert_eq!(kstrtobool(c_str!("1")), Ok(true));
-/// assert_eq!(kstrtobool(c_str!("0")), Ok(false));
+/// assert_eq!(kstrtobool(c"1"), Ok(true));
+/// assert_eq!(kstrtobool(c"0"), Ok(false));
///
/// // Invalid input
-/// assert_eq!(kstrtobool(c_str!("invalid")), Err(EINVAL));
-/// assert_eq!(kstrtobool(c_str!("2")), Err(EINVAL));
+/// assert_eq!(kstrtobool(c"invalid"), Err(EINVAL));
+/// assert_eq!(kstrtobool(c"2"), Err(EINVAL));
/// ```
pub fn kstrtobool(string: &CStr) -> Result<bool> {
// SAFETY:
diff --git a/rust/kernel/sync.rs b/rust/kernel/sync.rs
index cf5b638a097d..c94753d6413e 100644
--- a/rust/kernel/sync.rs
+++ b/rust/kernel/sync.rs
@@ -48,7 +48,6 @@ impl LockClassKey {
///
/// # Examples
/// ```
- /// # use kernel::c_str;
/// # use kernel::alloc::KBox;
/// # use kernel::types::ForeignOwnable;
/// # use kernel::sync::{LockClassKey, SpinLock};
@@ -60,7 +59,7 @@ impl LockClassKey {
/// {
/// stack_pin_init!(let num: SpinLock<u32> = SpinLock::new(
/// 0,
- /// c_str!("my_spinlock"),
+ /// c"my_spinlock",
/// // SAFETY: `key_ptr` is returned by the above `into_foreign()`, whose
/// // `from_foreign()` has not yet been called.
/// unsafe { <Pin<KBox<LockClassKey>> as ForeignOwnable>::borrow(key_ptr) }
diff --git a/rust/kernel/sync/condvar.rs b/rust/kernel/sync/condvar.rs
index aa5b9a7a726d..69d58dfbad7b 100644
--- a/rust/kernel/sync/condvar.rs
+++ b/rust/kernel/sync/condvar.rs
@@ -8,7 +8,7 @@
use super::{lock::Backend, lock::Guard, LockClassKey};
use crate::{
ffi::{c_int, c_long},
- str::CStr,
+ str::{CStr, CStrExt as _},
task::{
MAX_SCHEDULE_TIMEOUT, TASK_FREEZABLE, TASK_INTERRUPTIBLE, TASK_NORMAL, TASK_UNINTERRUPTIBLE,
},
diff --git a/rust/kernel/sync/lock.rs b/rust/kernel/sync/lock.rs
index cb00fdb94ffd..46a57d1fc309 100644
--- a/rust/kernel/sync/lock.rs
+++ b/rust/kernel/sync/lock.rs
@@ -7,7 +7,7 @@
use super::LockClassKey;
use crate::{
- str::CStr,
+ str::{CStr, CStrExt as _},
types::{NotThreadSafe, Opaque, ScopeGuard},
};
use core::{cell::UnsafeCell, marker::PhantomPinned, pin::Pin};
diff --git a/rust/kernel/sync/lock/global.rs b/rust/kernel/sync/lock/global.rs
index 38b448032799..eab48108a4ae 100644
--- a/rust/kernel/sync/lock/global.rs
+++ b/rust/kernel/sync/lock/global.rs
@@ -5,7 +5,7 @@
//! Support for defining statics containing locks.
use crate::{
- str::CStr,
+ str::{CStr, CStrExt as _},
sync::lock::{Backend, Guard, Lock},
sync::{LockClassKey, LockedBy},
types::Opaque,
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index dc0a02f5c3cf..9c5e7dbf1632 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -289,7 +289,6 @@ impl<T, F: FnOnce(T)> Drop for ScopeGuard<T, F> {
/// # Examples
///
/// ```
-/// # #![expect(unreachable_pub, clippy::disallowed_names)]
/// use kernel::types::Opaque;
/// # // Emulate a C struct binding which is from C, maybe uninitialized or not, only the C side
/// # // knows.