linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2 00/28] Rust core additions
@ 2022-12-02 16:14 ojeda
  2022-12-02 16:14 ` [PATCH v2 01/28] rust: prelude: split re-exports into groups ojeda
                   ` (28 more replies)
  0 siblings, 29 replies; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches

From: Miguel Ojeda <ojeda@kernel.org>

This is v2 of the first batch of changes to upstream the rest of
the Rust support. v1 is at:

    https://lore.kernel.org/rust-for-linux/20221110164152.26136-1-ojeda@kernel.org/

I collected the tags and applied the agreed changes. The full diff
follows (with respect to v1), since they are minor enough.

I will be applying the patches tomorrow, since v1 has had more than
three weeks of review time.

diff --git a/rust/build_error.rs b/rust/build_error.rs
index 0ff6b33059aa..fa24eeef9929 100644
--- a/rust/build_error.rs
+++ b/rust/build_error.rs
@@ -2,19 +2,26 @@
 
 //! Build-time error.
 //!
-//! This crate provides a function `build_error`, which will panic in
-//! compile-time if executed in const context, and will cause a build error
-//! if not executed at compile time and the optimizer does not optimise away the
-//! call.
+//! This crate provides a [const function][const-functions] `build_error`, which will panic in
+//! compile-time if executed in [const context][const-context], and will cause a build error
+//! if not executed at compile time and the optimizer does not optimise away the call.
 //!
 //! It is used by `build_assert!` in the kernel crate, allowing checking of
 //! conditions that could be checked statically, but could not be enforced in
-//! Rust yet (e.g. perform some checks in const functions, but those
+//! Rust yet (e.g. perform some checks in [const functions][const-functions], but those
 //! functions could still be called in the runtime).
+//!
+//! For details on constant evaluation in Rust, please see the [Reference][const-eval].
+//!
+//! [const-eval]: https://doc.rust-lang.org/reference/const_eval.html
+//! [const-functions]: https://doc.rust-lang.org/reference/const_eval.html#const-functions
+//! [const-context]: https://doc.rust-lang.org/reference/const_eval.html#const-context
 
 #![no_std]
 
-/// Panics if executed in const context, or triggers a build error if not.
+/// Panics if executed in [const context][const-context], or triggers a build error if not.
+///
+/// [const-context]: https://doc.rust-lang.org/reference/const_eval.html#const-context
 #[inline(never)]
 #[cold]
 #[export_name = "rust_build_error"]
diff --git a/rust/kernel/std_vendor.rs b/rust/kernel/std_vendor.rs
index da57b4e521f4..b3e68b24a8c6 100644
--- a/rust/kernel/std_vendor.rs
+++ b/rust/kernel/std_vendor.rs
@@ -35,9 +35,12 @@
 /// This is useful when debugging issues that only occur in release
 /// builds or when debugging in release mode is significantly faster.
 ///
-/// Note that the macro is intended as a debugging tool and therefore you
-/// should avoid having uses of it in version control for long periods
-/// (other than in tests and similar).
+/// Note that the macro is intended as a temporary debugging tool to be
+/// used during development. Therefore, avoid committing `dbg!` macro
+/// invocations into the kernel tree.
+///
+/// For debug output that is intended to be kept in the kernel tree,
+/// use [`pr_debug`] and similar facilities instead.
 ///
 /// # Stability
 ///
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index ffac633423db..b771310fa4a4 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -129,18 +129,6 @@ impl CStr {
         Ok(unsafe { Self::from_bytes_with_nul_unchecked(bytes) })
     }
 
-    /// Creates a [`CStr`] from a `[u8]`, panic if input is not valid.
-    ///
-    /// This function is only meant to be used by `c_str!` macro, so
-    /// crates using `c_str!` macro don't have to enable `const_panic` feature.
-    #[doc(hidden)]
-    pub const fn from_bytes_with_nul_unwrap(bytes: &[u8]) -> &Self {
-        match Self::from_bytes_with_nul(bytes) {
-            Ok(v) => v,
-            Err(_) => panic!("string contains interior NUL"),
-        }
-    }
-
     /// Creates a [`CStr`] from a `[u8]` without performing any additional
     /// checks.
     ///
@@ -349,7 +337,10 @@ where
 macro_rules! c_str {
     ($str:expr) => {{
         const S: &str = concat!($str, "\0");
-        const C: &$crate::str::CStr = $crate::str::CStr::from_bytes_with_nul_unwrap(S.as_bytes());
+        const C: &$crate::str::CStr = match $crate::str::CStr::from_bytes_with_nul(S.as_bytes()) {
+            Ok(v) => v,
+            Err(_) => panic!("string contains interior NUL"),
+        };
         C
     }};
 }
diff --git a/rust/macros/concat_idents.rs b/rust/macros/concat_idents.rs
index 3b5a9dd70e8a..7e4b450f3a50 100644
--- a/rust/macros/concat_idents.rs
+++ b/rust/macros/concat_idents.rs
@@ -18,6 +18,6 @@ pub(crate) fn concat_idents(ts: TokenStream) -> TokenStream {
     assert_eq!(expect_punct(&mut it), ',');
     let b = expect_ident(&mut it);
     assert!(it.next().is_none(), "only two idents can be concatenated");
-    let res = Ident::new(&(a.to_string() + &b.to_string()), b.span());
+    let res = Ident::new(&format!("{a}{b}"), b.span());
     TokenStream::from_iter([TokenTree::Ident(res)])
 }

Björn Roy Baron (1):
  rust: macros: add `concat_idents!` proc macro

Finn Behrens (1):
  rust: error: declare errors using macro

Gary Guo (9):
  rust: macros: add `#[vtable]` proc macro
  rust: macros: take string literals in `module!`
  rust: str: add `BStr` type
  rust: str: add `b_str!` macro
  rust: str: add `CStr` type
  rust: str: implement several traits for `CStr`
  rust: str: add `c_str!` macro
  rust: add `build_error` crate
  rust: build_assert: add `build_{error,assert}!` macros

Miguel Ojeda (7):
  rust: prelude: split re-exports into groups
  rust: print: add more `pr_*!` levels
  rust: print: add `pr_cont!` macro
  rust: samples: add `rust_print` example
  rust: alloc: add `RawVec::try_with_capacity_in()` constructor
  rust: alloc: add `Vec::try_with_capacity{,_in}()` constructors
  rust: static_assert: add `static_assert!` macro

Milan Landaverde (1):
  rust: str: add `CStr` unit tests

Niklas Mohrin (1):
  rust: std_vendor: add `dbg!` macro based on `std`'s one

Viktor Garske (1):
  rust: error: add codes from `errno-base.h`

Wedson Almeida Filho (7):
  rust: error: add `From` implementations for `Error`
  rust: prelude: add `error::code::*` constant items
  rust: str: add `Formatter` type
  rust: str: add `CString` type
  rust: str: add `fmt!` macro
  rust: types: add `Either` type
  rust: types: add `Opaque` type

 lib/Kconfig.debug                 |  16 +
 rust/Makefile                     |  22 +-
 rust/alloc/raw_vec.rs             |  33 +-
 rust/alloc/vec/mod.rs             |  89 +++++
 rust/build_error.rs               |  31 ++
 rust/exports.c                    |   5 +
 rust/kernel/build_assert.rs       |  82 +++++
 rust/kernel/error.rs              |  90 ++++-
 rust/kernel/lib.rs                |   9 +
 rust/kernel/prelude.rs            |  20 +-
 rust/kernel/print.rs              | 214 +++++++++++-
 rust/kernel/static_assert.rs      |  34 ++
 rust/kernel/std_vendor.rs         | 163 ++++++++++
 rust/kernel/str.rs                | 523 +++++++++++++++++++++++++++++-
 rust/kernel/types.rs              |  37 +++
 rust/macros/concat_idents.rs      |  23 ++
 rust/macros/helpers.rs            |  24 +-
 rust/macros/lib.rs                | 108 +++++-
 rust/macros/module.rs             |  10 +-
 rust/macros/vtable.rs             |  95 ++++++
 samples/rust/Kconfig              |  10 +
 samples/rust/Makefile             |   1 +
 samples/rust/rust_minimal.rs      |   8 +-
 samples/rust/rust_print.rs        |  54 +++
 scripts/generate_rust_analyzer.py |   8 +-
 25 files changed, 1667 insertions(+), 42 deletions(-)
 create mode 100644 rust/build_error.rs
 create mode 100644 rust/kernel/build_assert.rs
 create mode 100644 rust/kernel/static_assert.rs
 create mode 100644 rust/kernel/std_vendor.rs
 create mode 100644 rust/kernel/types.rs
 create mode 100644 rust/macros/concat_idents.rs
 create mode 100644 rust/macros/vtable.rs
 create mode 100644 samples/rust/rust_print.rs


base-commit: f0c4d9fc9cc9462659728d168387191387e903cc
-- 
2.38.1


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

