mirror of
https://github.com/torvalds/linux.git
synced 2026-01-24 23:16:46 +00:00
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`
...
This commit is contained in:
@@ -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"),
|
||||
|
||||
@@ -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.
|
||||
//
|
||||
|
||||
@@ -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(),
|
||||
)
|
||||
};
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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)
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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:?}")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ use core::{marker::PhantomData, ptr};
|
||||
|
||||
#[cfg(CONFIG_PRINTK)]
|
||||
use crate::c_str;
|
||||
use crate::str::CStrExt as _;
|
||||
|
||||
pub mod property;
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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) })
|
||||
}
|
||||
|
||||
@@ -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
|
||||
};
|
||||
|
||||
@@ -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},
|
||||
);
|
||||
|
||||
@@ -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 {
|
||||
|
||||
@@ -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;
|
||||
|
||||
79
rust/kernel/num.rs
Normal file
79
rust/kernel/num.rs
Normal file
@@ -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
|
||||
);
|
||||
1058
rust/kernel/num/bounded.rs
Normal file
1058
rust/kernel/num/bounded.rs
Normal file
File diff suppressed because it is too large
Load Diff
@@ -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)?;
|
||||
|
||||
@@ -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.
|
||||
///
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -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;
|
||||
|
||||
|
||||
@@ -243,14 +243,44 @@ 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`.
|
||||
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(&mut self) -> Option<CursorMut<'_, K, V>> {
|
||||
let root = addr_of_mut!(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`.
|
||||
CursorMut {
|
||||
current,
|
||||
tree: self,
|
||||
}
|
||||
@@ -258,16 +288,16 @@ impl<K, V> RBTree<K, V> {
|
||||
}
|
||||
|
||||
/// Returns a cursor over the tree nodes, starting with the largest key.
|
||||
pub fn cursor_back(&mut self) -> Option<Cursor<'_, K, V>> {
|
||||
let root = addr_of_mut!(self.root);
|
||||
// SAFETY: `self.root` is always a valid root node
|
||||
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: self,
|
||||
_tree: PhantomData,
|
||||
}
|
||||
})
|
||||
}
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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)]
|
||||
|
||||
@@ -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,
|
||||
mod private {
|
||||
pub trait Sealed {}
|
||||
|
||||
/// Supplied bytes are not terminated by `NUL`.
|
||||
NotNulTerminated,
|
||||
impl Sealed for super::CStr {}
|
||||
}
|
||||
|
||||
impl From<CStrConvertError> for Error {
|
||||
#[inline]
|
||||
fn from(_: CStrConvertError) -> Error {
|
||||
EINVAL
|
||||
}
|
||||
}
|
||||
|
||||
/// 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 CStrExt for CStr {
|
||||
#[inline]
|
||||
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()) }
|
||||
}
|
||||
|
||||
#[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 as_char_ptr(&self) -> *const c_char {
|
||||
self.as_ptr().cast()
|
||||
}
|
||||
|
||||
fn to_cstring(&self) -> Result<CString, AllocError> {
|
||||
CString::try_from(self)
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
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();
|
||||
}
|
||||
|
||||
fn to_ascii_lowercase(&self) -> Result<CString, AllocError> {
|
||||
let mut s = self.to_cstring()?;
|
||||
|
||||
s.make_ascii_lowercase();
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
|
||||
fn to_ascii_uppercase(&self) -> Result<CString, AllocError> {
|
||||
let mut s = self.to_cstring()?;
|
||||
|
||||
s.make_ascii_uppercase();
|
||||
|
||||
Ok(s)
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<BStr> for CStr {
|
||||
#[inline]
|
||||
fn as_ref(&self) -> &BStr {
|
||||
BStr::from_bytes(self.as_bytes())
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for CStr {
|
||||
type Target = BStr;
|
||||
|
||||
#[inline]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
self.as_ref()
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<ops::RangeFrom<usize>> for CStr {
|
||||
type Output = CStr;
|
||||
|
||||
#[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..]) }
|
||||
}
|
||||
}
|
||||
|
||||
impl Index<ops::RangeFull> for CStr {
|
||||
type Output = CStr;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, _index: ops::RangeFull) -> &Self::Output {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
mod private {
|
||||
use core::ops;
|
||||
|
||||
// Marker trait for index types that can be forward to `BStr`.
|
||||
pub trait CStrIndex {}
|
||||
|
||||
impl CStrIndex for usize {}
|
||||
impl CStrIndex for ops::Range<usize> {}
|
||||
impl CStrIndex for ops::RangeInclusive<usize> {}
|
||||
impl CStrIndex for ops::RangeToInclusive<usize> {}
|
||||
}
|
||||
|
||||
impl<Idx> Index<Idx> for CStr
|
||||
where
|
||||
Idx: private::CStrIndex,
|
||||
BStr: Index<Idx>,
|
||||
{
|
||||
type Output = <BStr as Index<Idx>>::Output;
|
||||
|
||||
#[inline]
|
||||
fn index(&self, index: Idx) -> &Self::Output {
|
||||
&self.as_ref()[index]
|
||||
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:
|
||||
|
||||
@@ -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) }
|
||||
|
||||
@@ -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,
|
||||
},
|
||||
|
||||
@@ -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};
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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.
|
||||
|
||||
Reference in New Issue
Block a user