* [PATCH v2 01/28] rust: prelude: split re-exports into groups
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-02 16:14 ` [PATCH v2 02/28] rust: print: add more `pr_*!` levels ojeda
                   ` (27 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches, Wei Liu

From: Miguel Ojeda <ojeda@kernel.org>

Split the prelude re-exports into groups: first the ones coming
from the `core` crate, then `alloc`, then our own crates and
finally the ones from modules from `kernel` itself (i.e. `super`).

We are doing this manually for the moment, but ideally, long-term,
this could be automated via `rustfmt` with options such as
`group_imports` and `imports_granularity` (both currently unstable).

Reviewed-by: Boqun Feng <boqun.feng@gmail.com>
Reviewed-by: Wei Liu <wei.liu@kernel.org>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/prelude.rs | 14 +++++++++-----
 1 file changed, 9 insertions(+), 5 deletions(-)

diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index 495e22250726..f8219285d8c0 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -11,10 +11,14 @@
 //! use kernel::prelude::*;
 //! ```
 
-pub use super::{
-    error::{Error, Result},
-    pr_emerg, pr_info, ThisModule,
-};
-pub use alloc::{boxed::Box, vec::Vec};
 pub use core::pin::Pin;
+
+pub use alloc::{boxed::Box, vec::Vec};
+
 pub use macros::module;
+
+pub use super::{pr_emerg, pr_info};
+
+pub use super::error::{Error, Result};
+
+pub use super::ThisModule;
-- 
2.38.1


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

* [PATCH v2 02/28] rust: print: add more `pr_*!` levels
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
  2022-12-02 16:14 ` [PATCH v2 01/28] rust: prelude: split re-exports into groups ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-02 16:14 ` [PATCH v2 03/28] rust: print: add `pr_cont!` macro ojeda
                   ` (26 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches, Adam Bratschi-Kaye,
	Wei Liu, Sergio Gonzalez Collado

From: Miguel Ojeda <ojeda@kernel.org>

Currently, only `pr_info!` (for the minimal sample) and
`pr_emerg!` (for the panic handler) are there.

Add the other levels as new macros, i.e. `pr_alert!`, `pr_crit!`,
`pr_err!`, `pr_warn!`, `pr_notice!` and `pr_debug!`.

Co-developed-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Signed-off-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Co-developed-by: Wedson Almeida Filho <wedsonaf@gmail.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com>
Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Boqun Feng <boqun.feng@gmail.com>
Reviewed-by: Wei Liu <wei.liu@kernel.org>
Reviewed-by: Sergio Gonzalez Collado <sergio.collado@gmail.com>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/prelude.rs |   2 +-
 rust/kernel/print.rs   | 154 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 155 insertions(+), 1 deletion(-)

diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index f8219285d8c0..6a1c6b38327f 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -17,7 +17,7 @@ pub use alloc::{boxed::Box, vec::Vec};
 
 pub use macros::module;
 
-pub use super::{pr_emerg, pr_info};
+pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};
 
 pub use super::error::{Error, Result};
 
diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs
index 55db5a1ba752..694f51c6da5c 100644
--- a/rust/kernel/print.rs
+++ b/rust/kernel/print.rs
@@ -74,7 +74,13 @@ pub mod format_strings {
     // Furthermore, `static` instead of `const` is used to share the strings
     // for all the kernel.
     pub static EMERG: [u8; LENGTH] = generate(false, bindings::KERN_EMERG);
+    pub static ALERT: [u8; LENGTH] = generate(false, bindings::KERN_ALERT);
+    pub static CRIT: [u8; LENGTH] = generate(false, bindings::KERN_CRIT);
+    pub static ERR: [u8; LENGTH] = generate(false, bindings::KERN_ERR);
+    pub static WARNING: [u8; LENGTH] = generate(false, bindings::KERN_WARNING);
+    pub static NOTICE: [u8; LENGTH] = generate(false, bindings::KERN_NOTICE);
     pub static INFO: [u8; LENGTH] = generate(false, bindings::KERN_INFO);
+    pub static DEBUG: [u8; LENGTH] = generate(false, bindings::KERN_DEBUG);
 }
 
 /// Prints a message via the kernel's [`_printk`].
@@ -172,6 +178,126 @@ macro_rules! pr_emerg (
     )
 );
 
+/// Prints an alert-level message (level 1).
+///
+/// Use this level if action must be taken immediately.
+///
+/// Equivalent to the kernel's [`pr_alert`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// `alloc::format!` for information about the formatting syntax.
+///
+/// [`pr_alert`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_alert
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_alert!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_alert (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::ALERT, $($arg)*)
+    )
+);
+
+/// Prints a critical-level message (level 2).
+///
+/// Use this level for critical conditions.
+///
+/// Equivalent to the kernel's [`pr_crit`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// `alloc::format!` for information about the formatting syntax.
+///
+/// [`pr_crit`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_crit
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_crit!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_crit (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::CRIT, $($arg)*)
+    )
+);
+
+/// Prints an error-level message (level 3).
+///
+/// Use this level for error conditions.
+///
+/// Equivalent to the kernel's [`pr_err`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// `alloc::format!` for information about the formatting syntax.
+///
+/// [`pr_err`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_err
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_err!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_err (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::ERR, $($arg)*)
+    )
+);
+
+/// Prints a warning-level message (level 4).
+///
+/// Use this level for warning conditions.
+///
+/// Equivalent to the kernel's [`pr_warn`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// `alloc::format!` for information about the formatting syntax.
+///
+/// [`pr_warn`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_warn
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_warn!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_warn (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::WARNING, $($arg)*)
+    )
+);
+
+/// Prints a notice-level message (level 5).
+///
+/// Use this level for normal but significant conditions.
+///
+/// Equivalent to the kernel's [`pr_notice`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// `alloc::format!` for information about the formatting syntax.
+///
+/// [`pr_notice`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_notice
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_notice!("hello {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_notice (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::NOTICE, $($arg)*)
+    )
+);
+
 /// Prints an info-level message (level 6).
 ///
 /// Use this level for informational messages.
@@ -196,3 +322,31 @@ macro_rules! pr_info (
         $crate::print_macro!($crate::print::format_strings::INFO, $($arg)*)
     )
 );
+
+/// Prints a debug-level message (level 7).
+///
+/// Use this level for debug messages.
+///
+/// Equivalent to the kernel's [`pr_debug`] macro, except that it doesn't support dynamic debug
+/// yet.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// `alloc::format!` for information about the formatting syntax.
+///
+/// [`pr_debug`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_debug
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// pr_debug!("hello {}\n", "there");
+/// ```
+#[macro_export]
+#[doc(alias = "print")]
+macro_rules! pr_debug (
+    ($($arg:tt)*) => (
+        if cfg!(debug_assertions) {
+            $crate::print_macro!($crate::print::format_strings::DEBUG, $($arg)*)
+        }
+    )
+);
-- 
2.38.1


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

* [PATCH v2 03/28] rust: print: add `pr_cont!` macro
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
  2022-12-02 16:14 ` [PATCH v2 01/28] rust: prelude: split re-exports into groups ojeda
  2022-12-02 16:14 ` [PATCH v2 02/28] rust: print: add more `pr_*!` levels ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-02 16:14 ` [PATCH v2 04/28] rust: samples: add `rust_print` example ojeda
                   ` (25 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches, Adam Bratschi-Kaye,
	Wei Liu, Sergio González Collado

From: Miguel Ojeda <ojeda@kernel.org>

This level is a bit different from the rest since it does not
pass the module name to the `_printk()` call.

Thus add a new parameter to the general `print_macro!` to
handle it differently.

Co-developed-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Signed-off-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Co-developed-by: Wedson Almeida Filho <wedsonaf@gmail.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com>
Co-developed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Wei Liu <wei.liu@kernel.org>
Reviewed-by: Sergio González Collado <sergio.collado@gmail.com>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/print.rs | 72 ++++++++++++++++++++++++++++++++++++++------
 1 file changed, 63 insertions(+), 9 deletions(-)

diff --git a/rust/kernel/print.rs b/rust/kernel/print.rs
index 694f51c6da5c..29bf9c2e8aee 100644
--- a/rust/kernel/print.rs
+++ b/rust/kernel/print.rs
@@ -81,6 +81,7 @@ pub mod format_strings {
     pub static NOTICE: [u8; LENGTH] = generate(false, bindings::KERN_NOTICE);
     pub static INFO: [u8; LENGTH] = generate(false, bindings::KERN_INFO);
     pub static DEBUG: [u8; LENGTH] = generate(false, bindings::KERN_DEBUG);
+    pub static CONT: [u8; LENGTH] = generate(true, bindings::KERN_CONT);
 }
 
 /// Prints a message via the kernel's [`_printk`].
@@ -111,6 +112,26 @@ pub unsafe fn call_printk(
     }
 }
 
+/// Prints a message via the kernel's [`_printk`] for the `CONT` level.
+///
+/// Public but hidden since it should only be used from public macros.
+///
+/// [`_printk`]: ../../../../include/linux/printk.h
+#[doc(hidden)]
+#[cfg_attr(not(CONFIG_PRINTK), allow(unused_variables))]
+pub fn call_printk_cont(args: fmt::Arguments<'_>) {
+    // `_printk` does not seem to fail in any path.
+    //
+    // SAFETY: The format string is fixed.
+    #[cfg(CONFIG_PRINTK)]
+    unsafe {
+        bindings::_printk(
+            format_strings::CONT.as_ptr() as _,
+            &args as *const _ as *const c_void,
+        );
+    }
+}
+
 /// Performs formatting and forwards the string to [`call_printk`].
 ///
 /// Public but hidden since it should only be used from public macros.
@@ -120,7 +141,7 @@ pub unsafe fn call_printk(
 #[allow(clippy::crate_in_macro_def)]
 macro_rules! print_macro (
     // The non-continuation cases (most of them, e.g. `INFO`).
-    ($format_string:path, $($arg:tt)+) => (
+    ($format_string:path, false, $($arg:tt)+) => (
         // SAFETY: This hidden macro should only be called by the documented
         // printing macros which ensure the format string is one of the fixed
         // ones. All `__LOG_PREFIX`s are null-terminated as they are generated
@@ -134,6 +155,13 @@ macro_rules! print_macro (
             );
         }
     );
+
+    // The `CONT` case.
+    ($format_string:path, true, $($arg:tt)+) => (
+        $crate::print::call_printk_cont(
+            format_args!($($arg)+),
+        );
+    );
 );
 
 /// Stub for doctests
@@ -174,7 +202,7 @@ macro_rules! print_macro (
 #[macro_export]
 macro_rules! pr_emerg (
     ($($arg:tt)*) => (
-        $crate::print_macro!($crate::print::format_strings::EMERG, $($arg)*)
+        $crate::print_macro!($crate::print::format_strings::EMERG, false, $($arg)*)
     )
 );
 
@@ -198,7 +226,7 @@ macro_rules! pr_emerg (
 #[macro_export]
 macro_rules! pr_alert (
     ($($arg:tt)*) => (
-        $crate::print_macro!($crate::print::format_strings::ALERT, $($arg)*)
+        $crate::print_macro!($crate::print::format_strings::ALERT, false, $($arg)*)
     )
 );
 
@@ -222,7 +250,7 @@ macro_rules! pr_alert (
 #[macro_export]
 macro_rules! pr_crit (
     ($($arg:tt)*) => (
-        $crate::print_macro!($crate::print::format_strings::CRIT, $($arg)*)
+        $crate::print_macro!($crate::print::format_strings::CRIT, false, $($arg)*)
     )
 );
 
@@ -246,7 +274,7 @@ macro_rules! pr_crit (
 #[macro_export]
 macro_rules! pr_err (
     ($($arg:tt)*) => (
-        $crate::print_macro!($crate::print::format_strings::ERR, $($arg)*)
+        $crate::print_macro!($crate::print::format_strings::ERR, false, $($arg)*)
     )
 );
 
@@ -270,7 +298,7 @@ macro_rules! pr_err (
 #[macro_export]
 macro_rules! pr_warn (
     ($($arg:tt)*) => (
-        $crate::print_macro!($crate::print::format_strings::WARNING, $($arg)*)
+        $crate::print_macro!($crate::print::format_strings::WARNING, false, $($arg)*)
     )
 );
 
@@ -294,7 +322,7 @@ macro_rules! pr_warn (
 #[macro_export]
 macro_rules! pr_notice (
     ($($arg:tt)*) => (
-        $crate::print_macro!($crate::print::format_strings::NOTICE, $($arg)*)
+        $crate::print_macro!($crate::print::format_strings::NOTICE, false, $($arg)*)
     )
 );
 
@@ -319,7 +347,7 @@ macro_rules! pr_notice (
 #[doc(alias = "print")]
 macro_rules! pr_info (
     ($($arg:tt)*) => (
-        $crate::print_macro!($crate::print::format_strings::INFO, $($arg)*)
+        $crate::print_macro!($crate::print::format_strings::INFO, false, $($arg)*)
     )
 );
 
@@ -346,7 +374,33 @@ macro_rules! pr_info (
 macro_rules! pr_debug (
     ($($arg:tt)*) => (
         if cfg!(debug_assertions) {
-            $crate::print_macro!($crate::print::format_strings::DEBUG, $($arg)*)
+            $crate::print_macro!($crate::print::format_strings::DEBUG, false, $($arg)*)
         }
     )
 );
+
+/// Continues a previous log message in the same line.
+///
+/// Use only when continuing a previous `pr_*!` macro (e.g. [`pr_info!`]).
+///
+/// Equivalent to the kernel's [`pr_cont`] macro.
+///
+/// Mimics the interface of [`std::print!`]. See [`core::fmt`] and
+/// `alloc::format!` for information about the formatting syntax.
+///
+/// [`pr_cont`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html#c.pr_cont
+/// [`std::print!`]: https://doc.rust-lang.org/std/macro.print.html
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::pr_cont;
+/// pr_info!("hello");
+/// pr_cont!(" {}\n", "there");
+/// ```
+#[macro_export]
+macro_rules! pr_cont (
+    ($($arg:tt)*) => (
+        $crate::print_macro!($crate::print::format_strings::CONT, true, $($arg)*)
+    )
+);
-- 
2.38.1


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

* [PATCH v2 04/28] rust: samples: add `rust_print` example
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (2 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 03/28] rust: print: add `pr_cont!` macro ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-02 16:14 ` [PATCH v2 05/28] rust: macros: add `concat_idents!` proc macro ojeda
                   ` (24 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches, Finn Behrens, Wei Liu,
	Sergio González Collado

From: Miguel Ojeda <ojeda@kernel.org>

Add example to exercise the printing macros (`pr_*!`) introduced
in the previous patches.

Reviewed-by: Finn Behrens <me@kloenk.dev>
Reviewed-by: Wei Liu <wei.liu@kernel.org>
Tested-by: Sergio González Collado <sergio.collado@gmail.com>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 samples/rust/Kconfig       | 10 +++++++
 samples/rust/Makefile      |  1 +
 samples/rust/rust_print.rs | 54 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 65 insertions(+)
 create mode 100644 samples/rust/rust_print.rs

diff --git a/samples/rust/Kconfig b/samples/rust/Kconfig
index 841e0906e943..b0f74a81c8f9 100644
--- a/samples/rust/Kconfig
+++ b/samples/rust/Kconfig
@@ -20,6 +20,16 @@ config SAMPLE_RUST_MINIMAL
 
 	  If unsure, say N.
 
+config SAMPLE_RUST_PRINT
+	tristate "Printing macros"
+	help
+	  This option builds the Rust printing macros sample.
+
+	  To compile this as a module, choose M here:
+	  the module will be called rust_print.
+
+	  If unsure, say N.
+
 config SAMPLE_RUST_HOSTPROGS
 	bool "Host programs"
 	help
diff --git a/samples/rust/Makefile b/samples/rust/Makefile
index 1daba5f8658a..03086dabbea4 100644
--- a/samples/rust/Makefile
+++ b/samples/rust/Makefile
@@ -1,5 +1,6 @@
 # SPDX-License-Identifier: GPL-2.0
 
 obj-$(CONFIG_SAMPLE_RUST_MINIMAL)		+= rust_minimal.o
+obj-$(CONFIG_SAMPLE_RUST_PRINT)			+= rust_print.o
 
 subdir-$(CONFIG_SAMPLE_RUST_HOSTPROGS)		+= hostprogs
diff --git a/samples/rust/rust_print.rs b/samples/rust/rust_print.rs
new file mode 100644
index 000000000000..09f737790f3f
--- /dev/null
+++ b/samples/rust/rust_print.rs
@@ -0,0 +1,54 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Rust printing macros sample.
+
+use kernel::pr_cont;
+use kernel::prelude::*;
+
+module! {
+    type: RustPrint,
+    name: b"rust_print",
+    author: b"Rust for Linux Contributors",
+    description: b"Rust printing macros sample",
+    license: b"GPL",
+}
+
+struct RustPrint;
+
+impl kernel::Module for RustPrint {
+    fn init(_module: &'static ThisModule) -> Result<Self> {
+        pr_info!("Rust printing macros sample (init)\n");
+
+        pr_emerg!("Emergency message (level 0) without args\n");
+        pr_alert!("Alert message (level 1) without args\n");
+        pr_crit!("Critical message (level 2) without args\n");
+        pr_err!("Error message (level 3) without args\n");
+        pr_warn!("Warning message (level 4) without args\n");
+        pr_notice!("Notice message (level 5) without args\n");
+        pr_info!("Info message (level 6) without args\n");
+
+        pr_info!("A line that");
+        pr_cont!(" is continued");
+        pr_cont!(" without args\n");
+
+        pr_emerg!("{} message (level {}) with args\n", "Emergency", 0);
+        pr_alert!("{} message (level {}) with args\n", "Alert", 1);
+        pr_crit!("{} message (level {}) with args\n", "Critical", 2);
+        pr_err!("{} message (level {}) with args\n", "Error", 3);
+        pr_warn!("{} message (level {}) with args\n", "Warning", 4);
+        pr_notice!("{} message (level {}) with args\n", "Notice", 5);
+        pr_info!("{} message (level {}) with args\n", "Info", 6);
+
+        pr_info!("A {} that", "line");
+        pr_cont!(" is {}", "continued");
+        pr_cont!(" with {}\n", "args");
+
+        Ok(RustPrint)
+    }
+}
+
+impl Drop for RustPrint {
+    fn drop(&mut self) {
+        pr_info!("Rust printing macros sample (exit)\n");
+    }
+}
-- 
2.38.1


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

* [PATCH v2 05/28] rust: macros: add `concat_idents!` proc macro
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (3 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 04/28] rust: samples: add `rust_print` example ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-04  0:20   ` Gary Guo
  2022-12-02 16:14 ` [PATCH v2 06/28] rust: macros: add `#[vtable]` " ojeda
                   ` (23 subsequent siblings)
  28 siblings, 1 reply; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches, Finn Behrens

From: Björn Roy Baron <bjorn3_gh@protonmail.com>

This macro provides similar functionality to the unstable feature
`concat_idents` without having to rely on it.

For instance:

    let x_1 = 42;
    let x_2 = concat_idents!(x, _1);
    assert!(x_1 == x_2);

It has different behavior with respect to macro hygiene. Unlike
the unstable `concat_idents!` macro, it allows, for example,
referring to local variables by taking the span of the second
macro as span for the output identifier.

Signed-off-by: Björn Roy Baron <bjorn3_gh@protonmail.com>
Reviewed-by: Finn Behrens <me@kloenk.dev>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/macros/concat_idents.rs | 23 +++++++++++++++++++
 rust/macros/lib.rs           | 44 ++++++++++++++++++++++++++++++++++++
 2 files changed, 67 insertions(+)
 create mode 100644 rust/macros/concat_idents.rs

diff --git a/rust/macros/concat_idents.rs b/rust/macros/concat_idents.rs
new file mode 100644
index 000000000000..7e4b450f3a50
--- /dev/null
+++ b/rust/macros/concat_idents.rs
@@ -0,0 +1,23 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use proc_macro::{token_stream, Ident, TokenStream, TokenTree};
+
+use crate::helpers::expect_punct;
+
+fn expect_ident(it: &mut token_stream::IntoIter) -> Ident {
+    if let Some(TokenTree::Ident(ident)) = it.next() {
+        ident
+    } else {
+        panic!("Expected Ident")
+    }
+}
+
+pub(crate) fn concat_idents(ts: TokenStream) -> TokenStream {
+    let mut it = ts.into_iter();
+    let a = expect_ident(&mut it);
+    assert_eq!(expect_punct(&mut it), ',');
+    let b = expect_ident(&mut it);
+    assert!(it.next().is_none(), "only two idents can be concatenated");
+    let res = Ident::new(&format!("{a}{b}"), b.span());
+    TokenStream::from_iter([TokenTree::Ident(res)])
+}
diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
index 91764bfb1f89..15555e7ff487 100644
--- a/rust/macros/lib.rs
+++ b/rust/macros/lib.rs
@@ -2,6 +2,7 @@
 
 //! Crate for all kernel procedural macros.
 
+mod concat_idents;
 mod helpers;
 mod module;
 
@@ -70,3 +71,46 @@ use proc_macro::TokenStream;
 pub fn module(ts: TokenStream) -> TokenStream {
     module::module(ts)
 }
+
+/// Concatenate two identifiers.
+///
+/// This is useful in macros that need to declare or reference items with names
+/// starting with a fixed prefix and ending in a user specified name. The resulting
+/// identifier has the span of the second argument.
+///
+/// # Examples
+///
+/// ```ignore
+/// use kernel::macro::concat_idents;
+///
+/// macro_rules! pub_no_prefix {
+///     ($prefix:ident, $($newname:ident),+) => {
+///         $(pub(crate) const $newname: u32 = kernel::macros::concat_idents!($prefix, $newname);)+
+///     };
+/// }
+///
+/// pub_no_prefix!(
+///     binder_driver_return_protocol_,
+///     BR_OK,
+///     BR_ERROR,
+///     BR_TRANSACTION,
+///     BR_REPLY,
+///     BR_DEAD_REPLY,
+///     BR_TRANSACTION_COMPLETE,
+///     BR_INCREFS,
+///     BR_ACQUIRE,
+///     BR_RELEASE,
+///     BR_DECREFS,
+///     BR_NOOP,
+///     BR_SPAWN_LOOPER,
+///     BR_DEAD_BINDER,
+///     BR_CLEAR_DEATH_NOTIFICATION_DONE,
+///     BR_FAILED_REPLY
+/// );
+///
+/// assert_eq!(BR_OK, binder_driver_return_protocol_BR_OK);
+/// ```
+#[proc_macro]
+pub fn concat_idents(ts: TokenStream) -> TokenStream {
+    concat_idents::concat_idents(ts)
+}
-- 
2.38.1


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

* [PATCH v2 06/28] rust: macros: add `#[vtable]` proc macro
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (4 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 05/28] rust: macros: add `concat_idents!` proc macro ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-06 12:49   ` Finn Behrens
  2022-12-02 16:14 ` [PATCH v2 07/28] rust: macros: take string literals in `module!` ojeda
                   ` (22 subsequent siblings)
  28 siblings, 1 reply; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches, Sergio González Collado

From: Gary Guo <gary@garyguo.net>

This procedural macro attribute provides a simple way to declare
a trait with a set of operations that later users can partially
implement, providing compile-time `HAS_*` boolean associated
constants that indicate whether a particular operation was overridden.

This is useful as the Rust counterpart to structs like
`file_operations` where some pointers may be `NULL`, indicating
an operation is not provided.

For instance:

    #[vtable]
    trait Operations {
        fn read(...) -> Result<usize> {
            Err(EINVAL)
        }

        fn write(...) -> Result<usize> {
            Err(EINVAL)
        }
    }

    #[vtable]
    impl Operations for S {
        fn read(...) -> Result<usize> {
            ...
        }
    }

    assert_eq!(<S as Operations>::HAS_READ, true);
    assert_eq!(<S as Operations>::HAS_WRITE, false);

Signed-off-by: Gary Guo <gary@garyguo.net>
Reviewed-by: Sergio González Collado <sergio.collado@gmail.com>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/prelude.rs |  2 +-
 rust/macros/lib.rs     | 52 +++++++++++++++++++++++
 rust/macros/vtable.rs  | 95 ++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 148 insertions(+), 1 deletion(-)
 create mode 100644 rust/macros/vtable.rs

diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index 6a1c6b38327f..7c4c35bf3c66 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -15,7 +15,7 @@ pub use core::pin::Pin;
 
 pub use alloc::{boxed::Box, vec::Vec};
 
-pub use macros::module;
+pub use macros::{module, vtable};
 
 pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};
 
diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
index 15555e7ff487..e40caaf0a656 100644
--- a/rust/macros/lib.rs
+++ b/rust/macros/lib.rs
@@ -5,6 +5,7 @@
 mod concat_idents;
 mod helpers;
 mod module;
+mod vtable;
 
 use proc_macro::TokenStream;
 
@@ -72,6 +73,57 @@ pub fn module(ts: TokenStream) -> TokenStream {
     module::module(ts)
 }
 
+/// Declares or implements a vtable trait.
+///
+/// Linux's use of pure vtables is very close to Rust traits, but they differ
+/// in how unimplemented functions are represented. In Rust, traits can provide
+/// default implementation for all non-required methods (and the default
+/// implementation could just return `Error::EINVAL`); Linux typically use C
+/// `NULL` pointers to represent these functions.
+///
+/// This attribute is intended to close the gap. Traits can be declared and
+/// implemented with the `#[vtable]` attribute, and a `HAS_*` associated constant
+/// will be generated for each method in the trait, indicating if the implementor
+/// has overridden a method.
+///
+/// This attribute is not needed if all methods are required.
+///
+/// # Examples
+///
+/// ```ignore
+/// use kernel::prelude::*;
+///
+/// // Declares a `#[vtable]` trait
+/// #[vtable]
+/// pub trait Operations: Send + Sync + Sized {
+///     fn foo(&self) -> Result<()> {
+///         Err(EINVAL)
+///     }
+///
+///     fn bar(&self) -> Result<()> {
+///         Err(EINVAL)
+///     }
+/// }
+///
+/// struct Foo;
+///
+/// // Implements the `#[vtable]` trait
+/// #[vtable]
+/// impl Operations for Foo {
+///     fn foo(&self) -> Result<()> {
+/// #        Err(EINVAL)
+///         // ...
+///     }
+/// }
+///
+/// assert_eq!(<Foo as Operations>::HAS_FOO, true);
+/// assert_eq!(<Foo as Operations>::HAS_BAR, false);
+/// ```
+#[proc_macro_attribute]
+pub fn vtable(attr: TokenStream, ts: TokenStream) -> TokenStream {
+    vtable::vtable(attr, ts)
+}
+
 /// Concatenate two identifiers.
 ///
 /// This is useful in macros that need to declare or reference items with names
diff --git a/rust/macros/vtable.rs b/rust/macros/vtable.rs
new file mode 100644
index 000000000000..34d5e7fb5768
--- /dev/null
+++ b/rust/macros/vtable.rs
@@ -0,0 +1,95 @@
+// SPDX-License-Identifier: GPL-2.0
+
+use proc_macro::{Delimiter, Group, TokenStream, TokenTree};
+use std::collections::HashSet;
+use std::fmt::Write;
+
+pub(crate) fn vtable(_attr: TokenStream, ts: TokenStream) -> TokenStream {
+    let mut tokens: Vec<_> = ts.into_iter().collect();
+
+    // Scan for the `trait` or `impl` keyword.
+    let is_trait = tokens
+        .iter()
+        .find_map(|token| match token {
+            TokenTree::Ident(ident) => match ident.to_string().as_str() {
+                "trait" => Some(true),
+                "impl" => Some(false),
+                _ => None,
+            },
+            _ => None,
+        })
+        .expect("#[vtable] attribute should only be applied to trait or impl block");
+
+    // Retrieve the main body. The main body should be the last token tree.
+    let body = match tokens.pop() {
+        Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => group,
+        _ => panic!("cannot locate main body of trait or impl block"),
+    };
+
+    let mut body_it = body.stream().into_iter();
+    let mut functions = Vec::new();
+    let mut consts = HashSet::new();
+    while let Some(token) = body_it.next() {
+        match token {
+            TokenTree::Ident(ident) if ident.to_string() == "fn" => {
+                let fn_name = match body_it.next() {
+                    Some(TokenTree::Ident(ident)) => ident.to_string(),
+                    // Possibly we've encountered a fn pointer type instead.
+                    _ => continue,
+                };
+                functions.push(fn_name);
+            }
+            TokenTree::Ident(ident) if ident.to_string() == "const" => {
+                let const_name = match body_it.next() {
+                    Some(TokenTree::Ident(ident)) => ident.to_string(),
+                    // Possibly we've encountered an inline const block instead.
+                    _ => continue,
+                };
+                consts.insert(const_name);
+            }
+            _ => (),
+        }
+    }
+
+    let mut const_items;
+    if is_trait {
+        const_items = "
+                /// A marker to prevent implementors from forgetting to use [`#[vtable]`](vtable)
+                /// attribute when implementing this trait.
+                const USE_VTABLE_ATTR: ();
+        "
+        .to_owned();
+
+        for f in functions {
+            let gen_const_name = format!("HAS_{}", f.to_uppercase());
+            // Skip if it's declared already -- this allows user override.
+            if consts.contains(&gen_const_name) {
+                continue;
+            }
+            // We don't know on the implementation-site whether a method is required or provided
+            // so we have to generate a const for all methods.
+            write!(
+                const_items,
+                "/// Indicates if the `{f}` method is overridden by the implementor.
+                const {gen_const_name}: bool = false;",
+            )
+            .unwrap();
+        }
+    } else {
+        const_items = "const USE_VTABLE_ATTR: () = ();".to_owned();
+
+        for f in functions {
+            let gen_const_name = format!("HAS_{}", f.to_uppercase());
+            if consts.contains(&gen_const_name) {
+                continue;
+            }
+            write!(const_items, "const {gen_const_name}: bool = true;").unwrap();
+        }
+    }
+
+    let new_body = vec![const_items.parse().unwrap(), body.stream()]
+        .into_iter()
+        .collect();
+    tokens.push(TokenTree::Group(Group::new(Delimiter::Brace, new_body)));
+    tokens.into_iter().collect()
+}
-- 
2.38.1


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

* [PATCH v2 07/28] rust: macros: take string literals in `module!`
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (5 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 06/28] rust: macros: add `#[vtable]` " ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-02 16:14 ` [PATCH v2 08/28] rust: error: declare errors using macro ojeda
                   ` (21 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches

From: Gary Guo <gary@garyguo.net>

Instead of taking binary string literals, take string ones instead,
making it easier for users to define a module, i.e. instead of
calling `module!` like:

    module! {
        ...
        name: b"rust_minimal",
        ...
    }

now it is called as:

    module! {
        ...
        name: "rust_minimal",
        ...
    }

Module names, aliases and license strings are restricted to
ASCII only. However, the author and the description allows UTF-8.

For simplicity (avoid parsing), escape sequences and raw string
literals are not yet handled.

Link: https://github.com/Rust-for-Linux/linux/issues/252
Link: https://lore.kernel.org/lkml/YukvvPOOu8uZl7+n@yadro.com/
Signed-off-by: Gary Guo <gary@garyguo.net>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/macros/helpers.rs       | 24 ++++++++++++++++++------
 rust/macros/lib.rs           | 12 ++++++------
 rust/macros/module.rs        | 10 +++++-----
 samples/rust/rust_minimal.rs |  8 ++++----
 samples/rust/rust_print.rs   |  8 ++++----
 5 files changed, 37 insertions(+), 25 deletions(-)

diff --git a/rust/macros/helpers.rs b/rust/macros/helpers.rs
index cdc7dc6135d2..cf7ad950dc1e 100644
--- a/rust/macros/helpers.rs
+++ b/rust/macros/helpers.rs
@@ -18,10 +18,16 @@ pub(crate) fn try_literal(it: &mut token_stream::IntoIter) -> Option<String> {
     }
 }
 
-pub(crate) fn try_byte_string(it: &mut token_stream::IntoIter) -> Option<String> {
-    try_literal(it).and_then(|byte_string| {
-        if byte_string.starts_with("b\"") && byte_string.ends_with('\"') {
-            Some(byte_string[2..byte_string.len() - 1].to_string())
+pub(crate) fn try_string(it: &mut token_stream::IntoIter) -> Option<String> {
+    try_literal(it).and_then(|string| {
+        if string.starts_with('\"') && string.ends_with('\"') {
+            let content = &string[1..string.len() - 1];
+            if content.contains('\\') {
+                panic!("Escape sequences in string literals not yet handled");
+            }
+            Some(content.to_string())
+        } else if string.starts_with("r\"") {
+            panic!("Raw string literals are not yet handled");
         } else {
             None
         }
@@ -40,8 +46,14 @@ pub(crate) fn expect_punct(it: &mut token_stream::IntoIter) -> char {
     }
 }
 
-pub(crate) fn expect_byte_string(it: &mut token_stream::IntoIter) -> String {
-    try_byte_string(it).expect("Expected byte string")
+pub(crate) fn expect_string(it: &mut token_stream::IntoIter) -> String {
+    try_string(it).expect("Expected string")
+}
+
+pub(crate) fn expect_string_ascii(it: &mut token_stream::IntoIter) -> String {
+    let string = try_string(it).expect("Expected string");
+    assert!(string.is_ascii(), "Expected ASCII string");
+    string
 }
 
 pub(crate) fn expect_end(it: &mut token_stream::IntoIter) {
diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
index e40caaf0a656..c1d385e345b9 100644
--- a/rust/macros/lib.rs
+++ b/rust/macros/lib.rs
@@ -25,20 +25,20 @@ use proc_macro::TokenStream;
 ///
 /// module!{
 ///     type: MyModule,
-///     name: b"my_kernel_module",
-///     author: b"Rust for Linux Contributors",
-///     description: b"My very own kernel module!",
-///     license: b"GPL",
+///     name: "my_kernel_module",
+///     author: "Rust for Linux Contributors",
+///     description: "My very own kernel module!",
+///     license: "GPL",
 ///     params: {
 ///        my_i32: i32 {
 ///            default: 42,
 ///            permissions: 0o000,
-///            description: b"Example of i32",
+///            description: "Example of i32",
 ///        },
 ///        writeable_i32: i32 {
 ///            default: 42,
 ///            permissions: 0o644,
-///            description: b"Example of i32",
+///            description: "Example of i32",
 ///        },
 ///    },
 /// }
diff --git a/rust/macros/module.rs b/rust/macros/module.rs
index 186a5b8be23c..a7e363c2b044 100644
--- a/rust/macros/module.rs
+++ b/rust/macros/module.rs
@@ -108,11 +108,11 @@ impl ModuleInfo {
 
             match key.as_str() {
                 "type" => info.type_ = expect_ident(it),
-                "name" => info.name = expect_byte_string(it),
-                "author" => info.author = Some(expect_byte_string(it)),
-                "description" => info.description = Some(expect_byte_string(it)),
-                "license" => info.license = expect_byte_string(it),
-                "alias" => info.alias = Some(expect_byte_string(it)),
+                "name" => info.name = expect_string_ascii(it),
+                "author" => info.author = Some(expect_string(it)),
+                "description" => info.description = Some(expect_string(it)),
+                "license" => info.license = expect_string_ascii(it),
+                "alias" => info.alias = Some(expect_string_ascii(it)),
                 _ => panic!(
                     "Unknown key \"{}\". Valid keys are: {:?}.",
                     key, EXPECTED_KEYS
diff --git a/samples/rust/rust_minimal.rs b/samples/rust/rust_minimal.rs
index 54ad17685742..dc05f4bbe27e 100644
--- a/samples/rust/rust_minimal.rs
+++ b/samples/rust/rust_minimal.rs
@@ -6,10 +6,10 @@ use kernel::prelude::*;
 
 module! {
     type: RustMinimal,
-    name: b"rust_minimal",
-    author: b"Rust for Linux Contributors",
-    description: b"Rust minimal sample",
-    license: b"GPL",
+    name: "rust_minimal",
+    author: "Rust for Linux Contributors",
+    description: "Rust minimal sample",
+    license: "GPL",
 }
 
 struct RustMinimal {
diff --git a/samples/rust/rust_print.rs b/samples/rust/rust_print.rs
index 09f737790f3f..8b39d9cef6d1 100644
--- a/samples/rust/rust_print.rs
+++ b/samples/rust/rust_print.rs
@@ -7,10 +7,10 @@ use kernel::prelude::*;
 
 module! {
     type: RustPrint,
-    name: b"rust_print",
-    author: b"Rust for Linux Contributors",
-    description: b"Rust printing macros sample",
-    license: b"GPL",
+    name: "rust_print",
+    author: "Rust for Linux Contributors",
+    description: "Rust printing macros sample",
+    license: "GPL",
 }
 
 struct RustPrint;
-- 
2.38.1


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

* [PATCH v2 08/28] rust: error: declare errors using macro
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (6 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 07/28] rust: macros: take string literals in `module!` ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-02 16:14 ` [PATCH v2 09/28] rust: error: add codes from `errno-base.h` ojeda
                   ` (20 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches, Finn Behrens

From: Finn Behrens <me@kloenk.dev>

Add a macro to declare errors, which simplifies the work needed to
add each one, avoids repetition of the code and makes it easier to
change the way they are declared.

Signed-off-by: Finn Behrens <me@kloenk.dev>
Reviewed-by: Gary Guo <gary@garyguo.net>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/error.rs | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index 466b2a8fe569..b843f3445483 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -8,8 +8,16 @@ use alloc::collections::TryReserveError;
 
 /// Contains the C-compatible error codes.
 pub mod code {
-    /// Out of memory.
-    pub const ENOMEM: super::Error = super::Error(-(crate::bindings::ENOMEM as i32));
+    macro_rules! declare_err {
+        ($err:tt $(,)? $($doc:expr),+) => {
+            $(
+            #[doc = $doc]
+            )*
+            pub const $err: super::Error = super::Error(-(crate::bindings::$err as i32));
+        };
+    }
+
+    declare_err!(ENOMEM, "Out of memory.");
 }
 
 /// Generic integer kernel error.
-- 
2.38.1


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

* [PATCH v2 09/28] rust: error: add codes from `errno-base.h`
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (7 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 08/28] rust: error: declare errors using macro ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-06 12:52   ` Finn Behrens
  2022-12-02 16:14 ` [PATCH v2 10/28] rust: error: add `From` implementations for `Error` ojeda
                   ` (19 subsequent siblings)
  28 siblings, 1 reply; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches, Viktor Garske

From: Viktor Garske <viktor@v-gar.de>

Only a few codes were added so far. With the `declare_err!`
macro in place, add the remaining ones (which is most of them)
from `include/uapi/asm-generic/errno-base.h`.

Co-developed-by: Wedson Almeida Filho <wedsonaf@gmail.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com>
Signed-off-by: Viktor Garske <viktor@v-gar.de>
Reviewed-by: Gary Guo <gary@garyguo.net>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/error.rs | 33 +++++++++++++++++++++++++++++++++
 1 file changed, 33 insertions(+)

diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index b843f3445483..861746f2422d 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -17,7 +17,40 @@ pub mod code {
         };
     }
 
+    declare_err!(EPERM, "Operation not permitted.");
+    declare_err!(ENOENT, "No such file or directory.");
+    declare_err!(ESRCH, "No such process.");
+    declare_err!(EINTR, "Interrupted system call.");
+    declare_err!(EIO, "I/O error.");
+    declare_err!(ENXIO, "No such device or address.");
+    declare_err!(E2BIG, "Argument list too long.");
+    declare_err!(ENOEXEC, "Exec format error.");
+    declare_err!(EBADF, "Bad file number.");
+    declare_err!(ECHILD, "Exec format error.");
+    declare_err!(EAGAIN, "Try again.");
     declare_err!(ENOMEM, "Out of memory.");
+    declare_err!(EACCES, "Permission denied.");
+    declare_err!(EFAULT, "Bad address.");
+    declare_err!(ENOTBLK, "Block device required.");
+    declare_err!(EBUSY, "Device or resource busy.");
+    declare_err!(EEXIST, "File exists.");
+    declare_err!(EXDEV, "Cross-device link.");
+    declare_err!(ENODEV, "No such device.");
+    declare_err!(ENOTDIR, "Not a directory.");
+    declare_err!(EISDIR, "Is a directory.");
+    declare_err!(EINVAL, "Invalid argument.");
+    declare_err!(ENFILE, "File table overflow.");
+    declare_err!(EMFILE, "Too many open files.");
+    declare_err!(ENOTTY, "Not a typewriter.");
+    declare_err!(ETXTBSY, "Text file busy.");
+    declare_err!(EFBIG, "File too large.");
+    declare_err!(ENOSPC, "No space left on device.");
+    declare_err!(ESPIPE, "Illegal seek.");
+    declare_err!(EROFS, "Read-only file system.");
+    declare_err!(EMLINK, "Too many links.");
+    declare_err!(EPIPE, "Broken pipe.");
+    declare_err!(EDOM, "Math argument out of domain of func.");
+    declare_err!(ERANGE, "Math result not representable.");
 }
 
 /// Generic integer kernel error.
-- 
2.38.1


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

* [PATCH v2 10/28] rust: error: add `From` implementations for `Error`
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (8 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 09/28] rust: error: add codes from `errno-base.h` ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-02 16:14 ` [PATCH v2 11/28] rust: prelude: add `error::code::*` constant items ojeda
                   ` (18 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches, Adam Bratschi-Kaye,
	Nándor István Krácser, Finn Behrens

From: Wedson Almeida Filho <wedsonaf@gmail.com>

Add a set of `From` implementations for the `Error` kernel type.

These implementations allow to easily convert from standard Rust
error types to the usual kernel errors based on one of the `E*`
integer codes.

On top of that, the question mark Rust operator (`?`) implicitly
performs a conversion on the error value using the `From` trait
when propagating. Thus it is extra convenient to use.

For instance, a kernel function that needs to convert a `i64` into
a `i32` and to bubble up the error as a kernel error may write:

    fn f(x: i64) -> Result<...> {
        ...
        let y = i32::try_from(x)?;
        ...
    }

which will transform the `TryFromIntError` into an `Err(EINVAL)`.

Co-developed-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Signed-off-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Co-developed-by: Nándor István Krácser <bonifaido@gmail.com>
Signed-off-by: Nándor István Krácser <bonifaido@gmail.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com>
Reviewed-by: Finn Behrens <me@kloenk.dev>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/error.rs | 45 +++++++++++++++++++++++++++++++++++++++++++-
 rust/kernel/lib.rs   |  1 +
 2 files changed, 45 insertions(+), 1 deletion(-)

diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
index 861746f2422d..5b9751d7ff1d 100644
--- a/rust/kernel/error.rs
+++ b/rust/kernel/error.rs
@@ -4,7 +4,14 @@
 //!
 //! C header: [`include/uapi/asm-generic/errno-base.h`](../../../include/uapi/asm-generic/errno-base.h)
 
-use alloc::collections::TryReserveError;
+use alloc::{
+    alloc::{AllocError, LayoutError},
+    collections::TryReserveError,
+};
+
+use core::convert::From;
+use core::num::TryFromIntError;
+use core::str::Utf8Error;
 
 /// Contains the C-compatible error codes.
 pub mod code {
@@ -71,12 +78,48 @@ impl Error {
     }
 }
 
+impl From<AllocError> for Error {
+    fn from(_: AllocError) -> Error {
+        code::ENOMEM
+    }
+}
+
+impl From<TryFromIntError> for Error {
+    fn from(_: TryFromIntError) -> Error {
+        code::EINVAL
+    }
+}
+
+impl From<Utf8Error> for Error {
+    fn from(_: Utf8Error) -> Error {
+        code::EINVAL
+    }
+}
+
 impl From<TryReserveError> for Error {
     fn from(_: TryReserveError) -> Error {
         code::ENOMEM
     }
 }
 
+impl From<LayoutError> for Error {
+    fn from(_: LayoutError) -> Error {
+        code::ENOMEM
+    }
+}
+
+impl From<core::fmt::Error> for Error {
+    fn from(_: core::fmt::Error) -> Error {
+        code::EINVAL
+    }
+}
+
+impl From<core::convert::Infallible> for Error {
+    fn from(e: core::convert::Infallible) -> Error {
+        match e {}
+    }
+}
+
 /// A [`Result`] with an [`Error`] error type.
 ///
 /// To be used as the return type for functions that may fail.
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index abd46261d385..ffc6626a6d29 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -12,6 +12,7 @@
 //! do so first instead of bypassing this crate.
 
 #![no_std]
+#![feature(allocator_api)]
 #![feature(core_ffi_c)]
 
 // Ensure conditional compilation based on the kernel configuration works;
-- 
2.38.1


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

* [PATCH v2 11/28] rust: prelude: add `error::code::*` constant items
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (9 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 10/28] rust: error: add `From` implementations for `Error` ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-02 16:14 ` [PATCH v2 12/28] rust: alloc: add `RawVec::try_with_capacity_in()` constructor ojeda
                   ` (17 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches

From: Wedson Almeida Filho <wedsonaf@gmail.com>

It is convenient to have all the `Error` constant items (such as
`EINVAL`) available as-is everywhere (i.e. for code using the kernel
prelude such as kernel modules).

Therefore, add all of them to the prelude.

For instance, this allows to write `Err(EINVAL)` to create
a kernel `Result`:

    fn f() -> Result<...> {
        ...
        Err(EINVAL)
    }

Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com>
Reviewed-by: Gary Guo <gary@garyguo.net>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/prelude.rs | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index 7c4c35bf3c66..1e08b08e9420 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -19,6 +19,6 @@ pub use macros::{module, vtable};
 
 pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};
 
-pub use super::error::{Error, Result};
+pub use super::error::{code::*, Error, Result};
 
 pub use super::ThisModule;
-- 
2.38.1


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

* [PATCH v2 12/28] rust: alloc: add `RawVec::try_with_capacity_in()` constructor
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (10 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 11/28] rust: prelude: add `error::code::*` constant items ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-02 16:14 ` [PATCH v2 13/28] rust: alloc: add `Vec::try_with_capacity{,_in}()` constructors ojeda
                   ` (16 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches

From: Miguel Ojeda <ojeda@kernel.org>

Add the `RawVec::try_with_capacity_in()` constructor as the fallible
version of `RawVec::with_capacity_in()`.

The implementation follows the original.

The infallible constructor is implemented in terms of the private
`RawVec::allocate_in()` constructor, thus also add the private
`RawVec::try_allocate_in()` constructor following the other.

It will be used to implement `Vec::try_with_capacity{,_in}()` in
the next patch.

Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/alloc/raw_vec.rs | 34 +++++++++++++++++++++++++++++++++-
 1 file changed, 33 insertions(+), 1 deletion(-)

diff --git a/rust/alloc/raw_vec.rs b/rust/alloc/raw_vec.rs
index daf5f2da7168..c342f3843972 100644
--- a/rust/alloc/raw_vec.rs
+++ b/rust/alloc/raw_vec.rs
@@ -20,11 +20,11 @@ use crate::collections::TryReserveErrorKind::*;
 #[cfg(test)]
 mod tests;
 
-#[cfg(not(no_global_oom_handling))]
 enum AllocInit {
     /// The contents of the new memory are uninitialized.
     Uninitialized,
     /// The new memory is guaranteed to be zeroed.
+    #[allow(dead_code)]
     Zeroed,
 }
 
@@ -133,6 +133,14 @@ impl<T, A: Allocator> RawVec<T, A> {
         Self::allocate_in(capacity, AllocInit::Uninitialized, alloc)
     }
 
+    /// Like `try_with_capacity`, but parameterized over the choice of
+    /// allocator for the returned `RawVec`.
+    #[allow(dead_code)]
+    #[inline]
+    pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<Self, TryReserveError> {
+        Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc)
+    }
+
     /// Like `with_capacity_zeroed`, but parameterized over the choice
     /// of allocator for the returned `RawVec`.
     #[cfg(not(no_global_oom_handling))]
@@ -203,6 +211,30 @@ impl<T, A: Allocator> RawVec<T, A> {
         }
     }
 
+    fn try_allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Result<Self, TryReserveError> {
+        // Don't allocate here because `Drop` will not deallocate when `capacity` is 0.
+        if mem::size_of::<T>() == 0 || capacity == 0 {
+            return Ok(Self::new_in(alloc));
+        }
+
+        let layout = Layout::array::<T>(capacity).map_err(|_| CapacityOverflow)?;
+        alloc_guard(layout.size())?;
+        let result = match init {
+            AllocInit::Uninitialized => alloc.allocate(layout),
+            AllocInit::Zeroed => alloc.allocate_zeroed(layout),
+        };
+        let ptr = result.map_err(|_| AllocError { layout, non_exhaustive: () })?;
+
+        // Allocators currently return a `NonNull<[u8]>` whose length
+        // matches the size requested. If that ever changes, the capacity
+        // here should change to `ptr.len() / mem::size_of::<T>()`.
+        Ok(Self {
+            ptr: unsafe { Unique::new_unchecked(ptr.cast().as_ptr()) },
+            cap: capacity,
+            alloc,
+        })
+    }
+
     /// Reconstitutes a `RawVec` from a pointer, capacity, and allocator.
     ///
     /// # Safety
-- 
2.38.1


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

* [PATCH v2 13/28] rust: alloc: add `Vec::try_with_capacity{,_in}()` constructors
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (11 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 12/28] rust: alloc: add `RawVec::try_with_capacity_in()` constructor ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-06 12:55   ` Finn Behrens
  2022-12-02 16:14 ` [PATCH v2 14/28] rust: str: add `BStr` type ojeda
                   ` (15 subsequent siblings)
  28 siblings, 1 reply; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches

From: Miguel Ojeda <ojeda@kernel.org>

Add `Vec::try_with_capacity()` and `Vec::try_with_capacity_in()` as
the fallible versions of `Vec::with_capacity()` and
`Vec::with_capacity_in()`, respectively.

The implementations follow the originals and use the previously
added `RawVec::try_with_capacity_in()`.

In turn, `Vec::try_with_capacity()` will be used to implement
the `CString` type (which wraps a `Vec<u8>`) in a later patch.

Reviewed-by: Gary Guo <gary@garyguo.net>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/alloc/raw_vec.rs |  1 -
 rust/alloc/vec/mod.rs | 89 +++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 89 insertions(+), 1 deletion(-)

diff --git a/rust/alloc/raw_vec.rs b/rust/alloc/raw_vec.rs
index c342f3843972..eb77db5def55 100644
--- a/rust/alloc/raw_vec.rs
+++ b/rust/alloc/raw_vec.rs
@@ -135,7 +135,6 @@ impl<T, A: Allocator> RawVec<T, A> {
 
     /// Like `try_with_capacity`, but parameterized over the choice of
     /// allocator for the returned `RawVec`.
-    #[allow(dead_code)]
     #[inline]
     pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<Self, TryReserveError> {
         Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc)
diff --git a/rust/alloc/vec/mod.rs b/rust/alloc/vec/mod.rs
index 540787804cc2..8ac6c1e3b2a8 100644
--- a/rust/alloc/vec/mod.rs
+++ b/rust/alloc/vec/mod.rs
@@ -472,6 +472,48 @@ impl<T> Vec<T> {
         Self::with_capacity_in(capacity, Global)
     }
 
+    /// Tries to construct a new, empty `Vec<T>` with the specified capacity.
+    ///
+    /// The vector will be able to hold exactly `capacity` elements without
+    /// reallocating. If `capacity` is 0, the vector will not allocate.
+    ///
+    /// It is important to note that although the returned vector has the
+    /// *capacity* specified, the vector will have a zero *length*. For an
+    /// explanation of the difference between length and capacity, see
+    /// *[Capacity and reallocation]*.
+    ///
+    /// [Capacity and reallocation]: #capacity-and-reallocation
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// let mut vec = Vec::try_with_capacity(10).unwrap();
+    ///
+    /// // The vector contains no items, even though it has capacity for more
+    /// assert_eq!(vec.len(), 0);
+    /// assert_eq!(vec.capacity(), 10);
+    ///
+    /// // These are all done without reallocating...
+    /// for i in 0..10 {
+    ///     vec.push(i);
+    /// }
+    /// assert_eq!(vec.len(), 10);
+    /// assert_eq!(vec.capacity(), 10);
+    ///
+    /// // ...but this may make the vector reallocate
+    /// vec.push(11);
+    /// assert_eq!(vec.len(), 11);
+    /// assert!(vec.capacity() >= 11);
+    ///
+    /// let mut result = Vec::try_with_capacity(usize::MAX);
+    /// assert!(result.is_err());
+    /// ```
+    #[inline]
+    #[stable(feature = "kernel", since = "1.0.0")]
+    pub fn try_with_capacity(capacity: usize) -> Result<Self, TryReserveError> {
+        Self::try_with_capacity_in(capacity, Global)
+    }
+
     /// Creates a `Vec<T>` directly from the raw components of another vector.
     ///
     /// # Safety
@@ -617,6 +659,53 @@ impl<T, A: Allocator> Vec<T, A> {
         Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 }
     }
 
+    /// Tries to construct a new, empty `Vec<T, A>` with the specified capacity
+    /// with the provided allocator.
+    ///
+    /// The vector will be able to hold exactly `capacity` elements without
+    /// reallocating. If `capacity` is 0, the vector will not allocate.
+    ///
+    /// It is important to note that although the returned vector has the
+    /// *capacity* specified, the vector will have a zero *length*. For an
+    /// explanation of the difference between length and capacity, see
+    /// *[Capacity and reallocation]*.
+    ///
+    /// [Capacity and reallocation]: #capacity-and-reallocation
+    ///
+    /// # Examples
+    ///
+    /// ```
+    /// #![feature(allocator_api)]
+    ///
+    /// use std::alloc::System;
+    ///
+    /// let mut vec = Vec::try_with_capacity_in(10, System).unwrap();
+    ///
+    /// // The vector contains no items, even though it has capacity for more
+    /// assert_eq!(vec.len(), 0);
+    /// assert_eq!(vec.capacity(), 10);
+    ///
+    /// // These are all done without reallocating...
+    /// for i in 0..10 {
+    ///     vec.push(i);
+    /// }
+    /// assert_eq!(vec.len(), 10);
+    /// assert_eq!(vec.capacity(), 10);
+    ///
+    /// // ...but this may make the vector reallocate
+    /// vec.push(11);
+    /// assert_eq!(vec.len(), 11);
+    /// assert!(vec.capacity() >= 11);
+    ///
+    /// let mut result = Vec::try_with_capacity_in(usize::MAX, System);
+    /// assert!(result.is_err());
+    /// ```
+    #[inline]
+    #[stable(feature = "kernel", since = "1.0.0")]
+    pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<Self, TryReserveError> {
+        Ok(Vec { buf: RawVec::try_with_capacity_in(capacity, alloc)?, len: 0 })
+    }
+
     /// Creates a `Vec<T, A>` directly from the raw components of another vector.
     ///
     /// # Safety
-- 
2.38.1


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

* [PATCH v2 14/28] rust: str: add `BStr` type
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (12 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 13/28] rust: alloc: add `Vec::try_with_capacity{,_in}()` constructors ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-02 16:14 ` [PATCH v2 15/28] rust: str: add `b_str!` macro ojeda
                   ` (14 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches

From: Gary Guo <gary@garyguo.net>

Add the `BStr` type, which is a byte string without UTF-8
validity guarantee.

It is simply an alias to `[u8]`, but has a more evident
semantical meaning.

Signed-off-by: Gary Guo <gary@garyguo.net>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/str.rs | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index e45ff220ae50..3aa1a0cb9bf8 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -4,6 +4,11 @@
 
 use core::fmt;
 
+/// Byte string without UTF-8 validity guarantee.
+///
+/// `BStr` is simply an alias to `[u8]`, but has a more evident semantical meaning.
+pub type BStr = [u8];
+
 /// Allows formatting of [`fmt::Arguments`] into a raw buffer.
 ///
 /// It does not fail if callers write past the end of the buffer so that they can calculate the
-- 
2.38.1


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

* [PATCH v2 15/28] rust: str: add `b_str!` macro
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (13 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 14/28] rust: str: add `BStr` type ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-02 16:14 ` [PATCH v2 16/28] rust: str: add `CStr` type ojeda
                   ` (13 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches

From: Gary Guo <gary@garyguo.net>

Add the `b_str!` macro, which creates a new `BStr` from
a string literal.

It is usable in const contexts, for instance:

    const X: &BStr = b_str!("Example");

Signed-off-by: Gary Guo <gary@garyguo.net>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/str.rs | 21 +++++++++++++++++++++
 1 file changed, 21 insertions(+)

diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index 3aa1a0cb9bf8..95eb757c619d 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -9,6 +9,27 @@ use core::fmt;
 /// `BStr` is simply an alias to `[u8]`, but has a more evident semantical meaning.
 pub type BStr = [u8];
 
+/// Creates a new [`BStr`] from a string literal.
+///
+/// `b_str!` converts the supplied string literal to byte string, so non-ASCII
+/// characters can be included.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::b_str;
+/// # use kernel::str::BStr;
+/// const MY_BSTR: &BStr = b_str!("My awesome BStr!");
+/// ```
+#[macro_export]
+macro_rules! b_str {
+    ($str:literal) => {{
+        const S: &'static str = $str;
+        const C: &'static $crate::str::BStr = S.as_bytes();
+        C
+    }};
+}
+
 /// Allows formatting of [`fmt::Arguments`] into a raw buffer.
 ///
 /// It does not fail if callers write past the end of the buffer so that they can calculate the
-- 
2.38.1


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

* [PATCH v2 16/28] rust: str: add `CStr` type
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (14 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 15/28] rust: str: add `b_str!` macro ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-02 16:14 ` [PATCH v2 17/28] rust: str: implement several traits for `CStr` ojeda
                   ` (12 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches, Milan Landaverde

From: Gary Guo <gary@garyguo.net>

Add the `CStr` type, which is a borrowed string that is guaranteed
to have exactly one `NUL` byte, which is at the end.

It is used for interoperability with kernel APIs that take C strings.

Add it to the prelude too.

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Milan Landaverde <milan@mdaverde.com>
Signed-off-by: Gary Guo <gary@garyguo.net>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/prelude.rs |   2 +-
 rust/kernel/str.rs     | 169 +++++++++++++++++++++++++++++++++++++++++
 2 files changed, 170 insertions(+), 1 deletion(-)

diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index 1e08b08e9420..89c2c9f4e7a7 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -21,4 +21,4 @@ pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notic
 
 pub use super::error::{code::*, Error, Result};
 
-pub use super::ThisModule;
+pub use super::{str::CStr, ThisModule};
diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index 95eb757c619d..d66565f92f71 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -4,6 +4,11 @@
 
 use core::fmt;
 
+use crate::{
+    bindings,
+    error::{code::*, Error},
+};
+
 /// Byte string without UTF-8 validity guarantee.
 ///
 /// `BStr` is simply an alias to `[u8]`, but has a more evident semantical meaning.
@@ -30,6 +35,170 @@ macro_rules! b_str {
     }};
 }
 
+/// 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,
+}
+
+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 {
+        // 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.
+        if self.0.is_empty() {
+            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
+    }
+
+    /// Wraps a raw C string pointer.
+    ///
+    /// # Safety
+    ///
+    /// `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 core::ffi::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 as _, len as _) };
+        // 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) }
+    }
+
+    /// Returns a C pointer to the string.
+    #[inline]
+    pub const fn as_char_ptr(&self) -> *const core::ffi::c_char {
+        self.0.as_ptr() as _
+    }
+
+    /// Convert the string to a byte slice without the trailing 0 byte.
+    #[inline]
+    pub fn as_bytes(&self) -> &[u8] {
+        &self.0[..self.len()]
+    }
+
+    /// Convert the string to a byte slice containing the trailing 0 byte.
+    #[inline]
+    pub const fn as_bytes_with_nul(&self) -> &[u8] {
+        &self.0
+    }
+
+    /// 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").unwrap();
+    /// assert_eq!(cstr.to_str(), Ok("foo"));
+    /// ```
+    #[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;
+    /// // SAFETY: String literals are guaranteed to be valid UTF-8
+    /// // by the Rust compiler.
+    /// let bar = c_str!("ツ");
+    /// assert_eq!(unsafe { bar.as_str_unchecked() }, "ツ");
+    /// ```
+    #[inline]
+    pub unsafe fn as_str_unchecked(&self) -> &str {
+        unsafe { core::str::from_utf8_unchecked(self.as_bytes()) }
+    }
+}
+
 /// Allows formatting of [`fmt::Arguments`] into a raw buffer.
 ///
 /// It does not fail if callers write past the end of the buffer so that they can calculate the
-- 
2.38.1


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

* [PATCH v2 17/28] rust: str: implement several traits for `CStr`
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (15 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 16/28] rust: str: add `CStr` type ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-02 16:14 ` [PATCH v2 18/28] rust: str: add `CStr` unit tests ojeda
                   ` (11 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches, Morgan Bartlett

From: Gary Guo <gary@garyguo.net>

Implement `Debug`, `Display`, `Deref` (into `BStr`), `AsRef<BStr>`
and a set of `Index<...>` traits.

This makes it `CStr` more convenient to use (and closer to `str`).

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Co-developed-by: Morgan Bartlett <mjmouse9999@gmail.com>
Signed-off-by: Morgan Bartlett <mjmouse9999@gmail.com>
Signed-off-by: Gary Guo <gary@garyguo.net>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/str.rs | 124 ++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 123 insertions(+), 1 deletion(-)

diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index d66565f92f71..11d297c1a61c 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -2,7 +2,8 @@
 
 //! String representations.
 
-use core::fmt;
+use core::fmt::{self, Write};
+use core::ops::{self, Deref, Index};
 
 use crate::{
     bindings,
@@ -199,6 +200,127 @@ impl CStr {
     }
 }
 
+impl fmt::Display for CStr {
+    /// Formats printable ASCII characters, escaping the rest.
+    ///
+    /// ```
+    /// # use kernel::c_str;
+    /// # use kernel::str::CStr;
+    /// # use kernel::str::CString;
+    /// let penguin = c_str!("🐧");
+    /// let s = CString::try_from_fmt(fmt!("{}", penguin)).unwrap();
+    /// assert_eq!(s.as_bytes_with_nul(), "\\xf0\\x9f\\x90\\xa7\0".as_bytes());
+    ///
+    /// let ascii = c_str!("so \"cool\"");
+    /// let s = CString::try_from_fmt(fmt!("{}", ascii)).unwrap();
+    /// assert_eq!(s.as_bytes_with_nul(), "so \"cool\"\0".as_bytes());
+    /// ```
+    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
+        for &c in self.as_bytes() {
+            if (0x20..0x7f).contains(&c) {
+                // Printable character.
+                f.write_char(c as char)?;
+            } else {
+                write!(f, "\\x{:02x}", c)?;
+            }
+        }
+        Ok(())
+    }
+}
+
+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::str::CStr;
+    /// # use kernel::str::CString;
+    /// let penguin = c_str!("🐧");
+    /// let s = CString::try_from_fmt(fmt!("{:?}", penguin)).unwrap();
+    /// 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)).unwrap();
+    /// assert_eq!(s.as_bytes_with_nul(), "\"so \\\"cool\\\"\"\0".as_bytes());
+    /// ```
+    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{:02x}", c)?,
+            }
+        }
+        f.write_str("\"")
+    }
+}
+
+impl AsRef<BStr> for CStr {
+    #[inline]
+    fn as_ref(&self) -> &BStr {
+        self.as_bytes()
+    }
+}
+
+impl Deref for CStr {
+    type Target = BStr;
+
+    #[inline]
+    fn deref(&self) -> &Self::Target {
+        self.as_bytes()
+    }
+}
+
+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_bytes()[index]
+    }
+}
+
 /// Allows formatting of [`fmt::Arguments`] into a raw buffer.
 ///
 /// It does not fail if callers write past the end of the buffer so that they can calculate the
-- 
2.38.1


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

* [PATCH v2 18/28] rust: str: add `CStr` unit tests
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (16 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 17/28] rust: str: implement several traits for `CStr` ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-02 16:14 ` [PATCH v2 19/28] rust: str: add `c_str!` macro ojeda
                   ` (10 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches, Milan Landaverde

From: Milan Landaverde <milan@mdaverde.com>

Add unit tests for `CStr::from_bytes_with_nul()` and
`CStr::from_bytes_with_nul_unchecked()`.

These serve as an example of the first unit tests for Rust code
(i.e. different from documentation tests).

Signed-off-by: Milan Landaverde <milan@mdaverde.com>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/str.rs | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index 11d297c1a61c..3ed685cb5a3c 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -321,6 +321,35 @@ where
     }
 }
 
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    #[test]
+    fn test_cstr_to_str() {
+        let good_bytes = b"\xf0\x9f\xa6\x80\0";
+        let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
+        let checked_str = checked_cstr.to_str().unwrap();
+        assert_eq!(checked_str, "🦀");
+    }
+
+    #[test]
+    #[should_panic]
+    fn test_cstr_to_str_panic() {
+        let bad_bytes = b"\xc3\x28\0";
+        let checked_cstr = CStr::from_bytes_with_nul(bad_bytes).unwrap();
+        checked_cstr.to_str().unwrap();
+    }
+
+    #[test]
+    fn test_cstr_as_str_unchecked() {
+        let good_bytes = b"\xf0\x9f\x90\xA7\0";
+        let checked_cstr = CStr::from_bytes_with_nul(good_bytes).unwrap();
+        let unchecked_str = unsafe { checked_cstr.as_str_unchecked() };
+        assert_eq!(unchecked_str, "🐧");
+    }
+}
+
 /// Allows formatting of [`fmt::Arguments`] into a raw buffer.
 ///
 /// It does not fail if callers write past the end of the buffer so that they can calculate the
-- 
2.38.1


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

* [PATCH v2 19/28] rust: str: add `c_str!` macro
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (17 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 18/28] rust: str: add `CStr` unit tests ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-02 16:14 ` [PATCH v2 20/28] rust: str: add `Formatter` type ojeda
                   ` (9 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches

From: Gary Guo <gary@garyguo.net>

Add `c_str!`, which is a convenience macro that creates a new `CStr`
from a string literal.

It is designed to be similar to a `str` in usage, and it is usable
in const contexts, for instance:

    const X: &CStr = c_str!("Example");

Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Gary Guo <gary@garyguo.net>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/str.rs | 23 +++++++++++++++++++++++
 1 file changed, 23 insertions(+)

diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index 3ed685cb5a3c..a995db36486f 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -321,6 +321,29 @@ where
     }
 }
 
+/// Creates a new [`CStr`] from a string literal.
+///
+/// The string literal should not contain any `NUL` bytes.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::c_str;
+/// # use kernel::str::CStr;
+/// const MY_CSTR: &CStr = c_str!("My awesome CStr!");
+/// ```
+#[macro_export]
+macro_rules! c_str {
+    ($str:expr) => {{
+        const S: &str = concat!($str, "\0");
+        const C: &$crate::str::CStr = match $crate::str::CStr::from_bytes_with_nul(S.as_bytes()) {
+            Ok(v) => v,
+            Err(_) => panic!("string contains interior NUL"),
+        };
+        C
+    }};
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
-- 
2.38.1


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

* [PATCH v2 20/28] rust: str: add `Formatter` type
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (18 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 19/28] rust: str: add `c_str!` macro ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-04 15:41   ` Dr. David Alan Gilbert
  2022-12-02 16:14 ` [PATCH v2 21/28] rust: str: add `CString` type ojeda
                   ` (8 subsequent siblings)
  28 siblings, 1 reply; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches, Adam Bratschi-Kaye

From: Wedson Almeida Filho <wedsonaf@gmail.com>

Add the `Formatter` type, which leverages `RawFormatter`,
but fails if callers attempt to write more than will fit
in the buffer.

In order to so, implement the `RawFormatter::from_buffer()`
constructor as well.

Co-developed-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Signed-off-by: Adam Bratschi-Kaye <ark.email@gmail.com>
Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com>
Reviewed-by: Gary Guo <gary@garyguo.net>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/str.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 57 insertions(+)

diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index a995db36486f..ce207d1b3d2a 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -406,6 +406,23 @@ impl RawFormatter {
         }
     }
 
+    /// Creates a new instance of [`RawFormatter`] with the given buffer.
+    ///
+    /// # Safety
+    ///
+    /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes
+    /// for the lifetime of the returned [`RawFormatter`].
+    pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self {
+        let pos = buf as usize;
+        // INVARIANT: We ensure that `end` is never less then `buf`, and the safety requirements
+        // guarantees that the memory region is valid for writes.
+        Self {
+            pos,
+            beg: pos,
+            end: pos.saturating_add(len),
+        }
+    }
+
     /// Returns the current insert position.
     ///
     /// N.B. It may point to invalid memory.
@@ -439,3 +456,43 @@ impl fmt::Write for RawFormatter {
         Ok(())
     }
 }
+
+/// Allows formatting of [`fmt::Arguments`] into a raw buffer.
+///
+/// Fails if callers attempt to write more than will fit in the buffer.
+pub(crate) struct Formatter(RawFormatter);
+
+impl Formatter {
+    /// Creates a new instance of [`Formatter`] with the given buffer.
+    ///
+    /// # Safety
+    ///
+    /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes
+    /// for the lifetime of the returned [`Formatter`].
+    #[allow(dead_code)]
+    pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self {
+        // SAFETY: The safety requirements of this function satisfy those of the callee.
+        Self(unsafe { RawFormatter::from_buffer(buf, len) })
+    }
+}
+
+impl Deref for Formatter {
+    type Target = RawFormatter;
+
+    fn deref(&self) -> &Self::Target {
+        &self.0
+    }
+}
+
+impl fmt::Write for Formatter {
+    fn write_str(&mut self, s: &str) -> fmt::Result {
+        self.0.write_str(s)?;
+
+        // Fail the request if we go past the end of the buffer.
+        if self.0.pos > self.0.end {
+            Err(fmt::Error)
+        } else {
+            Ok(())
+        }
+    }
+}
-- 
2.38.1


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

* [PATCH v2 21/28] rust: str: add `CString` type
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (19 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 20/28] rust: str: add `Formatter` type ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-02 16:14 ` [PATCH v2 22/28] rust: str: add `fmt!` macro ojeda
                   ` (7 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches

From: Wedson Almeida Filho <wedsonaf@gmail.com>

Add the `CString` type, which is an owned string that is guaranteed
to have exactly one `NUL` byte at the end, i.e. the owned equivalent
to `CStr` introduced earlier.

It is used for interoperability with kernel APIs that take C strings.

In order to do so, implement the `RawFormatter::new()` constructor
and the `RawFormatter::bytes_written()` method as well.

Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/str.rs | 91 +++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 89 insertions(+), 2 deletions(-)

diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index ce207d1b3d2a..17dc8d273302 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -2,6 +2,7 @@
 
 //! String representations.
 
+use alloc::vec::Vec;
 use core::fmt::{self, Write};
 use core::ops::{self, Deref, Index};
 
@@ -384,13 +385,22 @@ mod tests {
 /// is less than `end`.
 pub(crate) struct RawFormatter {
     // Use `usize` to use `saturating_*` functions.
-    #[allow(dead_code)]
     beg: usize,
     pos: usize,
     end: usize,
 }
 
 impl RawFormatter {
+    /// Creates a new instance of [`RawFormatter`] with an empty buffer.
+    fn new() -> Self {
+        // INVARIANT: The buffer is empty, so the region that needs to be writable is empty.
+        Self {
+            beg: 0,
+            pos: 0,
+            end: 0,
+        }
+    }
+
     /// Creates a new instance of [`RawFormatter`] with the given buffer pointers.
     ///
     /// # Safety
@@ -429,6 +439,11 @@ impl RawFormatter {
     pub(crate) fn pos(&self) -> *mut u8 {
         self.pos as _
     }
+
+    /// Return the number of bytes written to the formatter.
+    pub(crate) fn bytes_written(&self) -> usize {
+        self.pos - self.beg
+    }
 }
 
 impl fmt::Write for RawFormatter {
@@ -469,7 +484,6 @@ impl Formatter {
     ///
     /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes
     /// for the lifetime of the returned [`Formatter`].
-    #[allow(dead_code)]
     pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self {
         // SAFETY: The safety requirements of this function satisfy those of the callee.
         Self(unsafe { RawFormatter::from_buffer(buf, len) })
@@ -496,3 +510,76 @@ impl fmt::Write for Formatter {
         }
     }
 }
+
+/// An owned 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.
+///
+/// # Invariants
+///
+/// The string is always `NUL`-terminated and contains no other `NUL` bytes.
+///
+/// # Examples
+///
+/// ```
+/// use kernel::str::CString;
+///
+/// let s = CString::try_from_fmt(fmt!("{}{}{}", "abc", 10, 20)).unwrap();
+/// assert_eq!(s.as_bytes_with_nul(), "abc1020\0".as_bytes());
+///
+/// let tmp = "testing";
+/// let s = CString::try_from_fmt(fmt!("{tmp}{}", 123)).unwrap();
+/// assert_eq!(s.as_bytes_with_nul(), "testing123\0".as_bytes());
+///
+/// // This fails because it has an embedded `NUL` byte.
+/// let s = CString::try_from_fmt(fmt!("a\0b{}", 123));
+/// assert_eq!(s.is_ok(), false);
+/// ```
+pub struct CString {
+    buf: Vec<u8>,
+}
+
+impl CString {
+    /// Creates an instance of [`CString`] from the given formatted arguments.
+    pub fn try_from_fmt(args: fmt::Arguments<'_>) -> Result<Self, Error> {
+        // Calculate the size needed (formatted string plus `NUL` terminator).
+        let mut f = RawFormatter::new();
+        f.write_fmt(args)?;
+        f.write_str("\0")?;
+        let size = f.bytes_written();
+
+        // Allocate a vector with the required number of bytes, and write to it.
+        let mut buf = Vec::try_with_capacity(size)?;
+        // SAFETY: The buffer stored in `buf` is at least of size `size` and is valid for writes.
+        let mut f = unsafe { Formatter::from_buffer(buf.as_mut_ptr(), size) };
+        f.write_fmt(args)?;
+        f.write_str("\0")?;
+
+        // SAFETY: The number of bytes that can be written to `f` is bounded by `size`, which is
+        // `buf`'s capacity. The contents of the buffer have been initialised by writes to `f`.
+        unsafe { buf.set_len(f.bytes_written()) };
+
+        // Check that there are no `NUL` bytes before the end.
+        // SAFETY: The buffer is valid for read because `f.bytes_written()` is bounded by `size`
+        // (which the minimum buffer size) and is non-zero (we wrote at least the `NUL` terminator)
+        // so `f.bytes_written() - 1` doesn't underflow.
+        let ptr = unsafe { bindings::memchr(buf.as_ptr().cast(), 0, (f.bytes_written() - 1) as _) };
+        if !ptr.is_null() {
+            return Err(EINVAL);
+        }
+
+        // INVARIANT: We wrote the `NUL` terminator and checked above that no other `NUL` bytes
+        // exist in the buffer.
+        Ok(Self { buf })
+    }
+}
+
+impl Deref for CString {
+    type Target = CStr;
+
+    fn deref(&self) -> &Self::Target {
+        // SAFETY: The type invariants guarantee that the string is `NUL`-terminated and that no
+        // other `NUL` bytes exist.
+        unsafe { CStr::from_bytes_with_nul_unchecked(self.buf.as_slice()) }
+    }
+}
-- 
2.38.1


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

* [PATCH v2 22/28] rust: str: add `fmt!` macro
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (20 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 21/28] rust: str: add `CString` type ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-02 16:14 ` [PATCH v2 23/28] rust: std_vendor: add `dbg!` macro based on `std`'s one ojeda
                   ` (6 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches

From: Wedson Almeida Filho <wedsonaf@gmail.com>

Add the `fmt!` macro, which is a convenience alias for the Rust
`core::format_args!` macro.

For instance, it may be used to create a `CString`:

    CString::try_from_fmt(fmt!("{}{}", "abc", 42))?

Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com>
Reviewed-by: Gary Guo <gary@garyguo.net>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/str.rs | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index 17dc8d273302..b771310fa4a4 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -583,3 +583,9 @@ impl Deref for CString {
         unsafe { CStr::from_bytes_with_nul_unchecked(self.buf.as_slice()) }
     }
 }
+
+/// A convenience alias for [`core::format_args`].
+#[macro_export]
+macro_rules! fmt {
+    ($($f:tt)*) => ( core::format_args!($($f)*) )
+}
-- 
2.38.1


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

* [PATCH v2 23/28] rust: std_vendor: add `dbg!` macro based on `std`'s one
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (21 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 22/28] rust: str: add `fmt!` macro ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-02 16:14 ` [PATCH v2 24/28] rust: static_assert: add `static_assert!` macro ojeda
                   ` (5 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches, Niklas Mohrin

From: Niklas Mohrin <dev@niklasmohrin.de>

The Rust standard library has a really handy macro, `dbg!` [1,2].
It prints the source location (filename and line) along with the raw
source code that is invoked with and the `Debug` representation
of the given expression, e.g.:

    let a = 2;
    let b = dbg!(a * 2) + 1;
    //      ^-- prints: [src/main.rs:2] a * 2 = 4
    assert_eq!(b, 5);

Port the macro over to the `kernel` crate inside a new module
called `std_vendor`, using `pr_info!` instead of `eprintln!` and
make the rules about committing uses of `dbg!` into version control
more concrete (i.e. tailored for the kernel).

Since the source code for the macro is taken from the standard
library source (with only minor adjustments), the new file is
licensed under `Apache 2.0 OR MIT`, just like the original [3,4].

Link: https://doc.rust-lang.org/std/macro.dbg.html [1]
Link: https://github.com/rust-lang/rust/blob/master/library/std/src/macros.rs#L212 [2]
Link: https://github.com/rust-lang/rust/blob/master/library/std/Cargo.toml [3]
Link: https://github.com/rust-lang/rust/blob/master/COPYRIGHT [4]
Signed-off-by: Niklas Mohrin <dev@niklasmohrin.de>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/lib.rs        |   2 +
 rust/kernel/prelude.rs    |   2 +-
 rust/kernel/std_vendor.rs | 163 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 166 insertions(+), 1 deletion(-)
 create mode 100644 rust/kernel/std_vendor.rs

diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index ffc6626a6d29..d6371c9c8453 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -26,6 +26,8 @@ mod allocator;
 pub mod error;
 pub mod prelude;
 pub mod print;
+#[doc(hidden)]
+pub mod std_vendor;
 pub mod str;
 
 #[doc(hidden)]
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index 89c2c9f4e7a7..345fc9075d1f 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -17,7 +17,7 @@ pub use alloc::{boxed::Box, vec::Vec};
 
 pub use macros::{module, vtable};
 
-pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};
+pub use super::{dbg, pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};
 
 pub use super::error::{code::*, Error, Result};
 
diff --git a/rust/kernel/std_vendor.rs b/rust/kernel/std_vendor.rs
new file mode 100644
index 000000000000..b3e68b24a8c6
--- /dev/null
+++ b/rust/kernel/std_vendor.rs
@@ -0,0 +1,163 @@
+// SPDX-License-Identifier: Apache-2.0 OR MIT
+
+//! The contents of this file come from the Rust standard library, hosted in
+//! the <https://github.com/rust-lang/rust> repository, licensed under
+//! "Apache-2.0 OR MIT" and adapted for kernel use. For copyright details,
+//! see <https://github.com/rust-lang/rust/blob/master/COPYRIGHT>.
+
+/// [`std::dbg`], but using [`pr_info`] instead of [`eprintln`].
+///
+/// Prints and returns the value of a given expression for quick and dirty
+/// debugging.
+///
+/// An example:
+///
+/// ```rust
+/// let a = 2;
+/// # #[allow(clippy::dbg_macro)]
+/// let b = dbg!(a * 2) + 1;
+/// //      ^-- prints: [src/main.rs:2] a * 2 = 4
+/// assert_eq!(b, 5);
+/// ```
+///
+/// The macro works by using the `Debug` implementation of the type of
+/// the given expression to print the value with [`printk`] along with the
+/// source location of the macro invocation as well as the source code
+/// of the expression.
+///
+/// Invoking the macro on an expression moves and takes ownership of it
+/// before returning the evaluated expression unchanged. If the type
+/// of the expression does not implement `Copy` and you don't want
+/// to give up ownership, you can instead borrow with `dbg!(&expr)`
+/// for some expression `expr`.
+///
+/// The `dbg!` macro works exactly the same in release builds.
+/// This is useful when debugging issues that only occur in release
+/// builds or when debugging in release mode is significantly faster.
+///
+/// Note that the macro is intended as a temporary debugging tool to be
+/// used during development. Therefore, avoid committing `dbg!` macro
+/// invocations into the kernel tree.
+///
+/// For debug output that is intended to be kept in the kernel tree,
+/// use [`pr_debug`] and similar facilities instead.
+///
+/// # Stability
+///
+/// The exact output printed by this macro should not be relied upon
+/// and is subject to future changes.
+///
+/// # Further examples
+///
+/// With a method call:
+///
+/// ```rust
+/// # #[allow(clippy::dbg_macro)]
+/// fn foo(n: usize) {
+///     if dbg!(n.checked_sub(4)).is_some() {
+///         // ...
+///     }
+/// }
+///
+/// foo(3)
+/// ```
+///
+/// This prints to the kernel log:
+///
+/// ```text,ignore
+/// [src/main.rs:4] n.checked_sub(4) = None
+/// ```
+///
+/// Naive factorial implementation:
+///
+/// ```rust
+/// # #[allow(clippy::dbg_macro)]
+/// # {
+/// fn factorial(n: u32) -> u32 {
+///     if dbg!(n <= 1) {
+///         dbg!(1)
+///     } else {
+///         dbg!(n * factorial(n - 1))
+///     }
+/// }
+///
+/// dbg!(factorial(4));
+/// # }
+/// ```
+///
+/// This prints to the kernel log:
+///
+/// ```text,ignore
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = false
+/// [src/main.rs:3] n <= 1 = true
+/// [src/main.rs:4] 1 = 1
+/// [src/main.rs:5] n * factorial(n - 1) = 2
+/// [src/main.rs:5] n * factorial(n - 1) = 6
+/// [src/main.rs:5] n * factorial(n - 1) = 24
+/// [src/main.rs:11] factorial(4) = 24
+/// ```
+///
+/// The `dbg!(..)` macro moves the input:
+///
+/// ```ignore
+/// /// A wrapper around `usize` which importantly is not Copyable.
+/// #[derive(Debug)]
+/// struct NoCopy(usize);
+///
+/// let a = NoCopy(42);
+/// let _ = dbg!(a); // <-- `a` is moved here.
+/// let _ = dbg!(a); // <-- `a` is moved again; error!
+/// ```
+///
+/// You can also use `dbg!()` without a value to just print the
+/// file and line whenever it's reached.
+///
+/// Finally, if you want to `dbg!(..)` multiple values, it will treat them as
+/// a tuple (and return it, too):
+///
+/// ```
+/// # #[allow(clippy::dbg_macro)]
+/// assert_eq!(dbg!(1usize, 2u32), (1, 2));
+/// ```
+///
+/// However, a single argument with a trailing comma will still not be treated
+/// as a tuple, following the convention of ignoring trailing commas in macro
+/// invocations. You can use a 1-tuple directly if you need one:
+///
+/// ```
+/// # #[allow(clippy::dbg_macro)]
+/// # {
+/// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored
+/// assert_eq!((1,), dbg!((1u32,))); // 1-tuple
+/// # }
+/// ```
+///
+/// [`std::dbg`]: https://doc.rust-lang.org/std/macro.dbg.html
+/// [`eprintln`]: https://doc.rust-lang.org/std/macro.eprintln.html
+/// [`printk`]: https://www.kernel.org/doc/html/latest/core-api/printk-basics.html
+#[macro_export]
+macro_rules! dbg {
+    // NOTE: We cannot use `concat!` to make a static string as a format argument
+    // of `pr_info!` because `file!` could contain a `{` or
+    // `$val` expression could be a block (`{ .. }`), in which case the `pr_info!`
+    // will be malformed.
+    () => {
+        $crate::pr_info!("[{}:{}]\n", ::core::file!(), ::core::line!())
+    };
+    ($val:expr $(,)?) => {
+        // Use of `match` here is intentional because it affects the lifetimes
+        // of temporaries - https://stackoverflow.com/a/48732525/1063961
+        match $val {
+            tmp => {
+                $crate::pr_info!("[{}:{}] {} = {:#?}\n",
+                    ::core::file!(), ::core::line!(), ::core::stringify!($val), &tmp);
+                tmp
+            }
+        }
+    };
+    ($($val:expr),+ $(,)?) => {
+        ($($crate::dbg!($val)),+,)
+    };
+}
-- 
2.38.1


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

* [PATCH v2 24/28] rust: static_assert: add `static_assert!` macro
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (22 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 23/28] rust: std_vendor: add `dbg!` macro based on `std`'s one ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-02 16:14 ` [PATCH v2 25/28] rust: add `build_error` crate ojeda
                   ` (4 subsequent siblings)
  28 siblings, 0 replies; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches

From: Miguel Ojeda <ojeda@kernel.org>

Add the `static_assert!` macro, which is a compile-time assert, similar
to the C11 `_Static_assert` and C++11 `static_assert` declarations [1,2].
Do so in a new module, called `static_assert`.

For instance:

    static_assert!(42 > 24);
    static_assert!(core::mem::size_of::<u8>() == 1);

    const X: &[u8] = b"bar";
    static_assert!(X[1] == b'a');

    const fn f(x: i32) -> i32 {
        x + 2
    }
    static_assert!(f(40) == 42);

Link: https://en.cppreference.com/w/c/language/_Static_assert [1]
Link: https://en.cppreference.com/w/cpp/language/static_assert [2]
Co-developed-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Alex Gaynor <alex.gaynor@gmail.com>
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/lib.rs           |  1 +
 rust/kernel/prelude.rs       |  2 ++
 rust/kernel/static_assert.rs | 34 ++++++++++++++++++++++++++++++++++
 3 files changed, 37 insertions(+)
 create mode 100644 rust/kernel/static_assert.rs

diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index d6371c9c8453..9b83ef736298 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -26,6 +26,7 @@ mod allocator;
 pub mod error;
 pub mod prelude;
 pub mod print;
+mod static_assert;
 #[doc(hidden)]
 pub mod std_vendor;
 pub mod str;
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index 345fc9075d1f..178fe8e6cb6d 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -19,6 +19,8 @@ pub use macros::{module, vtable};
 
 pub use super::{dbg, pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};
 
+pub use super::static_assert;
+
 pub use super::error::{code::*, Error, Result};
 
 pub use super::{str::CStr, ThisModule};
diff --git a/rust/kernel/static_assert.rs b/rust/kernel/static_assert.rs
new file mode 100644
index 000000000000..3115ee0ba8e9
--- /dev/null
+++ b/rust/kernel/static_assert.rs
@@ -0,0 +1,34 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Static assert.
+
+/// Static assert (i.e. compile-time assert).
+///
+/// Similar to C11 [`_Static_assert`] and C++11 [`static_assert`].
+///
+/// The feature may be added to Rust in the future: see [RFC 2790].
+///
+/// [`_Static_assert`]: https://en.cppreference.com/w/c/language/_Static_assert
+/// [`static_assert`]: https://en.cppreference.com/w/cpp/language/static_assert
+/// [RFC 2790]: https://github.com/rust-lang/rfcs/issues/2790
+///
+/// # Examples
+///
+/// ```
+/// static_assert!(42 > 24);
+/// static_assert!(core::mem::size_of::<u8>() == 1);
+///
+/// const X: &[u8] = b"bar";
+/// static_assert!(X[1] == b'a');
+///
+/// const fn f(x: i32) -> i32 {
+///     x + 2
+/// }
+/// static_assert!(f(40) == 42);
+/// ```
+#[macro_export]
+macro_rules! static_assert {
+    ($condition:expr) => {
+        const _: () = core::assert!($condition);
+    };
+}
-- 
2.38.1


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

* [PATCH v2 25/28] rust: add `build_error` crate
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (23 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 24/28] rust: static_assert: add `static_assert!` macro ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-02 18:31   ` Wei Liu
  2022-12-02 16:14 ` [PATCH v2 26/28] rust: build_assert: add `build_{error,assert}!` macros ojeda
                   ` (3 subsequent siblings)
  28 siblings, 1 reply; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches

From: Gary Guo <gary@garyguo.net>

The `build_error` crate provides a function `build_error` which
will panic at compile-time if executed in const context and,
by default, will cause a build error if not executed at compile
time and the optimizer does not optimise away the call.

The `CONFIG_RUST_BUILD_ASSERT_ALLOW` kernel option allows to
relax the default build failure and convert it to a runtime
check. If the runtime check fails, `panic!` will be called.

Its functionality will be exposed to users as a couple macros in
the `kernel` crate in the following patch, thus some documentation
here refers to them for simplicity.

Signed-off-by: Gary Guo <gary@garyguo.net>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 lib/Kconfig.debug                 | 16 ++++++++++++++++
 rust/Makefile                     | 22 +++++++++++++++++-----
 rust/build_error.rs               | 31 +++++++++++++++++++++++++++++++
 rust/exports.c                    |  5 +++++
 scripts/generate_rust_analyzer.py |  8 +++++++-
 5 files changed, 76 insertions(+), 6 deletions(-)
 create mode 100644 rust/build_error.rs

diff --git a/lib/Kconfig.debug b/lib/Kconfig.debug
index 29280072dc0e..452c9f06c2bc 100644
--- a/lib/Kconfig.debug
+++ b/lib/Kconfig.debug
@@ -2801,6 +2801,22 @@ config RUST_OVERFLOW_CHECKS
 
 	  If unsure, say Y.
 
+config RUST_BUILD_ASSERT_ALLOW
+	bool "Allow unoptimized build-time assertions"
+	depends on RUST
+	help
+	  Controls how are `build_error!` and `build_assert!` handled during build.
+
+	  If calls to them exist in the binary, it may indicate a violated invariant
+	  or that the optimizer failed to verify the invariant during compilation.
+
+	  This should not happen, thus by default the build is aborted. However,
+	  as an escape hatch, you can choose Y here to ignore them during build
+	  and let the check be carried at runtime (with `panic!` being called if
+	  the check fails).
+
+	  If unsure, say N.
+
 endmenu # "Rust"
 
 source "Documentation/Kconfig"
diff --git a/rust/Makefile b/rust/Makefile
index 7700d3853404..ff70c4c916f8 100644
--- a/rust/Makefile
+++ b/rust/Makefile
@@ -19,6 +19,12 @@ obj-$(CONFIG_RUST) += alloc.o bindings.o kernel.o
 always-$(CONFIG_RUST) += exports_alloc_generated.h exports_bindings_generated.h \
     exports_kernel_generated.h
 
+ifdef CONFIG_RUST_BUILD_ASSERT_ALLOW
+obj-$(CONFIG_RUST) += build_error.o
+else
+always-$(CONFIG_RUST) += build_error.o
+endif
+
 obj-$(CONFIG_RUST) += exports.o
 
 # Avoids running `$(RUSTC)` for the sysroot when it may not be available.
@@ -108,7 +114,7 @@ rustdoc-alloc: $(src)/alloc/lib.rs rustdoc-core rustdoc-compiler_builtins FORCE
 	$(call if_changed,rustdoc)
 
 rustdoc-kernel: private rustc_target_flags = --extern alloc \
-    --extern macros=$(objtree)/$(obj)/libmacros.so \
+    --extern build_error --extern macros=$(objtree)/$(obj)/libmacros.so \
     --extern bindings
 rustdoc-kernel: $(src)/kernel/lib.rs rustdoc-core rustdoc-macros \
     rustdoc-compiler_builtins rustdoc-alloc $(obj)/libmacros.so \
@@ -126,6 +132,9 @@ quiet_cmd_rustc_test_library = RUSTC TL $<
 		-L$(objtree)/$(obj)/test \
 		--crate-name $(subst rusttest-,,$(subst rusttestlib-,,$@)) $<
 
+rusttestlib-build_error: $(src)/build_error.rs rusttest-prepare FORCE
+	$(call if_changed,rustc_test_library)
+
 rusttestlib-macros: private rustc_target_flags = --extern proc_macro
 rusttestlib-macros: private rustc_test_library_proc = yes
 rusttestlib-macros: $(src)/macros/lib.rs rusttest-prepare FORCE
@@ -216,9 +225,9 @@ rusttest-macros: $(src)/macros/lib.rs rusttest-prepare FORCE
 	$(call if_changed,rustdoc_test)
 
 rusttest-kernel: private rustc_target_flags = --extern alloc \
-    --extern macros --extern bindings
+    --extern build_error --extern macros --extern bindings
 rusttest-kernel: $(src)/kernel/lib.rs rusttest-prepare \
-    rusttestlib-macros rusttestlib-bindings FORCE
+    rusttestlib-build_error rusttestlib-macros rusttestlib-bindings FORCE
 	$(call if_changed,rustc_test)
 	$(call if_changed,rustc_test_library)
 
@@ -366,6 +375,9 @@ $(obj)/alloc.o: private rustc_target_flags = $(alloc-cfgs)
 $(obj)/alloc.o: $(src)/alloc/lib.rs $(obj)/compiler_builtins.o FORCE
 	$(call if_changed_dep,rustc_library)
 
+$(obj)/build_error.o: $(src)/build_error.rs $(obj)/compiler_builtins.o FORCE
+	$(call if_changed_dep,rustc_library)
+
 $(obj)/bindings.o: $(src)/bindings/lib.rs \
     $(obj)/compiler_builtins.o \
     $(obj)/bindings/bindings_generated.rs \
@@ -373,8 +385,8 @@ $(obj)/bindings.o: $(src)/bindings/lib.rs \
 	$(call if_changed_dep,rustc_library)
 
 $(obj)/kernel.o: private rustc_target_flags = --extern alloc \
-    --extern macros --extern bindings
-$(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/alloc.o \
+    --extern build_error --extern macros --extern bindings
+$(obj)/kernel.o: $(src)/kernel/lib.rs $(obj)/alloc.o $(obj)/build_error.o \
     $(obj)/libmacros.so $(obj)/bindings.o FORCE
 	$(call if_changed_dep,rustc_library)
 
diff --git a/rust/build_error.rs b/rust/build_error.rs
new file mode 100644
index 000000000000..fa24eeef9929
--- /dev/null
+++ b/rust/build_error.rs
@@ -0,0 +1,31 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Build-time error.
+//!
+//! This crate provides a [const function][const-functions] `build_error`, which will panic in
+//! compile-time if executed in [const context][const-context], and will cause a build error
+//! if not executed at compile time and the optimizer does not optimise away the call.
+//!
+//! It is used by `build_assert!` in the kernel crate, allowing checking of
+//! conditions that could be checked statically, but could not be enforced in
+//! Rust yet (e.g. perform some checks in [const functions][const-functions], but those
+//! functions could still be called in the runtime).
+//!
+//! For details on constant evaluation in Rust, please see the [Reference][const-eval].
+//!
+//! [const-eval]: https://doc.rust-lang.org/reference/const_eval.html
+//! [const-functions]: https://doc.rust-lang.org/reference/const_eval.html#const-functions
+//! [const-context]: https://doc.rust-lang.org/reference/const_eval.html#const-context
+
+#![no_std]
+
+/// Panics if executed in [const context][const-context], or triggers a build error if not.
+///
+/// [const-context]: https://doc.rust-lang.org/reference/const_eval.html#const-context
+#[inline(never)]
+#[cold]
+#[export_name = "rust_build_error"]
+#[track_caller]
+pub const fn build_error(msg: &'static str) -> ! {
+    panic!("{}", msg);
+}
diff --git a/rust/exports.c b/rust/exports.c
index bb7cc64cecd0..83e2a7070cae 100644
--- a/rust/exports.c
+++ b/rust/exports.c
@@ -19,3 +19,8 @@
 #include "exports_alloc_generated.h"
 #include "exports_bindings_generated.h"
 #include "exports_kernel_generated.h"
+
+// For modules using `rust/build_error.rs`.
+#ifdef CONFIG_RUST_BUILD_ASSERT_ALLOW
+EXPORT_SYMBOL_RUST_GPL(rust_build_error);
+#endif
diff --git a/scripts/generate_rust_analyzer.py b/scripts/generate_rust_analyzer.py
index 75bb611bd751..ecc7ea9a4dcf 100755
--- a/scripts/generate_rust_analyzer.py
+++ b/scripts/generate_rust_analyzer.py
@@ -67,6 +67,12 @@ def generate_crates(srctree, objtree, sysroot_src):
     )
     crates[-1]["proc_macro_dylib_path"] = "rust/libmacros.so"
 
+    append_crate(
+        "build_error",
+        srctree / "rust" / "build_error.rs",
+        ["core", "compiler_builtins"],
+    )
+
     append_crate(
         "bindings",
         srctree / "rust"/ "bindings" / "lib.rs",
@@ -78,7 +84,7 @@ def generate_crates(srctree, objtree, sysroot_src):
     append_crate(
         "kernel",
         srctree / "rust" / "kernel" / "lib.rs",
-        ["core", "alloc", "macros", "bindings"],
+        ["core", "alloc", "macros", "build_error", "bindings"],
         cfg=cfg,
     )
     crates[-1]["source"] = {
-- 
2.38.1


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

* [PATCH v2 26/28] rust: build_assert: add `build_{error,assert}!` macros
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (24 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 25/28] rust: add `build_error` crate ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-02 18:32   ` Wei Liu
  2022-12-02 16:14 ` [PATCH v2 27/28] rust: types: add `Either` type ojeda
                   ` (2 subsequent siblings)
  28 siblings, 1 reply; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches

From: Gary Guo <gary@garyguo.net>

Add the `build_error!` and `build_assert!` macros which leverage
the previously introduced `build_error` crate. Do so in a new
module, called `build_assert`.

The former fails the build if the code path calling it can possibly
be executed. The latter asserts that a boolean expression is `true`
at compile time.

In particular, `build_assert!` can be used in some contexts where
`static_assert!` cannot:

    fn f1<const N: usize>() {
        static_assert!(N > 1);` // Error.
        build_assert!(N > 1);   // Build-time check.
        assert!(N > 1);         // Run-time check.
    }

    #[inline]
    fn f2(n: usize) {
        static_assert!(n > 1);  // Error.
        build_assert!(n > 1);   // Build-time check.
        assert!(n > 1);         // Run-time check.
    }

Signed-off-by: Gary Guo <gary@garyguo.net>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/build_assert.rs | 82 +++++++++++++++++++++++++++++++++++++
 rust/kernel/lib.rs          |  4 ++
 rust/kernel/prelude.rs      |  2 +
 3 files changed, 88 insertions(+)
 create mode 100644 rust/kernel/build_assert.rs

diff --git a/rust/kernel/build_assert.rs b/rust/kernel/build_assert.rs
new file mode 100644
index 000000000000..659542393c09
--- /dev/null
+++ b/rust/kernel/build_assert.rs
@@ -0,0 +1,82 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Build-time assert.
+
+/// Fails the build if the code path calling `build_error!` can possibly be executed.
+///
+/// If the macro is executed in const context, `build_error!` will panic.
+/// If the compiler or optimizer cannot guarantee that `build_error!` can never
+/// be called, a build error will be triggered.
+///
+/// # Examples
+///
+/// ```
+/// # use kernel::build_error;
+/// #[inline]
+/// fn foo(a: usize) -> usize {
+///     a.checked_add(1).unwrap_or_else(|| build_error!("overflow"))
+/// }
+///
+/// assert_eq!(foo(usize::MAX - 1), usize::MAX); // OK.
+/// // foo(usize::MAX); // Fails to compile.
+/// ```
+#[macro_export]
+macro_rules! build_error {
+    () => {{
+        $crate::build_error("")
+    }};
+    ($msg:expr) => {{
+        $crate::build_error($msg)
+    }};
+}
+
+/// Asserts that a boolean expression is `true` at compile time.
+///
+/// If the condition is evaluated to `false` in const context, `build_assert!`
+/// will panic. If the compiler or optimizer cannot guarantee the condition will
+/// be evaluated to `true`, a build error will be triggered.
+///
+/// [`static_assert!`] should be preferred to `build_assert!` whenever possible.
+///
+/// # Examples
+///
+/// These examples show that different types of [`assert!`] will trigger errors
+/// at different stage of compilation. It is preferred to err as early as
+/// possible, so [`static_assert!`] should be used whenever possible.
+/// ```ignore
+/// fn foo() {
+///     static_assert!(1 > 1); // Compile-time error
+///     build_assert!(1 > 1); // Build-time error
+///     assert!(1 > 1); // Run-time error
+/// }
+/// ```
+///
+/// When the condition refers to generic parameters or parameters of an inline function,
+/// [`static_assert!`] cannot be used. Use `build_assert!` in this scenario.
+/// ```
+/// fn foo<const N: usize>() {
+///     // `static_assert!(N > 1);` is not allowed
+///     build_assert!(N > 1); // Build-time check
+///     assert!(N > 1); // Run-time check
+/// }
+///
+/// #[inline]
+/// fn bar(n: usize) {
+///     // `static_assert!(n > 1);` is not allowed
+///     build_assert!(n > 1); // Build-time check
+///     assert!(n > 1); // Run-time check
+/// }
+/// ```
+#[macro_export]
+macro_rules! build_assert {
+    ($cond:expr $(,)?) => {{
+        if !$cond {
+            $crate::build_error(concat!("assertion failed: ", stringify!($cond)));
+        }
+    }};
+    ($cond:expr, $msg:expr) => {{
+        if !$cond {
+            $crate::build_error($msg);
+        }
+    }};
+}
diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index 9b83ef736298..a3abc110ff97 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -23,6 +23,7 @@ compile_error!("Missing kernel configuration for conditional compilation");
 #[cfg(not(test))]
 #[cfg(not(testlib))]
 mod allocator;
+mod build_assert;
 pub mod error;
 pub mod prelude;
 pub mod print;
@@ -35,6 +36,9 @@ pub mod str;
 pub use bindings;
 pub use macros;
 
+#[doc(hidden)]
+pub use build_error::build_error;
+
 /// Prefix to appear before log messages printed from within the `kernel` crate.
 const __LOG_PREFIX: &[u8] = b"rust_kernel\0";
 
diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
index 178fe8e6cb6d..7a90249ee9b9 100644
--- a/rust/kernel/prelude.rs
+++ b/rust/kernel/prelude.rs
@@ -17,6 +17,8 @@ pub use alloc::{boxed::Box, vec::Vec};
 
 pub use macros::{module, vtable};
 
+pub use super::build_assert;
+
 pub use super::{dbg, pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};
 
 pub use super::static_assert;
-- 
2.38.1


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

* [PATCH v2 27/28] rust: types: add `Either` type
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (25 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 26/28] rust: build_assert: add `build_{error,assert}!` macros ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-02 23:41   ` Josh Triplett
  2022-12-02 16:14 ` [PATCH v2 28/28] rust: types: add `Opaque` type ojeda
  2022-12-04  1:05 ` [PATCH v2 00/28] Rust core additions Miguel Ojeda
  28 siblings, 1 reply; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches, Wei Liu

From: Wedson Almeida Filho <wedsonaf@gmail.com>

Introduce the new `types` module of the `kernel` crate with
`Either` as its first type.

`Either<L, R>` is a sum type that always holds either a value
of type `L` (`Left` variant) or `R` (`Right` variant).

For instance:

    struct Executor {
        queue: Either<BoxedQueue, &'static Queue>,
    }

Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com>
Reviewed-by: Wei Liu <wei.liu@kernel.org>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/lib.rs   |  1 +
 rust/kernel/types.rs | 12 ++++++++++++
 2 files changed, 13 insertions(+)
 create mode 100644 rust/kernel/types.rs

diff --git a/rust/kernel/lib.rs b/rust/kernel/lib.rs
index a3abc110ff97..53040fa9e897 100644
--- a/rust/kernel/lib.rs
+++ b/rust/kernel/lib.rs
@@ -31,6 +31,7 @@ mod static_assert;
 #[doc(hidden)]
 pub mod std_vendor;
 pub mod str;
+pub mod types;
 
 #[doc(hidden)]
 pub use bindings;
diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
new file mode 100644
index 000000000000..3b0c44769708
--- /dev/null
+++ b/rust/kernel/types.rs
@@ -0,0 +1,12 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! Kernel types.
+
+/// A sum type that always holds either a value of type `L` or `R`.
+pub enum Either<L, R> {
+    /// Constructs an instance of [`Either`] containing a value of type `L`.
+    Left(L),
+
+    /// Constructs an instance of [`Either`] containing a value of type `R`.
+    Right(R),
+}
-- 
2.38.1


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

* [PATCH v2 28/28] rust: types: add `Opaque` type
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (26 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 27/28] rust: types: add `Either` type ojeda
@ 2022-12-02 16:14 ` ojeda
  2022-12-04  1:05 ` [PATCH v2 00/28] Rust core additions Miguel Ojeda
  28 siblings, 0 replies; 46+ messages in thread
From: ojeda @ 2022-12-02 16:14 UTC (permalink / raw)
  To: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron
  Cc: rust-for-linux, linux-kernel, patches

From: Wedson Almeida Filho <wedsonaf@gmail.com>

Add the `Opaque` type, which is meant to be used with FFI objects
that are never interpreted by Rust code, e.g.:

    struct Waiter {
        completion: Opaque<bindings::completion>,
        next: *mut Waiter,
    }

It has the advantage that the objects don't have to be
zero-initialised before calling their init functions, making
the code performance closer to C.

Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com>
[Reworded, adapted for upstream and applied latest changes]
Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
---
 rust/kernel/types.rs | 25 +++++++++++++++++++++++++
 1 file changed, 25 insertions(+)

diff --git a/rust/kernel/types.rs b/rust/kernel/types.rs
index 3b0c44769708..e84e51ec9716 100644
--- a/rust/kernel/types.rs
+++ b/rust/kernel/types.rs
@@ -2,6 +2,31 @@
 
 //! Kernel types.
 
+use core::{cell::UnsafeCell, mem::MaybeUninit};
+
+/// Stores an opaque value.
+///
+/// This is meant to be used with FFI objects that are never interpreted by Rust code.
+#[repr(transparent)]
+pub struct Opaque<T>(MaybeUninit<UnsafeCell<T>>);
+
+impl<T> Opaque<T> {
+    /// Creates a new opaque value.
+    pub const fn new(value: T) -> Self {
+        Self(MaybeUninit::new(UnsafeCell::new(value)))
+    }
+
+    /// Creates an uninitialised value.
+    pub const fn uninit() -> Self {
+        Self(MaybeUninit::uninit())
+    }
+
+    /// Returns a raw pointer to the opaque data.
+    pub fn get(&self) -> *mut T {
+        UnsafeCell::raw_get(self.0.as_ptr())
+    }
+}
+
 /// A sum type that always holds either a value of type `L` or `R`.
 pub enum Either<L, R> {
     /// Constructs an instance of [`Either`] containing a value of type `L`.
-- 
2.38.1


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

* Re: [PATCH v2 25/28] rust: add `build_error` crate
  2022-12-02 16:14 ` [PATCH v2 25/28] rust: add `build_error` crate ojeda
@ 2022-12-02 18:31   ` Wei Liu
  0 siblings, 0 replies; 46+ messages in thread
From: Wei Liu @ 2022-12-02 18:31 UTC (permalink / raw)
  To: ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Wei Liu

On Fri, Dec 02, 2022 at 05:14:56PM +0100, ojeda@kernel.org wrote:
> From: Gary Guo <gary@garyguo.net>
> 
> The `build_error` crate provides a function `build_error` which
> will panic at compile-time if executed in const context and,
> by default, will cause a build error if not executed at compile
> time and the optimizer does not optimise away the call.
> 
> The `CONFIG_RUST_BUILD_ASSERT_ALLOW` kernel option allows to
> relax the default build failure and convert it to a runtime
> check. If the runtime check fails, `panic!` will be called.
> 
> Its functionality will be exposed to users as a couple macros in
> the `kernel` crate in the following patch, thus some documentation
> here refers to them for simplicity.
> 
> Signed-off-by: Gary Guo <gary@garyguo.net>
> [Reworded, adapted for upstream and applied latest changes]
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

Reviewed-by: Wei Liu <wei.liu@kernel.org>

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

* Re: [PATCH v2 26/28] rust: build_assert: add `build_{error,assert}!` macros
  2022-12-02 16:14 ` [PATCH v2 26/28] rust: build_assert: add `build_{error,assert}!` macros ojeda
@ 2022-12-02 18:32   ` Wei Liu
  0 siblings, 0 replies; 46+ messages in thread
From: Wei Liu @ 2022-12-02 18:32 UTC (permalink / raw)
  To: ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Wei Liu

On Fri, Dec 02, 2022 at 05:14:57PM +0100, ojeda@kernel.org wrote:
> From: Gary Guo <gary@garyguo.net>
> 
> Add the `build_error!` and `build_assert!` macros which leverage
> the previously introduced `build_error` crate. Do so in a new
> module, called `build_assert`.
> 
> The former fails the build if the code path calling it can possibly
> be executed. The latter asserts that a boolean expression is `true`
> at compile time.
> 
> In particular, `build_assert!` can be used in some contexts where
> `static_assert!` cannot:
> 
>     fn f1<const N: usize>() {
>         static_assert!(N > 1);` // Error.
>         build_assert!(N > 1);   // Build-time check.
>         assert!(N > 1);         // Run-time check.
>     }
> 
>     #[inline]
>     fn f2(n: usize) {
>         static_assert!(n > 1);  // Error.
>         build_assert!(n > 1);   // Build-time check.
>         assert!(n > 1);         // Run-time check.
>     }
> 
> Signed-off-by: Gary Guo <gary@garyguo.net>
> [Reworded, adapted for upstream and applied latest changes]
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

Reviewed-by: Wei Liu <wei.liu@kernel.org>

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

* Re: [PATCH v2 27/28] rust: types: add `Either` type
  2022-12-02 16:14 ` [PATCH v2 27/28] rust: types: add `Either` type ojeda
@ 2022-12-02 23:41   ` Josh Triplett
  2022-12-04  0:58     ` Miguel Ojeda
  2022-12-04 10:31     ` Gary Guo
  0 siblings, 2 replies; 46+ messages in thread
From: Josh Triplett @ 2022-12-02 23:41 UTC (permalink / raw)
  To: ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Wei Liu

On Fri, Dec 02, 2022 at 05:14:58PM +0100, ojeda@kernel.org wrote:
> From: Wedson Almeida Filho <wedsonaf@gmail.com>
> 
> Introduce the new `types` module of the `kernel` crate with
> `Either` as its first type.
> 
> `Either<L, R>` is a sum type that always holds either a value
> of type `L` (`Left` variant) or `R` (`Right` variant).
> 
> For instance:
> 
>     struct Executor {
>         queue: Either<BoxedQueue, &'static Queue>,
>     }

This specific example seems like it would be better served by the
existing `Cow` type.

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

* Re: [PATCH v2 05/28] rust: macros: add `concat_idents!` proc macro
  2022-12-02 16:14 ` [PATCH v2 05/28] rust: macros: add `concat_idents!` proc macro ojeda
@ 2022-12-04  0:20   ` Gary Guo
  0 siblings, 0 replies; 46+ messages in thread
From: Gary Guo @ 2022-12-04  0:20 UTC (permalink / raw)
  To: ojeda, Finn Behrens
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches

On Fri,  2 Dec 2022 17:14:36 +0100
ojeda@kernel.org wrote:

> From: Björn Roy Baron <bjorn3_gh@protonmail.com>
> 
> This macro provides similar functionality to the unstable feature
> `concat_idents` without having to rely on it.
> 
> For instance:
> 
>     let x_1 = 42;
>     let x_2 = concat_idents!(x, _1);
>     assert!(x_1 == x_2);
> 
> It has different behavior with respect to macro hygiene. Unlike
> the unstable `concat_idents!` macro, it allows, for example,
> referring to local variables by taking the span of the second
> macro as span for the output identifier.
> 
> Signed-off-by: Björn Roy Baron <bjorn3_gh@protonmail.com>
> Reviewed-by: Finn Behrens <me@kloenk.dev>
> [Reworded, adapted for upstream and applied latest changes]
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
> ---
>  rust/macros/concat_idents.rs | 23 +++++++++++++++++++
>  rust/macros/lib.rs           | 44 ++++++++++++++++++++++++++++++++++++
>  2 files changed, 67 insertions(+)
>  create mode 100644 rust/macros/concat_idents.rs
> 
> diff --git a/rust/macros/concat_idents.rs b/rust/macros/concat_idents.rs
> new file mode 100644
> index 000000000000..7e4b450f3a50
> --- /dev/null
> +++ b/rust/macros/concat_idents.rs
> @@ -0,0 +1,23 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +use proc_macro::{token_stream, Ident, TokenStream, TokenTree};
> +
> +use crate::helpers::expect_punct;
> +
> +fn expect_ident(it: &mut token_stream::IntoIter) -> Ident {
> +    if let Some(TokenTree::Ident(ident)) = it.next() {
> +        ident
> +    } else {
> +        panic!("Expected Ident")
> +    }
> +}
> +
> +pub(crate) fn concat_idents(ts: TokenStream) -> TokenStream {
> +    let mut it = ts.into_iter();
> +    let a = expect_ident(&mut it);
> +    assert_eq!(expect_punct(&mut it), ',');
> +    let b = expect_ident(&mut it);
> +    assert!(it.next().is_none(), "only two idents can be concatenated");
> +    let res = Ident::new(&format!("{a}{b}"), b.span());
> +    TokenStream::from_iter([TokenTree::Ident(res)])
> +}
> diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
> index 91764bfb1f89..15555e7ff487 100644
> --- a/rust/macros/lib.rs
> +++ b/rust/macros/lib.rs
> @@ -2,6 +2,7 @@
>  
>  //! Crate for all kernel procedural macros.
>  
> +mod concat_idents;
>  mod helpers;
>  mod module;
>  
> @@ -70,3 +71,46 @@ use proc_macro::TokenStream;
>  pub fn module(ts: TokenStream) -> TokenStream {
>      module::module(ts)
>  }
> +
> +/// Concatenate two identifiers.
> +///
> +/// This is useful in macros that need to declare or reference items with names
> +/// starting with a fixed prefix and ending in a user specified name. The resulting
> +/// identifier has the span of the second argument.
> +///
> +/// # Examples
> +///
> +/// ```ignore
> +/// use kernel::macro::concat_idents;
> +///
> +/// macro_rules! pub_no_prefix {
> +///     ($prefix:ident, $($newname:ident),+) => {
> +///         $(pub(crate) const $newname: u32 = kernel::macros::concat_idents!($prefix, $newname);)+
> +///     };
> +/// }
> +///
> +/// pub_no_prefix!(
> +///     binder_driver_return_protocol_,
> +///     BR_OK,
> +///     BR_ERROR,
> +///     BR_TRANSACTION,
> +///     BR_REPLY,
> +///     BR_DEAD_REPLY,
> +///     BR_TRANSACTION_COMPLETE,
> +///     BR_INCREFS,
> +///     BR_ACQUIRE,
> +///     BR_RELEASE,
> +///     BR_DECREFS,
> +///     BR_NOOP,
> +///     BR_SPAWN_LOOPER,
> +///     BR_DEAD_BINDER,
> +///     BR_CLEAR_DEATH_NOTIFICATION_DONE,
> +///     BR_FAILED_REPLY
> +/// );
> +///
> +/// assert_eq!(BR_OK, binder_driver_return_protocol_BR_OK);
> +/// ```
> +#[proc_macro]
> +pub fn concat_idents(ts: TokenStream) -> TokenStream {
> +    concat_idents::concat_idents(ts)
> +}

Reviewed-by: Gary Guo <gary@garyguo.net>

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

* Re: [PATCH v2 27/28] rust: types: add `Either` type
  2022-12-02 23:41   ` Josh Triplett
@ 2022-12-04  0:58     ` Miguel Ojeda
  2022-12-04 10:31     ` Gary Guo
  1 sibling, 0 replies; 46+ messages in thread
From: Miguel Ojeda @ 2022-12-04  0:58 UTC (permalink / raw)
  To: Josh Triplett
  Cc: ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Wei Liu

On Sat, Dec 3, 2022 at 12:42 AM Josh Triplett <josh@joshtriplett.org> wrote:
>
> This specific example seems like it would be better served by the
> existing `Cow` type.

Yeah, possibly -- it is taken from one of the use cases in the full
repository. Perhaps it was deemed simpler, or providing a way to go to
an owned instance was to be avoided.

Thanks for taking a look!

Cheers,
Miguel

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

* Re: [PATCH v2 00/28] Rust core additions
  2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
                   ` (27 preceding siblings ...)
  2022-12-02 16:14 ` [PATCH v2 28/28] rust: types: add `Opaque` type ojeda
@ 2022-12-04  1:05 ` Miguel Ojeda
  28 siblings, 0 replies; 46+ messages in thread
From: Miguel Ojeda @ 2022-12-04  1:05 UTC (permalink / raw)
  To: ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches

On Fri, Dec 2, 2022 at 5:15 PM <ojeda@kernel.org> wrote:
>
> This is v2 of the first batch of changes to upstream the rest of
> the Rust support. v1 is at:
>
>     https://lore.kernel.org/rust-for-linux/20221110164152.26136-1-ojeda@kernel.org/
>
> I collected the tags and applied the agreed changes. The full diff
> follows (with respect to v1), since they are minor enough.
>
> I will be applying the patches tomorrow, since v1 has had more than
> three weeks of review time.

Queued.

Cheers,
Miguel

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

* Re: [PATCH v2 27/28] rust: types: add `Either` type
  2022-12-02 23:41   ` Josh Triplett
  2022-12-04  0:58     ` Miguel Ojeda
@ 2022-12-04 10:31     ` Gary Guo
  2022-12-04 17:36       ` Wedson Almeida Filho
  1 sibling, 1 reply; 46+ messages in thread
From: Gary Guo @ 2022-12-04 10:31 UTC (permalink / raw)
  To: Josh Triplett
  Cc: ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Wei Liu

On Fri, 2 Dec 2022 15:41:59 -0800
Josh Triplett <josh@joshtriplett.org> wrote:

> On Fri, Dec 02, 2022 at 05:14:58PM +0100, ojeda@kernel.org wrote:
> > From: Wedson Almeida Filho <wedsonaf@gmail.com>
> > 
> > Introduce the new `types` module of the `kernel` crate with
> > `Either` as its first type.
> > 
> > `Either<L, R>` is a sum type that always holds either a value
> > of type `L` (`Left` variant) or `R` (`Right` variant).
> > 
> > For instance:
> > 
> >     struct Executor {
> >         queue: Either<BoxedQueue, &'static Queue>,
> >     }  
> 
> This specific example seems like it would be better served by the
> existing `Cow` type.

We use `no_global_oom_handling`, which gates most `ToOwned`
implementations (e.g. `str` cannot implement `to_owned()` because it
cannot guarantee allocation success).

So the Rust `Cow` is pretty much useless in the kernel.

Best,
Gary

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

* Re: [PATCH v2 20/28] rust: str: add `Formatter` type
  2022-12-02 16:14 ` [PATCH v2 20/28] rust: str: add `Formatter` type ojeda
@ 2022-12-04 15:41   ` Dr. David Alan Gilbert
  2022-12-04 17:26     ` Wedson Almeida Filho
  0 siblings, 1 reply; 46+ messages in thread
From: Dr. David Alan Gilbert @ 2022-12-04 15:41 UTC (permalink / raw)
  To: ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Adam Bratschi-Kaye

* ojeda@kernel.org (ojeda@kernel.org) wrote:
> From: Wedson Almeida Filho <wedsonaf@gmail.com>
> 
> Add the `Formatter` type, which leverages `RawFormatter`,
> but fails if callers attempt to write more than will fit
> in the buffer.
> 
> In order to so, implement the `RawFormatter::from_buffer()`
> constructor as well.
> 
> Co-developed-by: Adam Bratschi-Kaye <ark.email@gmail.com>
> Signed-off-by: Adam Bratschi-Kaye <ark.email@gmail.com>
> Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com>
> Reviewed-by: Gary Guo <gary@garyguo.net>
> [Reworded, adapted for upstream and applied latest changes]
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
> ---
>  rust/kernel/str.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 57 insertions(+)
> 
> diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
> index a995db36486f..ce207d1b3d2a 100644
> --- a/rust/kernel/str.rs
> +++ b/rust/kernel/str.rs
> @@ -406,6 +406,23 @@ impl RawFormatter {
>          }
>      }
>  
> +    /// Creates a new instance of [`RawFormatter`] with the given buffer.
> +    ///
> +    /// # Safety
> +    ///
> +    /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes
> +    /// for the lifetime of the returned [`RawFormatter`].
> +    pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self {
> +        let pos = buf as usize;
> +        // INVARIANT: We ensure that `end` is never less then `buf`, and the safety requirements
> +        // guarantees that the memory region is valid for writes.
> +        Self {
> +            pos,
> +            beg: pos,
> +            end: pos.saturating_add(len),
> +        }
> +    }
> +
>      /// Returns the current insert position.
>      ///
>      /// N.B. It may point to invalid memory.
> @@ -439,3 +456,43 @@ impl fmt::Write for RawFormatter {
>          Ok(())
>      }
>  }
> +
> +/// Allows formatting of [`fmt::Arguments`] into a raw buffer.
> +///
> +/// Fails if callers attempt to write more than will fit in the buffer.
> +pub(crate) struct Formatter(RawFormatter);
> +
> +impl Formatter {
> +    /// Creates a new instance of [`Formatter`] with the given buffer.
> +    ///
> +    /// # Safety
> +    ///
> +    /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes
> +    /// for the lifetime of the returned [`Formatter`].
> +    #[allow(dead_code)]
> +    pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self {
> +        // SAFETY: The safety requirements of this function satisfy those of the callee.
> +        Self(unsafe { RawFormatter::from_buffer(buf, len) })
> +    }
> +}
> +
> +impl Deref for Formatter {
> +    type Target = RawFormatter;
> +
> +    fn deref(&self) -> &Self::Target {
> +        &self.0
> +    }
> +}
> +
> +impl fmt::Write for Formatter {
> +    fn write_str(&mut self, s: &str) -> fmt::Result {
> +        self.0.write_str(s)?;
> +
> +        // Fail the request if we go past the end of the buffer.

Reading this for the first time, I'm surprised by this, perhaps a
bit more comment is needed?  I was expecting that nothing would
let pos pass end.

Dave

> +        if self.0.pos > self.0.end {
> +            Err(fmt::Error)
> +        } else {
> +            Ok(())
> +        }
> +    }
> +}
> -- 
> 2.38.1
> 
-- 
 -----Open up your eyes, open up your mind, open up your code -------   
/ Dr. David Alan Gilbert    |       Running GNU/Linux       | Happy  \ 
\        dave @ treblig.org |                               | In Hex /
 \ _________________________|_____ http://www.treblig.org   |_______/

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

* Re: [PATCH v2 20/28] rust: str: add `Formatter` type
  2022-12-04 15:41   ` Dr. David Alan Gilbert
@ 2022-12-04 17:26     ` Wedson Almeida Filho
  2022-12-04 18:05       ` Dr. David Alan Gilbert
  0 siblings, 1 reply; 46+ messages in thread
From: Wedson Almeida Filho @ 2022-12-04 17:26 UTC (permalink / raw)
  To: Dr. David Alan Gilbert
  Cc: ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
	rust-for-linux, linux-kernel, patches, Adam Bratschi-Kaye

On Sun, 4 Dec 2022 at 15:41, Dr. David Alan Gilbert <dave@treblig.org> wrote:
>
> * ojeda@kernel.org (ojeda@kernel.org) wrote:
> > From: Wedson Almeida Filho <wedsonaf@gmail.com>
> >
> > Add the `Formatter` type, which leverages `RawFormatter`,
> > but fails if callers attempt to write more than will fit
> > in the buffer.
> >
> > In order to so, implement the `RawFormatter::from_buffer()`
> > constructor as well.
> >
> > Co-developed-by: Adam Bratschi-Kaye <ark.email@gmail.com>
> > Signed-off-by: Adam Bratschi-Kaye <ark.email@gmail.com>
> > Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com>
> > Reviewed-by: Gary Guo <gary@garyguo.net>
> > [Reworded, adapted for upstream and applied latest changes]
> > Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
> > ---
> >  rust/kernel/str.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++
> >  1 file changed, 57 insertions(+)
> >
> > diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
> > index a995db36486f..ce207d1b3d2a 100644
> > --- a/rust/kernel/str.rs
> > +++ b/rust/kernel/str.rs
> > @@ -406,6 +406,23 @@ impl RawFormatter {
> >          }
> >      }
> >
> > +    /// Creates a new instance of [`RawFormatter`] with the given buffer.
> > +    ///
> > +    /// # Safety
> > +    ///
> > +    /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes
> > +    /// for the lifetime of the returned [`RawFormatter`].
> > +    pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self {
> > +        let pos = buf as usize;
> > +        // INVARIANT: We ensure that `end` is never less then `buf`, and the safety requirements
> > +        // guarantees that the memory region is valid for writes.
> > +        Self {
> > +            pos,
> > +            beg: pos,
> > +            end: pos.saturating_add(len),
> > +        }
> > +    }
> > +
> >      /// Returns the current insert position.
> >      ///
> >      /// N.B. It may point to invalid memory.
> > @@ -439,3 +456,43 @@ impl fmt::Write for RawFormatter {
> >          Ok(())
> >      }
> >  }
> > +
> > +/// Allows formatting of [`fmt::Arguments`] into a raw buffer.
> > +///
> > +/// Fails if callers attempt to write more than will fit in the buffer.
> > +pub(crate) struct Formatter(RawFormatter);

Here we mention that `Formatter` fails if callers attempt to write
more than will fit in the buffer.

This is in contrast with `RawFormatter`, which doesn't fail in such
cases. There's also a comment there explaining it (not visible in this
patch because it's already there), but I reproduce below:

/// Allows formatting of [`fmt::Arguments`] into a raw buffer.
///
/// It does not fail if callers write past the end of the buffer so
that they can calculate the
/// size required to fit everything.
///
/// # Invariants
///
/// The memory region between `pos` (inclusive) and `end` (exclusive)
is valid for writes if `pos`
/// is less than `end`.
pub(crate) struct RawFormatter {

`RawFormatter` is used to implement the "%pA" printf specifier, which
requires this behaviour.

> > +
> > +impl Formatter {
> > +    /// Creates a new instance of [`Formatter`] with the given buffer.
> > +    ///
> > +    /// # Safety
> > +    ///
> > +    /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes
> > +    /// for the lifetime of the returned [`Formatter`].
> > +    #[allow(dead_code)]
> > +    pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self {
> > +        // SAFETY: The safety requirements of this function satisfy those of the callee.
> > +        Self(unsafe { RawFormatter::from_buffer(buf, len) })
> > +    }
> > +}
> > +
> > +impl Deref for Formatter {
> > +    type Target = RawFormatter;
> > +
> > +    fn deref(&self) -> &Self::Target {
> > +        &self.0
> > +    }
> > +}
> > +
> > +impl fmt::Write for Formatter {
> > +    fn write_str(&mut self, s: &str) -> fmt::Result {
> > +        self.0.write_str(s)?;
> > +
> > +        // Fail the request if we go past the end of the buffer.
>
> Reading this for the first time, I'm surprised by this, perhaps a
> bit more comment is needed?  I was expecting that nothing would
> let pos pass end.

Given the comments I highlight above, do you think we still need more?

(My impression is that you're reading this without the context I tried
to explain above, and this context may perhaps be sufficient.)

Thanks,
-Wedson

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

* Re: [PATCH v2 27/28] rust: types: add `Either` type
  2022-12-04 10:31     ` Gary Guo
@ 2022-12-04 17:36       ` Wedson Almeida Filho
  2022-12-05 13:53         ` Miguel Ojeda
  2022-12-05 23:00         ` Josh Triplett
  0 siblings, 2 replies; 46+ messages in thread
From: Wedson Almeida Filho @ 2022-12-04 17:36 UTC (permalink / raw)
  To: Gary Guo
  Cc: Josh Triplett, ojeda, Alex Gaynor, Boqun Feng,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Wei Liu

On Sun, 4 Dec 2022 at 10:31, Gary Guo <gary@garyguo.net> wrote:
>
> On Fri, 2 Dec 2022 15:41:59 -0800
> Josh Triplett <josh@joshtriplett.org> wrote:
>
> > On Fri, Dec 02, 2022 at 05:14:58PM +0100, ojeda@kernel.org wrote:
> > > From: Wedson Almeida Filho <wedsonaf@gmail.com>
> > >
> > > Introduce the new `types` module of the `kernel` crate with
> > > `Either` as its first type.
> > >
> > > `Either<L, R>` is a sum type that always holds either a value
> > > of type `L` (`Left` variant) or `R` (`Right` variant).
> > >
> > > For instance:
> > >
> > >     struct Executor {
> > >         queue: Either<BoxedQueue, &'static Queue>,
> > >     }
> >
> > This specific example seems like it would be better served by the
> > existing `Cow` type.
>
> We use `no_global_oom_handling`, which gates most `ToOwned`
> implementations (e.g. `str` cannot implement `to_owned()` because it
> cannot guarantee allocation success).
>
> So the Rust `Cow` is pretty much useless in the kernel.

It's also implemented in `std`, which the kernel doesn't include.
(Which is actually good for us, since we can't really use it.)

Josh, how do you feel about adding a `TryToOwned` trait to
`core::borrow`? This would be similar to the precedent of `TryFrom` in
addition to `From` for the fallible case, and would be usable by the
kernel.

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

* Re: [PATCH v2 20/28] rust: str: add `Formatter` type
  2022-12-04 17:26     ` Wedson Almeida Filho
@ 2022-12-04 18:05       ` Dr. David Alan Gilbert
  0 siblings, 0 replies; 46+ messages in thread
From: Dr. David Alan Gilbert @ 2022-12-04 18:05 UTC (permalink / raw)
  To: Wedson Almeida Filho
  Cc: ojeda, Alex Gaynor, Boqun Feng, Gary Guo, Björn Roy Baron,
	rust-for-linux, linux-kernel, patches, Adam Bratschi-Kaye

* Wedson Almeida Filho (wedsonaf@gmail.com) wrote:
> On Sun, 4 Dec 2022 at 15:41, Dr. David Alan Gilbert <dave@treblig.org> wrote:
> >
> > * ojeda@kernel.org (ojeda@kernel.org) wrote:
> > > From: Wedson Almeida Filho <wedsonaf@gmail.com>
> > >
> > > Add the `Formatter` type, which leverages `RawFormatter`,
> > > but fails if callers attempt to write more than will fit
> > > in the buffer.
> > >
> > > In order to so, implement the `RawFormatter::from_buffer()`
> > > constructor as well.
> > >
> > > Co-developed-by: Adam Bratschi-Kaye <ark.email@gmail.com>
> > > Signed-off-by: Adam Bratschi-Kaye <ark.email@gmail.com>
> > > Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com>
> > > Reviewed-by: Gary Guo <gary@garyguo.net>
> > > [Reworded, adapted for upstream and applied latest changes]
> > > Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
> > > ---
> > >  rust/kernel/str.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++
> > >  1 file changed, 57 insertions(+)
> > >
> > > diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
> > > index a995db36486f..ce207d1b3d2a 100644
> > > --- a/rust/kernel/str.rs
> > > +++ b/rust/kernel/str.rs
> > > @@ -406,6 +406,23 @@ impl RawFormatter {
> > >          }
> > >      }
> > >
> > > +    /// Creates a new instance of [`RawFormatter`] with the given buffer.
> > > +    ///
> > > +    /// # Safety
> > > +    ///
> > > +    /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes
> > > +    /// for the lifetime of the returned [`RawFormatter`].
> > > +    pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self {
> > > +        let pos = buf as usize;
> > > +        // INVARIANT: We ensure that `end` is never less then `buf`, and the safety requirements
> > > +        // guarantees that the memory region is valid for writes.
> > > +        Self {
> > > +            pos,
> > > +            beg: pos,
> > > +            end: pos.saturating_add(len),
> > > +        }
> > > +    }
> > > +
> > >      /// Returns the current insert position.
> > >      ///
> > >      /// N.B. It may point to invalid memory.
> > > @@ -439,3 +456,43 @@ impl fmt::Write for RawFormatter {
> > >          Ok(())
> > >      }
> > >  }
> > > +
> > > +/// Allows formatting of [`fmt::Arguments`] into a raw buffer.
> > > +///
> > > +/// Fails if callers attempt to write more than will fit in the buffer.
> > > +pub(crate) struct Formatter(RawFormatter);
> 
> Here we mention that `Formatter` fails if callers attempt to write
> more than will fit in the buffer.
> 
> This is in contrast with `RawFormatter`, which doesn't fail in such
> cases. There's also a comment there explaining it (not visible in this
> patch because it's already there), but I reproduce below:
> 
> /// Allows formatting of [`fmt::Arguments`] into a raw buffer.
> ///
> /// It does not fail if callers write past the end of the buffer so
> that they can calculate the
> /// size required to fit everything.
> ///
> /// # Invariants
> ///
> /// The memory region between `pos` (inclusive) and `end` (exclusive)
> is valid for writes if `pos`
> /// is less than `end`.
> pub(crate) struct RawFormatter {
> 
> `RawFormatter` is used to implement the "%pA" printf specifier, which
> requires this behaviour.
> 
> > > +
> > > +impl Formatter {
> > > +    /// Creates a new instance of [`Formatter`] with the given buffer.
> > > +    ///
> > > +    /// # Safety
> > > +    ///
> > > +    /// The memory region starting at `buf` and extending for `len` bytes must be valid for writes
> > > +    /// for the lifetime of the returned [`Formatter`].
> > > +    #[allow(dead_code)]
> > > +    pub(crate) unsafe fn from_buffer(buf: *mut u8, len: usize) -> Self {
> > > +        // SAFETY: The safety requirements of this function satisfy those of the callee.
> > > +        Self(unsafe { RawFormatter::from_buffer(buf, len) })
> > > +    }
> > > +}
> > > +
> > > +impl Deref for Formatter {
> > > +    type Target = RawFormatter;
> > > +
> > > +    fn deref(&self) -> &Self::Target {
> > > +        &self.0
> > > +    }
> > > +}
> > > +
> > > +impl fmt::Write for Formatter {
> > > +    fn write_str(&mut self, s: &str) -> fmt::Result {
> > > +        self.0.write_str(s)?;
> > > +
> > > +        // Fail the request if we go past the end of the buffer.
> >
> > Reading this for the first time, I'm surprised by this, perhaps a
> > bit more comment is needed?  I was expecting that nothing would
> > let pos pass end.
> 
> Given the comments I highlight above, do you think we still need more?
> 
> (My impression is that you're reading this without the context I tried
> to explain above, and this context may perhaps be sufficient.)

Thanks for the pointer; I guess I find it trickier when I can't see the
type in self.0 to immediately see it's RawFormatter, and 'Raw' is
abstract enough to need to go hunt to see it's behaviour.

With that context, I wouldn't object to what's there, but how about
something like:

      // RawFormatter (self.0) still updates pos if the buffer
      // is too small, but doesn't fail - we want to fail the request.

Dave

> Thanks,
> -Wedson
-- 
 -----Open up your eyes, open up your mind, open up your code -------   
/ Dr. David Alan Gilbert    |       Running GNU/Linux       | Happy  \ 
\        dave @ treblig.org |                               | In Hex /
 \ _________________________|_____ http://www.treblig.org   |_______/

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

* Re: [PATCH v2 27/28] rust: types: add `Either` type
  2022-12-04 17:36       ` Wedson Almeida Filho
@ 2022-12-05 13:53         ` Miguel Ojeda
  2022-12-05 23:00         ` Josh Triplett
  1 sibling, 0 replies; 46+ messages in thread
From: Miguel Ojeda @ 2022-12-05 13:53 UTC (permalink / raw)
  To: Wedson Almeida Filho
  Cc: Gary Guo, Josh Triplett, ojeda, Alex Gaynor, Boqun Feng,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Wei Liu

On Sun, Dec 4, 2022 at 6:36 PM Wedson Almeida Filho <wedsonaf@gmail.com> wrote:
>
> It's also implemented in `std`, which the kernel doesn't include.
> (Which is actually good for us, since we can't really use it.)

We have it around in the kernel (the `std` one is a re-export), so one
"could" replace the `Either` with `Cow` in the case of the commit
message via ignoring the to-owned side of it (but I assume Josh didn't
mean to suggest that).

Anyway, it can be easily configured out from our `alloc`, so I will
send the patch.

Cheers,
Miguel

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

* Re: [PATCH v2 27/28] rust: types: add `Either` type
  2022-12-04 17:36       ` Wedson Almeida Filho
  2022-12-05 13:53         ` Miguel Ojeda
@ 2022-12-05 23:00         ` Josh Triplett
  1 sibling, 0 replies; 46+ messages in thread
From: Josh Triplett @ 2022-12-05 23:00 UTC (permalink / raw)
  To: Wedson Almeida Filho
  Cc: Gary Guo, ojeda, Alex Gaynor, Boqun Feng, Björn Roy Baron,
	rust-for-linux, linux-kernel, patches, Wei Liu

On Sun, Dec 04, 2022 at 05:36:08PM +0000, Wedson Almeida Filho wrote:
> On Sun, 4 Dec 2022 at 10:31, Gary Guo <gary@garyguo.net> wrote:
> >
> > On Fri, 2 Dec 2022 15:41:59 -0800
> > Josh Triplett <josh@joshtriplett.org> wrote:
> >
> > > On Fri, Dec 02, 2022 at 05:14:58PM +0100, ojeda@kernel.org wrote:
> > > > From: Wedson Almeida Filho <wedsonaf@gmail.com>
> > > >
> > > > Introduce the new `types` module of the `kernel` crate with
> > > > `Either` as its first type.
> > > >
> > > > `Either<L, R>` is a sum type that always holds either a value
> > > > of type `L` (`Left` variant) or `R` (`Right` variant).
> > > >
> > > > For instance:
> > > >
> > > >     struct Executor {
> > > >         queue: Either<BoxedQueue, &'static Queue>,
> > > >     }
> > >
> > > This specific example seems like it would be better served by the
> > > existing `Cow` type.
> >
> > We use `no_global_oom_handling`, which gates most `ToOwned`
> > implementations (e.g. `str` cannot implement `to_owned()` because it
> > cannot guarantee allocation success).
> >
> > So the Rust `Cow` is pretty much useless in the kernel.
> 
> It's also implemented in `std`, which the kernel doesn't include.
> (Which is actually good for us, since we can't really use it.)
> 
> Josh, how do you feel about adding a `TryToOwned` trait to
> `core::borrow`? This would be similar to the precedent of `TryFrom` in
> addition to `From` for the fallible case, and would be usable by the
> kernel.

I'd expect it to be in alloc rather than core (though I suppose it
doesn't *fundamentally* depend on an allocator itself), but I'd be happy
to see a fallible version proposed, yeah.

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

* Re: [PATCH v2 06/28] rust: macros: add `#[vtable]` proc macro
  2022-12-02 16:14 ` [PATCH v2 06/28] rust: macros: add `#[vtable]` " ojeda
@ 2022-12-06 12:49   ` Finn Behrens
  2022-12-06 15:44     ` Miguel Ojeda
  0 siblings, 1 reply; 46+ messages in thread
From: Finn Behrens @ 2022-12-06 12:49 UTC (permalink / raw)
  To: ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Sergio González Collado



On 2 Dec 2022, at 17:14, ojeda@kernel.org wrote:

> From: Gary Guo <gary@garyguo.net>
>
> This procedural macro attribute provides a simple way to declare
> a trait with a set of operations that later users can partially
> implement, providing compile-time `HAS_*` boolean associated
> constants that indicate whether a particular operation was overridden.
>
> This is useful as the Rust counterpart to structs like
> `file_operations` where some pointers may be `NULL`, indicating
> an operation is not provided.
>
> For instance:
>
>     #[vtable]
>     trait Operations {
>         fn read(...) -> Result<usize> {
>             Err(EINVAL)
>         }
>
>         fn write(...) -> Result<usize> {
>             Err(EINVAL)
>         }
>     }
>
>     #[vtable]
>     impl Operations for S {
>         fn read(...) -> Result<usize> {
>             ...
>         }
>     }
>
>     assert_eq!(<S as Operations>::HAS_READ, true);
>     assert_eq!(<S as Operations>::HAS_WRITE, false);
>
> Signed-off-by: Gary Guo <gary@garyguo.net>
> Reviewed-by: Sergio González Collado <sergio.collado@gmail.com>
> [Reworded, adapted for upstream and applied latest changes]
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Reviewed-by: Finn Behrens <fin@nyantec.com>

Regards,
Finn

> ---
>  rust/kernel/prelude.rs |  2 +-
>  rust/macros/lib.rs     | 52 +++++++++++++++++++++++
>  rust/macros/vtable.rs  | 95 ++++++++++++++++++++++++++++++++++++++++++
>  3 files changed, 148 insertions(+), 1 deletion(-)
>  create mode 100644 rust/macros/vtable.rs
>
> diff --git a/rust/kernel/prelude.rs b/rust/kernel/prelude.rs
> index 6a1c6b38327f..7c4c35bf3c66 100644
> --- a/rust/kernel/prelude.rs
> +++ b/rust/kernel/prelude.rs
> @@ -15,7 +15,7 @@ pub use core::pin::Pin;
>
>  pub use alloc::{boxed::Box, vec::Vec};
>
> -pub use macros::module;
> +pub use macros::{module, vtable};
>
>  pub use super::{pr_alert, pr_crit, pr_debug, pr_emerg, pr_err, pr_info, pr_notice, pr_warn};
>
> diff --git a/rust/macros/lib.rs b/rust/macros/lib.rs
> index 15555e7ff487..e40caaf0a656 100644
> --- a/rust/macros/lib.rs
> +++ b/rust/macros/lib.rs
> @@ -5,6 +5,7 @@
>  mod concat_idents;
>  mod helpers;
>  mod module;
> +mod vtable;
>
>  use proc_macro::TokenStream;
>
> @@ -72,6 +73,57 @@ pub fn module(ts: TokenStream) -> TokenStream {
>      module::module(ts)
>  }
>
> +/// Declares or implements a vtable trait.
> +///
> +/// Linux's use of pure vtables is very close to Rust traits, but they differ
> +/// in how unimplemented functions are represented. In Rust, traits can provide
> +/// default implementation for all non-required methods (and the default
> +/// implementation could just return `Error::EINVAL`); Linux typically use C
> +/// `NULL` pointers to represent these functions.
> +///
> +/// This attribute is intended to close the gap. Traits can be declared and
> +/// implemented with the `#[vtable]` attribute, and a `HAS_*` associated constant
> +/// will be generated for each method in the trait, indicating if the implementor
> +/// has overridden a method.
> +///
> +/// This attribute is not needed if all methods are required.
> +///
> +/// # Examples
> +///
> +/// ```ignore
> +/// use kernel::prelude::*;
> +///
> +/// // Declares a `#[vtable]` trait
> +/// #[vtable]
> +/// pub trait Operations: Send + Sync + Sized {
> +///     fn foo(&self) -> Result<()> {
> +///         Err(EINVAL)
> +///     }
> +///
> +///     fn bar(&self) -> Result<()> {
> +///         Err(EINVAL)
> +///     }
> +/// }
> +///
> +/// struct Foo;
> +///
> +/// // Implements the `#[vtable]` trait
> +/// #[vtable]
> +/// impl Operations for Foo {
> +///     fn foo(&self) -> Result<()> {
> +/// #        Err(EINVAL)
> +///         // ...
> +///     }
> +/// }
> +///
> +/// assert_eq!(<Foo as Operations>::HAS_FOO, true);
> +/// assert_eq!(<Foo as Operations>::HAS_BAR, false);
> +/// ```
> +#[proc_macro_attribute]
> +pub fn vtable(attr: TokenStream, ts: TokenStream) -> TokenStream {
> +    vtable::vtable(attr, ts)
> +}
> +
>  /// Concatenate two identifiers.
>  ///
>  /// This is useful in macros that need to declare or reference items with names
> diff --git a/rust/macros/vtable.rs b/rust/macros/vtable.rs
> new file mode 100644
> index 000000000000..34d5e7fb5768
> --- /dev/null
> +++ b/rust/macros/vtable.rs
> @@ -0,0 +1,95 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +use proc_macro::{Delimiter, Group, TokenStream, TokenTree};
> +use std::collections::HashSet;
> +use std::fmt::Write;
> +
> +pub(crate) fn vtable(_attr: TokenStream, ts: TokenStream) -> TokenStream {
> +    let mut tokens: Vec<_> = ts.into_iter().collect();
> +
> +    // Scan for the `trait` or `impl` keyword.
> +    let is_trait = tokens
> +        .iter()
> +        .find_map(|token| match token {
> +            TokenTree::Ident(ident) => match ident.to_string().as_str() {
> +                "trait" => Some(true),
> +                "impl" => Some(false),
> +                _ => None,
> +            },
> +            _ => None,
> +        })
> +        .expect("#[vtable] attribute should only be applied to trait or impl block");
> +
> +    // Retrieve the main body. The main body should be the last token tree.
> +    let body = match tokens.pop() {
> +        Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => group,
> +        _ => panic!("cannot locate main body of trait or impl block"),
> +    };
> +
> +    let mut body_it = body.stream().into_iter();
> +    let mut functions = Vec::new();
> +    let mut consts = HashSet::new();
> +    while let Some(token) = body_it.next() {
> +        match token {
> +            TokenTree::Ident(ident) if ident.to_string() == "fn" => {
> +                let fn_name = match body_it.next() {
> +                    Some(TokenTree::Ident(ident)) => ident.to_string(),
> +                    // Possibly we've encountered a fn pointer type instead.
> +                    _ => continue,
> +                };
> +                functions.push(fn_name);
> +            }
> +            TokenTree::Ident(ident) if ident.to_string() == "const" => {
> +                let const_name = match body_it.next() {
> +                    Some(TokenTree::Ident(ident)) => ident.to_string(),
> +                    // Possibly we've encountered an inline const block instead.
> +                    _ => continue,
> +                };
> +                consts.insert(const_name);
> +            }
> +            _ => (),
> +        }
> +    }
> +
> +    let mut const_items;
> +    if is_trait {
> +        const_items = "
> +                /// A marker to prevent implementors from forgetting to use [`#[vtable]`](vtable)
> +                /// attribute when implementing this trait.
> +                const USE_VTABLE_ATTR: ();
> +        "
> +        .to_owned();
> +
> +        for f in functions {
> +            let gen_const_name = format!("HAS_{}", f.to_uppercase());
> +            // Skip if it's declared already -- this allows user override.
> +            if consts.contains(&gen_const_name) {
> +                continue;
> +            }
> +            // We don't know on the implementation-site whether a method is required or provided
> +            // so we have to generate a const for all methods.
> +            write!(
> +                const_items,
> +                "/// Indicates if the `{f}` method is overridden by the implementor.
> +                const {gen_const_name}: bool = false;",
> +            )
> +            .unwrap();
> +        }
> +    } else {
> +        const_items = "const USE_VTABLE_ATTR: () = ();".to_owned();
> +
> +        for f in functions {
> +            let gen_const_name = format!("HAS_{}", f.to_uppercase());
> +            if consts.contains(&gen_const_name) {
> +                continue;
> +            }
> +            write!(const_items, "const {gen_const_name}: bool = true;").unwrap();
> +        }
> +    }
> +
> +    let new_body = vec![const_items.parse().unwrap(), body.stream()]
> +        .into_iter()
> +        .collect();
> +    tokens.push(TokenTree::Group(Group::new(Delimiter::Brace, new_body)));
> +    tokens.into_iter().collect()
> +}
> -- 
> 2.38.1

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

* Re: [PATCH v2 09/28] rust: error: add codes from `errno-base.h`
  2022-12-02 16:14 ` [PATCH v2 09/28] rust: error: add codes from `errno-base.h` ojeda
@ 2022-12-06 12:52   ` Finn Behrens
  0 siblings, 0 replies; 46+ messages in thread
From: Finn Behrens @ 2022-12-06 12:52 UTC (permalink / raw)
  To: ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Viktor Garske



On 2 Dec 2022, at 17:14, ojeda@kernel.org wrote:

> From: Viktor Garske <viktor@v-gar.de>
>
> Only a few codes were added so far. With the `declare_err!`
> macro in place, add the remaining ones (which is most of them)
> from `include/uapi/asm-generic/errno-base.h`.
>
> Co-developed-by: Wedson Almeida Filho <wedsonaf@gmail.com>
> Signed-off-by: Wedson Almeida Filho <wedsonaf@gmail.com>
> Signed-off-by: Viktor Garske <viktor@v-gar.de>
> Reviewed-by: Gary Guo <gary@garyguo.net>
> [Reworded, adapted for upstream and applied latest changes]
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Reviewed-by: Finn Behrens <fin@nyantec.com>

Regards,
Finn

> ---
>  rust/kernel/error.rs | 33 +++++++++++++++++++++++++++++++++
>  1 file changed, 33 insertions(+)
>
> diff --git a/rust/kernel/error.rs b/rust/kernel/error.rs
> index b843f3445483..861746f2422d 100644
> --- a/rust/kernel/error.rs
> +++ b/rust/kernel/error.rs
> @@ -17,7 +17,40 @@ pub mod code {
>          };
>      }
>
> +    declare_err!(EPERM, "Operation not permitted.");
> +    declare_err!(ENOENT, "No such file or directory.");
> +    declare_err!(ESRCH, "No such process.");
> +    declare_err!(EINTR, "Interrupted system call.");
> +    declare_err!(EIO, "I/O error.");
> +    declare_err!(ENXIO, "No such device or address.");
> +    declare_err!(E2BIG, "Argument list too long.");
> +    declare_err!(ENOEXEC, "Exec format error.");
> +    declare_err!(EBADF, "Bad file number.");
> +    declare_err!(ECHILD, "Exec format error.");
> +    declare_err!(EAGAIN, "Try again.");
>      declare_err!(ENOMEM, "Out of memory.");
> +    declare_err!(EACCES, "Permission denied.");
> +    declare_err!(EFAULT, "Bad address.");
> +    declare_err!(ENOTBLK, "Block device required.");
> +    declare_err!(EBUSY, "Device or resource busy.");
> +    declare_err!(EEXIST, "File exists.");
> +    declare_err!(EXDEV, "Cross-device link.");
> +    declare_err!(ENODEV, "No such device.");
> +    declare_err!(ENOTDIR, "Not a directory.");
> +    declare_err!(EISDIR, "Is a directory.");
> +    declare_err!(EINVAL, "Invalid argument.");
> +    declare_err!(ENFILE, "File table overflow.");
> +    declare_err!(EMFILE, "Too many open files.");
> +    declare_err!(ENOTTY, "Not a typewriter.");
> +    declare_err!(ETXTBSY, "Text file busy.");
> +    declare_err!(EFBIG, "File too large.");
> +    declare_err!(ENOSPC, "No space left on device.");
> +    declare_err!(ESPIPE, "Illegal seek.");
> +    declare_err!(EROFS, "Read-only file system.");
> +    declare_err!(EMLINK, "Too many links.");
> +    declare_err!(EPIPE, "Broken pipe.");
> +    declare_err!(EDOM, "Math argument out of domain of func.");
> +    declare_err!(ERANGE, "Math result not representable.");
>  }
>
>  /// Generic integer kernel error.
> -- 
> 2.38.1

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

* Re: [PATCH v2 13/28] rust: alloc: add `Vec::try_with_capacity{,_in}()` constructors
  2022-12-02 16:14 ` [PATCH v2 13/28] rust: alloc: add `Vec::try_with_capacity{,_in}()` constructors ojeda
@ 2022-12-06 12:55   ` Finn Behrens
  0 siblings, 0 replies; 46+ messages in thread
From: Finn Behrens @ 2022-12-06 12:55 UTC (permalink / raw)
  To: ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches



On 2 Dec 2022, at 17:14, ojeda@kernel.org wrote:

> From: Miguel Ojeda <ojeda@kernel.org>
>
> Add `Vec::try_with_capacity()` and `Vec::try_with_capacity_in()` as
> the fallible versions of `Vec::with_capacity()` and
> `Vec::with_capacity_in()`, respectively.
>
> The implementations follow the originals and use the previously
> added `RawVec::try_with_capacity_in()`.
>
> In turn, `Vec::try_with_capacity()` will be used to implement
> the `CString` type (which wraps a `Vec<u8>`) in a later patch.
>
> Reviewed-by: Gary Guo <gary@garyguo.net>
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Reviewed-by: Finn Behrens <fin@nyantec.com>

Regards,
Finn

> ---
>  rust/alloc/raw_vec.rs |  1 -
>  rust/alloc/vec/mod.rs | 89 +++++++++++++++++++++++++++++++++++++++++++
>  2 files changed, 89 insertions(+), 1 deletion(-)
>
> diff --git a/rust/alloc/raw_vec.rs b/rust/alloc/raw_vec.rs
> index c342f3843972..eb77db5def55 100644
> --- a/rust/alloc/raw_vec.rs
> +++ b/rust/alloc/raw_vec.rs
> @@ -135,7 +135,6 @@ impl<T, A: Allocator> RawVec<T, A> {
>
>      /// Like `try_with_capacity`, but parameterized over the choice of
>      /// allocator for the returned `RawVec`.
> -    #[allow(dead_code)]
>      #[inline]
>      pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<Self, TryReserveError> {
>          Self::try_allocate_in(capacity, AllocInit::Uninitialized, alloc)
> diff --git a/rust/alloc/vec/mod.rs b/rust/alloc/vec/mod.rs
> index 540787804cc2..8ac6c1e3b2a8 100644
> --- a/rust/alloc/vec/mod.rs
> +++ b/rust/alloc/vec/mod.rs
> @@ -472,6 +472,48 @@ impl<T> Vec<T> {
>          Self::with_capacity_in(capacity, Global)
>      }
>
> +    /// Tries to construct a new, empty `Vec<T>` with the specified capacity.
> +    ///
> +    /// The vector will be able to hold exactly `capacity` elements without
> +    /// reallocating. If `capacity` is 0, the vector will not allocate.
> +    ///
> +    /// It is important to note that although the returned vector has the
> +    /// *capacity* specified, the vector will have a zero *length*. For an
> +    /// explanation of the difference between length and capacity, see
> +    /// *[Capacity and reallocation]*.
> +    ///
> +    /// [Capacity and reallocation]: #capacity-and-reallocation
> +    ///
> +    /// # Examples
> +    ///
> +    /// ```
> +    /// let mut vec = Vec::try_with_capacity(10).unwrap();
> +    ///
> +    /// // The vector contains no items, even though it has capacity for more
> +    /// assert_eq!(vec.len(), 0);
> +    /// assert_eq!(vec.capacity(), 10);
> +    ///
> +    /// // These are all done without reallocating...
> +    /// for i in 0..10 {
> +    ///     vec.push(i);
> +    /// }
> +    /// assert_eq!(vec.len(), 10);
> +    /// assert_eq!(vec.capacity(), 10);
> +    ///
> +    /// // ...but this may make the vector reallocate
> +    /// vec.push(11);
> +    /// assert_eq!(vec.len(), 11);
> +    /// assert!(vec.capacity() >= 11);
> +    ///
> +    /// let mut result = Vec::try_with_capacity(usize::MAX);
> +    /// assert!(result.is_err());
> +    /// ```
> +    #[inline]
> +    #[stable(feature = "kernel", since = "1.0.0")]
> +    pub fn try_with_capacity(capacity: usize) -> Result<Self, TryReserveError> {
> +        Self::try_with_capacity_in(capacity, Global)
> +    }
> +
>      /// Creates a `Vec<T>` directly from the raw components of another vector.
>      ///
>      /// # Safety
> @@ -617,6 +659,53 @@ impl<T, A: Allocator> Vec<T, A> {
>          Vec { buf: RawVec::with_capacity_in(capacity, alloc), len: 0 }
>      }
>
> +    /// Tries to construct a new, empty `Vec<T, A>` with the specified capacity
> +    /// with the provided allocator.
> +    ///
> +    /// The vector will be able to hold exactly `capacity` elements without
> +    /// reallocating. If `capacity` is 0, the vector will not allocate.
> +    ///
> +    /// It is important to note that although the returned vector has the
> +    /// *capacity* specified, the vector will have a zero *length*. For an
> +    /// explanation of the difference between length and capacity, see
> +    /// *[Capacity and reallocation]*.
> +    ///
> +    /// [Capacity and reallocation]: #capacity-and-reallocation
> +    ///
> +    /// # Examples
> +    ///
> +    /// ```
> +    /// #![feature(allocator_api)]
> +    ///
> +    /// use std::alloc::System;
> +    ///
> +    /// let mut vec = Vec::try_with_capacity_in(10, System).unwrap();
> +    ///
> +    /// // The vector contains no items, even though it has capacity for more
> +    /// assert_eq!(vec.len(), 0);
> +    /// assert_eq!(vec.capacity(), 10);
> +    ///
> +    /// // These are all done without reallocating...
> +    /// for i in 0..10 {
> +    ///     vec.push(i);
> +    /// }
> +    /// assert_eq!(vec.len(), 10);
> +    /// assert_eq!(vec.capacity(), 10);
> +    ///
> +    /// // ...but this may make the vector reallocate
> +    /// vec.push(11);
> +    /// assert_eq!(vec.len(), 11);
> +    /// assert!(vec.capacity() >= 11);
> +    ///
> +    /// let mut result = Vec::try_with_capacity_in(usize::MAX, System);
> +    /// assert!(result.is_err());
> +    /// ```
> +    #[inline]
> +    #[stable(feature = "kernel", since = "1.0.0")]
> +    pub fn try_with_capacity_in(capacity: usize, alloc: A) -> Result<Self, TryReserveError> {
> +        Ok(Vec { buf: RawVec::try_with_capacity_in(capacity, alloc)?, len: 0 })
> +    }
> +
>      /// Creates a `Vec<T, A>` directly from the raw components of another vector.
>      ///
>      /// # Safety
> -- 
> 2.38.1

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

* Re: [PATCH v2 06/28] rust: macros: add `#[vtable]` proc macro
  2022-12-06 12:49   ` Finn Behrens
@ 2022-12-06 15:44     ` Miguel Ojeda
  0 siblings, 0 replies; 46+ messages in thread
From: Miguel Ojeda @ 2022-12-06 15:44 UTC (permalink / raw)
  To: Finn Behrens
  Cc: ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Sergio González Collado

On Tue, Dec 6, 2022 at 1:50 PM Finn Behrens <fin@nyantec.com> wrote:
>
> Reviewed-by: Finn Behrens <fin@nyantec.com>

Thanks a lot for these, Finn -- I already queued the patches on the
weekend, but if for some reason the series needs to be dropped and
reapplied, I will pick your new tags.

Cheers,
Miguel

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

end of thread, other threads:[~2022-12-06 15:45 UTC | newest]

Thread overview: 46+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-12-02 16:14 [PATCH v2 00/28] Rust core additions ojeda
2022-12-02 16:14 ` [PATCH v2 01/28] rust: prelude: split re-exports into groups ojeda
2022-12-02 16:14 ` [PATCH v2 02/28] rust: print: add more `pr_*!` levels ojeda
2022-12-02 16:14 ` [PATCH v2 03/28] rust: print: add `pr_cont!` macro ojeda
2022-12-02 16:14 ` [PATCH v2 04/28] rust: samples: add `rust_print` example ojeda
2022-12-02 16:14 ` [PATCH v2 05/28] rust: macros: add `concat_idents!` proc macro ojeda
2022-12-04  0:20   ` Gary Guo
2022-12-02 16:14 ` [PATCH v2 06/28] rust: macros: add `#[vtable]` " ojeda
2022-12-06 12:49   ` Finn Behrens
2022-12-06 15:44     ` Miguel Ojeda
2022-12-02 16:14 ` [PATCH v2 07/28] rust: macros: take string literals in `module!` ojeda
2022-12-02 16:14 ` [PATCH v2 08/28] rust: error: declare errors using macro ojeda
2022-12-02 16:14 ` [PATCH v2 09/28] rust: error: add codes from `errno-base.h` ojeda
2022-12-06 12:52   ` Finn Behrens
2022-12-02 16:14 ` [PATCH v2 10/28] rust: error: add `From` implementations for `Error` ojeda
2022-12-02 16:14 ` [PATCH v2 11/28] rust: prelude: add `error::code::*` constant items ojeda
2022-12-02 16:14 ` [PATCH v2 12/28] rust: alloc: add `RawVec::try_with_capacity_in()` constructor ojeda
2022-12-02 16:14 ` [PATCH v2 13/28] rust: alloc: add `Vec::try_with_capacity{,_in}()` constructors ojeda
2022-12-06 12:55   ` Finn Behrens
2022-12-02 16:14 ` [PATCH v2 14/28] rust: str: add `BStr` type ojeda
2022-12-02 16:14 ` [PATCH v2 15/28] rust: str: add `b_str!` macro ojeda
2022-12-02 16:14 ` [PATCH v2 16/28] rust: str: add `CStr` type ojeda
2022-12-02 16:14 ` [PATCH v2 17/28] rust: str: implement several traits for `CStr` ojeda
2022-12-02 16:14 ` [PATCH v2 18/28] rust: str: add `CStr` unit tests ojeda
2022-12-02 16:14 ` [PATCH v2 19/28] rust: str: add `c_str!` macro ojeda
2022-12-02 16:14 ` [PATCH v2 20/28] rust: str: add `Formatter` type ojeda
2022-12-04 15:41   ` Dr. David Alan Gilbert
2022-12-04 17:26     ` Wedson Almeida Filho
2022-12-04 18:05       ` Dr. David Alan Gilbert
2022-12-02 16:14 ` [PATCH v2 21/28] rust: str: add `CString` type ojeda
2022-12-02 16:14 ` [PATCH v2 22/28] rust: str: add `fmt!` macro ojeda
2022-12-02 16:14 ` [PATCH v2 23/28] rust: std_vendor: add `dbg!` macro based on `std`'s one ojeda
2022-12-02 16:14 ` [PATCH v2 24/28] rust: static_assert: add `static_assert!` macro ojeda
2022-12-02 16:14 ` [PATCH v2 25/28] rust: add `build_error` crate ojeda
2022-12-02 18:31   ` Wei Liu
2022-12-02 16:14 ` [PATCH v2 26/28] rust: build_assert: add `build_{error,assert}!` macros ojeda
2022-12-02 18:32   ` Wei Liu
2022-12-02 16:14 ` [PATCH v2 27/28] rust: types: add `Either` type ojeda
2022-12-02 23:41   ` Josh Triplett
2022-12-04  0:58     ` Miguel Ojeda
2022-12-04 10:31     ` Gary Guo
2022-12-04 17:36       ` Wedson Almeida Filho
2022-12-05 13:53         ` Miguel Ojeda
2022-12-05 23:00         ` Josh Triplett
2022-12-02 16:14 ` [PATCH v2 28/28] rust: types: add `Opaque` type ojeda
2022-12-04  1:05 ` [PATCH v2 00/28] Rust core additions Miguel Ojeda

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).