All of lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH v1 00/28] Rust core additions
@ 2022-11-10 16:41 Miguel Ojeda
  2022-11-10 16:41 ` [PATCH v1 01/28] rust: prelude: split re-exports into groups Miguel Ojeda
                   ` (27 more replies)
  0 siblings, 28 replies; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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

This patch series is the first batch of changes to upstream the rest
of the Rust support.

In this instance, all the facilities introduced are part of the "Rust
core". They do not interact with the C side in new major ways (no new
C types used; only `strlen`, `memchr`, additional error codes and some
more `printk` format strings).

After this series, `str.rs` and `print.rs` are in sync with downstream
and all remaining proc macros have been added. `error.rs` is fairly
complete too, though a few more `pub(crate)` features will come later
(to avoid leaving dead code in-between series).

Note that a few temporary `#[allow(dead_code)]` attributes are used in
order to have a bit more freedom organizing the patches while keeping
all of them buildable without warnings/errors, but at the end of the
series there is none remaining (of the temporary ones).

Virtually all the code has been in linux-next for months and was part
of the Rust patch series before the trimming down (i.e. up to v8).

Each patch has been built-tested on a Rust-enabled `defconfig` with
`CLIPPY=1` on the `all`, `rustfmtcheck`, `rustdoc` and `rusttest`
targets.

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               |  24 ++
 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         | 160 +++++++++
 rust/kernel/str.rs                | 532 +++++++++++++++++++++++++++++-
 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, 1666 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	[flat|nested] 68+ messages in thread

* [PATCH v1 01/28] rust: prelude: split re-exports into groups
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-10 18:05   ` Boqun Feng
  2022-11-14 14:40   ` Wei Liu
  2022-11-10 16:41 ` [PATCH v1 02/28] rust: print: add more `pr_*!` levels Miguel Ojeda
                   ` (26 subsequent siblings)
  27 siblings, 2 replies; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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

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

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] 68+ messages in thread

* [PATCH v1 02/28] rust: print: add more `pr_*!` levels
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
  2022-11-10 16:41 ` [PATCH v1 01/28] rust: prelude: split re-exports into groups Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-10 18:12   ` Boqun Feng
  2022-11-14 14:40   ` Wei Liu
  2022-11-10 16:41 ` [PATCH v1 03/28] rust: print: add `pr_cont!` macro Miguel Ojeda
                   ` (25 subsequent siblings)
  27 siblings, 2 replies; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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

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>
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] 68+ messages in thread

* [PATCH v1 03/28] rust: print: add `pr_cont!` macro
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
  2022-11-10 16:41 ` [PATCH v1 01/28] rust: prelude: split re-exports into groups Miguel Ojeda
  2022-11-10 16:41 ` [PATCH v1 02/28] rust: print: add more `pr_*!` levels Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-14 14:40   ` Wei Liu
  2022-11-14 15:04   ` Sergio González Collado
  2022-11-10 16:41 ` [PATCH v1 04/28] rust: samples: add `rust_print` example Miguel Ojeda
                   ` (24 subsequent siblings)
  27 siblings, 2 replies; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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

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>
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] 68+ messages in thread

* [PATCH v1 04/28] rust: samples: add `rust_print` example
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (2 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 03/28] rust: print: add `pr_cont!` macro Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-11  9:40   ` Finn Behrens
                     ` (2 more replies)
  2022-11-10 16:41 ` [PATCH v1 05/28] rust: macros: add `concat_idents!` proc macro Miguel Ojeda
                   ` (23 subsequent siblings)
  27 siblings, 3 replies; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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

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

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] 68+ messages in thread

* [PATCH v1 05/28] rust: macros: add `concat_idents!` proc macro
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (3 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 04/28] rust: samples: add `rust_print` example Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-11  9:25   ` Finn Behrens
  2022-11-14 14:26   ` Gary Guo
  2022-11-10 16:41 ` [PATCH v1 06/28] rust: macros: add `#[vtable]` " Miguel Ojeda
                   ` (22 subsequent siblings)
  27 siblings, 2 replies; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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: 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>
[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..3b5a9dd70e8a
--- /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(&(a.to_string() + &b.to_string()), 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] 68+ messages in thread

* [PATCH v1 06/28] rust: macros: add `#[vtable]` proc macro
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (4 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 05/28] rust: macros: add `concat_idents!` proc macro Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-14 15:06   ` Sergio González Collado
  2022-11-10 16:41 ` [PATCH v1 07/28] rust: macros: take string literals in `module!` Miguel Ojeda
                   ` (21 subsequent siblings)
  27 siblings, 1 reply; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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>

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>
[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] 68+ messages in thread

* [PATCH v1 07/28] rust: macros: take string literals in `module!`
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (5 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 06/28] rust: macros: add `#[vtable]` " Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-14 14:47   ` Wei Liu
  2022-11-10 16:41 ` [PATCH v1 08/28] rust: error: declare errors using macro Miguel Ojeda
                   ` (20 subsequent siblings)
  27 siblings, 1 reply; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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] 68+ messages in thread

* [PATCH v1 08/28] rust: error: declare errors using macro
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (6 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 07/28] rust: macros: take string literals in `module!` Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-14 14:28   ` Gary Guo
  2022-11-10 16:41 ` [PATCH v1 09/28] rust: error: add codes from `errno-base.h` Miguel Ojeda
                   ` (19 subsequent siblings)
  27 siblings, 1 reply; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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>
[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] 68+ messages in thread

* [PATCH v1 09/28] rust: error: add codes from `errno-base.h`
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (7 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 08/28] rust: error: declare errors using macro Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-14 14:29   ` Gary Guo
  2022-11-10 16:41 ` [PATCH v1 10/28] rust: error: add `From` implementations for `Error` Miguel Ojeda
                   ` (18 subsequent siblings)
  27 siblings, 1 reply; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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>
[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] 68+ messages in thread

* [PATCH v1 10/28] rust: error: add `From` implementations for `Error`
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (8 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 09/28] rust: error: add codes from `errno-base.h` Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-11  9:50   ` Finn Behrens
  2022-11-10 16:41 ` [PATCH v1 11/28] rust: prelude: add `error::code::*` constant items Miguel Ojeda
                   ` (17 subsequent siblings)
  27 siblings, 1 reply; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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

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>
[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] 68+ messages in thread

* [PATCH v1 11/28] rust: prelude: add `error::code::*` constant items
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (9 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 10/28] rust: error: add `From` implementations for `Error` Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-14 14:32   ` Gary Guo
  2022-11-10 16:41 ` [PATCH v1 12/28] rust: alloc: add `RawVec::try_with_capacity_in()` constructor Miguel Ojeda
                   ` (16 subsequent siblings)
  27 siblings, 1 reply; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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>
[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] 68+ messages in thread

* [PATCH v1 12/28] rust: alloc: add `RawVec::try_with_capacity_in()` constructor
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (10 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 11/28] rust: prelude: add `error::code::*` constant items Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-14 14:34   ` Gary Guo
  2022-11-10 16:41 ` [PATCH v1 13/28] rust: alloc: add `Vec::try_with_capacity{,_in}()` constructors Miguel Ojeda
                   ` (15 subsequent siblings)
  27 siblings, 1 reply; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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

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.

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] 68+ messages in thread

* [PATCH v1 13/28] rust: alloc: add `Vec::try_with_capacity{,_in}()` constructors
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (11 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 12/28] rust: alloc: add `RawVec::try_with_capacity_in()` constructor Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-14 14:35   ` Gary Guo
  2022-11-10 16:41 ` [PATCH v1 14/28] rust: str: add `BStr` type Miguel Ojeda
                   ` (14 subsequent siblings)
  27 siblings, 1 reply; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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

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.

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] 68+ messages in thread

* [PATCH v1 14/28] rust: str: add `BStr` type
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (12 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 13/28] rust: alloc: add `Vec::try_with_capacity{,_in}()` constructors Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-10 16:41 ` [PATCH v1 15/28] rust: str: add `b_str!` macro Miguel Ojeda
                   ` (13 subsequent siblings)
  27 siblings, 0 replies; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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] 68+ messages in thread

* [PATCH v1 15/28] rust: str: add `b_str!` macro
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (13 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 14/28] rust: str: add `BStr` type Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-10 16:41 ` [PATCH v1 16/28] rust: str: add `CStr` type Miguel Ojeda
                   ` (12 subsequent siblings)
  27 siblings, 0 replies; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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] 68+ messages in thread

* [PATCH v1 16/28] rust: str: add `CStr` type
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (14 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 15/28] rust: str: add `b_str!` macro Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-10 16:41 ` [PATCH v1 17/28] rust: str: implement several traits for `CStr` Miguel Ojeda
                   ` (11 subsequent siblings)
  27 siblings, 0 replies; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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] 68+ messages in thread

* [PATCH v1 17/28] rust: str: implement several traits for `CStr`
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (15 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 16/28] rust: str: add `CStr` type Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-10 16:41 ` [PATCH v1 18/28] rust: str: add `CStr` unit tests Miguel Ojeda
                   ` (10 subsequent siblings)
  27 siblings, 0 replies; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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] 68+ messages in thread

* [PATCH v1 18/28] rust: str: add `CStr` unit tests
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (16 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 17/28] rust: str: implement several traits for `CStr` Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-10 16:41 ` [PATCH v1 19/28] rust: str: add `c_str!` macro Miguel Ojeda
                   ` (9 subsequent siblings)
  27 siblings, 0 replies; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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] 68+ messages in thread

* [PATCH v1 19/28] rust: str: add `c_str!` macro
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (17 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 18/28] rust: str: add `CStr` unit tests Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-14 14:39   ` Gary Guo
  2022-11-10 16:41 ` [PATCH v1 20/28] rust: str: add `Formatter` type Miguel Ojeda
                   ` (8 subsequent siblings)
  27 siblings, 1 reply; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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 | 32 ++++++++++++++++++++++++++++++++
 1 file changed, 32 insertions(+)

diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
index 3ed685cb5a3c..3fb73b888dce 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -128,6 +128,18 @@ 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.
     ///
@@ -321,6 +333,26 @@ 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 = $crate::str::CStr::from_bytes_with_nul_unwrap(S.as_bytes());
+        C
+    }};
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
-- 
2.38.1


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

* [PATCH v1 20/28] rust: str: add `Formatter` type
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (18 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 19/28] rust: str: add `c_str!` macro Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-14 14:42   ` Gary Guo
  2022-11-10 16:41 ` [PATCH v1 21/28] rust: str: add `CString` type Miguel Ojeda
                   ` (7 subsequent siblings)
  27 siblings, 1 reply; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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>
[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 3fb73b888dce..db6473db31c6 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -415,6 +415,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.
@@ -448,3 +465,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] 68+ messages in thread

* [PATCH v1 21/28] rust: str: add `CString` type
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (19 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 20/28] rust: str: add `Formatter` type Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-14 14:53   ` Gary Guo
  2022-11-10 16:41 ` [PATCH v1 22/28] rust: str: add `fmt!` macro Miguel Ojeda
                   ` (6 subsequent siblings)
  27 siblings, 1 reply; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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 db6473db31c6..877148b77e71 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};
 
@@ -393,13 +394,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
@@ -438,6 +448,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 {
@@ -478,7 +493,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) })
@@ -505,3 +519,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] 68+ messages in thread

* [PATCH v1 22/28] rust: str: add `fmt!` macro
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (20 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 21/28] rust: str: add `CString` type Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-14 14:58   ` Gary Guo
  2022-11-10 16:41 ` [PATCH v1 23/28] rust: std_vendor: add `dbg!` macro based on `std`'s one Miguel Ojeda
                   ` (5 subsequent siblings)
  27 siblings, 1 reply; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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>
[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 877148b77e71..ffac633423db 100644
--- a/rust/kernel/str.rs
+++ b/rust/kernel/str.rs
@@ -592,3 +592,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] 68+ messages in thread

* [PATCH v1 23/28] rust: std_vendor: add `dbg!` macro based on `std`'s one
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (21 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 22/28] rust: str: add `fmt!` macro Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-10 18:01   ` Boqun Feng
  2022-11-10 16:41 ` [PATCH v1 24/28] rust: static_assert: add `static_assert!` macro Miguel Ojeda
                   ` (4 subsequent siblings)
  27 siblings, 1 reply; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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, using `pr_info!`
instead of `eprintln!`, inside a new module called `std_vendor`.

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 | 160 ++++++++++++++++++++++++++++++++++++++
 3 files changed, 163 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..da57b4e521f4
--- /dev/null
+++ b/rust/kernel/std_vendor.rs
@@ -0,0 +1,160 @@
+// 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 debugging tool and therefore you
+/// should avoid having uses of it in version control for long periods
+/// (other than in tests and similar).
+///
+/// # 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] 68+ messages in thread

* [PATCH v1 24/28] rust: static_assert: add `static_assert!` macro
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (22 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 23/28] rust: std_vendor: add `dbg!` macro based on `std`'s one Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-10 16:41 ` [PATCH v1 25/28] rust: add `build_error` crate Miguel Ojeda
                   ` (3 subsequent siblings)
  27 siblings, 0 replies; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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

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] 68+ messages in thread

* [PATCH v1 25/28] rust: add `build_error` crate
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (23 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 24/28] rust: static_assert: add `static_assert!` macro Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-14 14:30   ` Wei Liu
  2022-11-10 16:41 ` [PATCH v1 26/28] rust: build_assert: add `build_{error,assert}!` macros Miguel Ojeda
                   ` (2 subsequent siblings)
  27 siblings, 1 reply; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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               | 24 ++++++++++++++++++++++++
 rust/exports.c                    |  5 +++++
 scripts/generate_rust_analyzer.py |  8 +++++++-
 5 files changed, 69 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..0ff6b33059aa
--- /dev/null
+++ b/rust/build_error.rs
@@ -0,0 +1,24 @@
+// SPDX-License-Identifier: GPL-2.0
+
+//! 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.
+//!
+//! 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
+//! functions could still be called in the runtime).
+
+#![no_std]
+
+/// Panics if executed in const context, or triggers a build error if not.
+#[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] 68+ messages in thread

* [PATCH v1 26/28] rust: build_assert: add `build_{error,assert}!` macros
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (24 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 25/28] rust: add `build_error` crate Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-10 16:41 ` [PATCH v1 27/28] rust: types: add `Either` type Miguel Ojeda
  2022-11-10 16:41 ` [PATCH v1 28/28] rust: types: add `Opaque` type Miguel Ojeda
  27 siblings, 0 replies; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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] 68+ messages in thread

* [PATCH v1 27/28] rust: types: add `Either` type
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (25 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 26/28] rust: build_assert: add `build_{error,assert}!` macros Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-14 14:32   ` Wei Liu
  2022-11-10 16:41 ` [PATCH v1 28/28] rust: types: add `Opaque` type Miguel Ojeda
  27 siblings, 1 reply; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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>

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>
[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] 68+ messages in thread

* [PATCH v1 28/28] rust: types: add `Opaque` type
  2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
                   ` (26 preceding siblings ...)
  2022-11-10 16:41 ` [PATCH v1 27/28] rust: types: add `Either` type Miguel Ojeda
@ 2022-11-10 16:41 ` Miguel Ojeda
  2022-11-14 15:03   ` Gary Guo
  27 siblings, 1 reply; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 16:41 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] 68+ messages in thread

* Re: [PATCH v1 23/28] rust: std_vendor: add `dbg!` macro based on `std`'s one
  2022-11-10 16:41 ` [PATCH v1 23/28] rust: std_vendor: add `dbg!` macro based on `std`'s one Miguel Ojeda
@ 2022-11-10 18:01   ` Boqun Feng
  2022-11-10 19:14     ` Miguel Ojeda
  0 siblings, 1 reply; 68+ messages in thread
From: Boqun Feng @ 2022-11-10 18:01 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Niklas Mohrin

On Thu, Nov 10, 2022 at 05:41:35PM +0100, Miguel Ojeda wrote:
> 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, using `pr_info!`
> instead of `eprintln!`, inside a new module called `std_vendor`.
> 

I got confused when I saw `dbg!` uses `pr_info` instead of `pr_debug`,
but then I saw the discussion:

	https://github.com/Rust-for-Linux/linux/pull/483#discussion_r689881969

and I'm almost convinced ;-) Better add the gist of discussion into
comment/document/commit log? Users need to know when to use `dbg!` and
when to use `pr_debug!`, right?

Regards,
Boqun

> 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 | 160 ++++++++++++++++++++++++++++++++++++++
>  3 files changed, 163 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..da57b4e521f4
> --- /dev/null
> +++ b/rust/kernel/std_vendor.rs
> @@ -0,0 +1,160 @@
> +// 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 debugging tool and therefore you
> +/// should avoid having uses of it in version control for long periods
> +/// (other than in tests and similar).
> +///
> +/// # 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	[flat|nested] 68+ messages in thread

* Re: [PATCH v1 01/28] rust: prelude: split re-exports into groups
  2022-11-10 16:41 ` [PATCH v1 01/28] rust: prelude: split re-exports into groups Miguel Ojeda
@ 2022-11-10 18:05   ` Boqun Feng
  2022-11-14 14:40   ` Wei Liu
  1 sibling, 0 replies; 68+ messages in thread
From: Boqun Feng @ 2022-11-10 18:05 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches

On Thu, Nov 10, 2022 at 05:41:13PM +0100, Miguel Ojeda wrote:
> 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).
> 
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

Reviewed-by: Boqun Feng <boqun.feng@gmail.com>

Regards,
Boqun

> ---
>  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	[flat|nested] 68+ messages in thread

* Re: [PATCH v1 02/28] rust: print: add more `pr_*!` levels
  2022-11-10 16:41 ` [PATCH v1 02/28] rust: print: add more `pr_*!` levels Miguel Ojeda
@ 2022-11-10 18:12   ` Boqun Feng
  2022-11-14 14:40   ` Wei Liu
  1 sibling, 0 replies; 68+ messages in thread
From: Boqun Feng @ 2022-11-10 18:12 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Adam Bratschi-Kaye

On Thu, Nov 10, 2022 at 05:41:14PM +0100, Miguel Ojeda wrote:
> 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>
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

Reviewed-by: Boqun Feng <boqun.feng@gmail.com>

Regards,
Boqun

> ---
>  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	[flat|nested] 68+ messages in thread

* Re: [PATCH v1 23/28] rust: std_vendor: add `dbg!` macro based on `std`'s one
  2022-11-10 18:01   ` Boqun Feng
@ 2022-11-10 19:14     ` Miguel Ojeda
  2022-11-10 19:16       ` Boqun Feng
  0 siblings, 1 reply; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 19:14 UTC (permalink / raw)
  To: Boqun Feng
  Cc: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Niklas Mohrin

On Thu, Nov 10, 2022 at 7:02 PM Boqun Feng <boqun.feng@gmail.com> wrote:
>
> and I'm almost convinced ;-) Better add the gist of discussion into
> comment/document/commit log? Users need to know when to use `dbg!` and
> when to use `pr_debug!`, right?

The docs talk about it a bit:

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

That is the original wording from the standard library, but we can
definitely make the rules more concrete on our end with something
like:

    `dbg!` 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, use `pr_debug!` and
    similar facilities instead.

Cheers,
Miguel

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

* Re: [PATCH v1 23/28] rust: std_vendor: add `dbg!` macro based on `std`'s one
  2022-11-10 19:14     ` Miguel Ojeda
@ 2022-11-10 19:16       ` Boqun Feng
  2022-11-10 19:20         ` Miguel Ojeda
  0 siblings, 1 reply; 68+ messages in thread
From: Boqun Feng @ 2022-11-10 19:16 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Niklas Mohrin

On Thu, Nov 10, 2022 at 08:14:17PM +0100, Miguel Ojeda wrote:
> On Thu, Nov 10, 2022 at 7:02 PM Boqun Feng <boqun.feng@gmail.com> wrote:
> >
> > and I'm almost convinced ;-) Better add the gist of discussion into
> > comment/document/commit log? Users need to know when to use `dbg!` and
> > when to use `pr_debug!`, right?
> 
> The docs talk about it a bit:
> 
>     +/// 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).
> 
> That is the original wording from the standard library, but we can
> definitely make the rules more concrete on our end with something

Yeah, having some kernel contexts is better ;-)

> like:
> 
>     `dbg!` 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, use `pr_debug!` and
>     similar facilities instead.
> 

Look good to me, thank you!

Regards,
Boqun

> Cheers,
> Miguel

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

* Re: [PATCH v1 23/28] rust: std_vendor: add `dbg!` macro based on `std`'s one
  2022-11-10 19:16       ` Boqun Feng
@ 2022-11-10 19:20         ` Miguel Ojeda
  0 siblings, 0 replies; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-10 19:20 UTC (permalink / raw)
  To: Boqun Feng
  Cc: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Niklas Mohrin

On Thu, Nov 10, 2022 at 8:16 PM Boqun Feng <boqun.feng@gmail.com> wrote:
>
> Yeah, having some kernel contexts is better ;-)

Agreed, and being able to tweak the docs is, after all, one of the
advantages of having a custom version in-tree anyway :)

Thanks a lot!

Cheers,
Miguel

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

* Re: [PATCH v1 05/28] rust: macros: add `concat_idents!` proc macro
  2022-11-10 16:41 ` [PATCH v1 05/28] rust: macros: add `concat_idents!` proc macro Miguel Ojeda
@ 2022-11-11  9:25   ` Finn Behrens
  2022-11-14 14:26   ` Gary Guo
  1 sibling, 0 replies; 68+ messages in thread
From: Finn Behrens @ 2022-11-11  9:25 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches

On 10 Nov 2022, at 17:41, Miguel Ojeda 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>
> [Reworded, adapted for upstream and applied latest changes]
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Reviewed-by: Finn Behrens <me@kloenk.dev>

Regards,
Finn

> ---
>  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..3b5a9dd70e8a
> --- /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(&(a.to_string() + &b.to_string()), 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	[flat|nested] 68+ messages in thread

* Re: [PATCH v1 04/28] rust: samples: add `rust_print` example
  2022-11-10 16:41 ` [PATCH v1 04/28] rust: samples: add `rust_print` example Miguel Ojeda
@ 2022-11-11  9:40   ` Finn Behrens
  2022-11-11 17:31     ` Miguel Ojeda
  2022-11-14 14:41   ` Wei Liu
  2022-11-21 22:51   ` Sergio González Collado
  2 siblings, 1 reply; 68+ messages in thread
From: Finn Behrens @ 2022-11-11  9:40 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches

On 10 Nov 2022, at 17:41, Miguel Ojeda wrote:

> Add example to exercise the printing macros (`pr_*!`) introduced
> in the previous patches.
>
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Reviewed-by: Finn Behrens <me@kloenk.dev>

> ---
>  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");
Could be nice, to also have an int or similar as arg, but as internal the same macro is used as above, not really of interest.

Regards,
Finn
> +
> +        Ok(RustPrint)
> +    }
> +}
> +
> +impl Drop for RustPrint {
> +    fn drop(&mut self) {
> +        pr_info!("Rust printing macros sample (exit)\n");
> +    }
> +}
> -- 
> 2.38.1

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

* Re: [PATCH v1 10/28] rust: error: add `From` implementations for `Error`
  2022-11-10 16:41 ` [PATCH v1 10/28] rust: error: add `From` implementations for `Error` Miguel Ojeda
@ 2022-11-11  9:50   ` Finn Behrens
  0 siblings, 0 replies; 68+ messages in thread
From: Finn Behrens @ 2022-11-11  9:50 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Adam Bratschi-Kaye, Nándor István Krácser

On 10 Nov 2022, at 17:41, Miguel Ojeda wrote:

> 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>
> [Reworded, adapted for upstream and applied latest changes]
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
Reviewed-by: Finn Behrens <me@kloenk.dev>

Regards,
Finn
> ---
>  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	[flat|nested] 68+ messages in thread

* Re: [PATCH v1 04/28] rust: samples: add `rust_print` example
  2022-11-11  9:40   ` Finn Behrens
@ 2022-11-11 17:31     ` Miguel Ojeda
  0 siblings, 0 replies; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-11 17:31 UTC (permalink / raw)
  To: Finn Behrens
  Cc: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, rust-for-linux, linux-kernel,
	patches

On Fri, Nov 11, 2022 at 10:40 AM Finn Behrens <me@kloenk.dev> wrote:
>
> Could be nice, to also have an int or similar as arg, but as internal the same macro is used as above, not really of interest.

Yeah, there are some integers above, but we can add more examples
later on, e.g. with custom kernel types too.

Thanks for the reviews in several patches, by the way!

Cheers,
Miguel

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

* Re: [PATCH v1 05/28] rust: macros: add `concat_idents!` proc macro
  2022-11-10 16:41 ` [PATCH v1 05/28] rust: macros: add `concat_idents!` proc macro Miguel Ojeda
  2022-11-11  9:25   ` Finn Behrens
@ 2022-11-14 14:26   ` Gary Guo
  2022-11-14 14:39     ` Björn Roy Baron
  2022-11-14 17:22     ` Miguel Ojeda
  1 sibling, 2 replies; 68+ messages in thread
From: Gary Guo @ 2022-11-14 14:26 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches

On Thu, 10 Nov 2022 17:41:17 +0100
Miguel Ojeda <ojeda@kernel.org> wrote:

> +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(&(a.to_string() + &b.to_string()), b.span());

Probably clearer to write `Ident::new(&format!("{a}{b}"), b.span())`
here?

Best,
Gary

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

* Re: [PATCH v1 08/28] rust: error: declare errors using macro
  2022-11-10 16:41 ` [PATCH v1 08/28] rust: error: declare errors using macro Miguel Ojeda
@ 2022-11-14 14:28   ` Gary Guo
  0 siblings, 0 replies; 68+ messages in thread
From: Gary Guo @ 2022-11-14 14:28 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Finn Behrens

On Thu, 10 Nov 2022 17:41:20 +0100
Miguel Ojeda <ojeda@kernel.org> wrote:

> 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>
> [Reworded, adapted for upstream and applied latest changes]
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

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

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


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

* Re: [PATCH v1 09/28] rust: error: add codes from `errno-base.h`
  2022-11-10 16:41 ` [PATCH v1 09/28] rust: error: add codes from `errno-base.h` Miguel Ojeda
@ 2022-11-14 14:29   ` Gary Guo
  0 siblings, 0 replies; 68+ messages in thread
From: Gary Guo @ 2022-11-14 14:29 UTC (permalink / raw)
  To: Miguel Ojeda, Viktor Garske
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches

On Thu, 10 Nov 2022 17:41:21 +0100
Miguel Ojeda <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>
> [Reworded, adapted for upstream and applied latest changes]
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

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

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


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

* Re: [PATCH v1 25/28] rust: add `build_error` crate
  2022-11-10 16:41 ` [PATCH v1 25/28] rust: add `build_error` crate Miguel Ojeda
@ 2022-11-14 14:30   ` Wei Liu
  2022-11-14 18:22     ` Miguel Ojeda
  0 siblings, 1 reply; 68+ messages in thread
From: Wei Liu @ 2022-11-14 14:30 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Wei Liu

On Thu, Nov 10, 2022 at 05:41:37PM +0100, Miguel Ojeda wrote:
> From: Gary Guo <gary@garyguo.net>
[...]
> diff --git a/rust/build_error.rs b/rust/build_error.rs
> new file mode 100644
> index 000000000000..0ff6b33059aa
> --- /dev/null
> +++ b/rust/build_error.rs
> @@ -0,0 +1,24 @@
> +// SPDX-License-Identifier: GPL-2.0
> +
> +//! Build-time error.
> +//!
> +//! This crate provides a function `build_error`, which will panic in

a const function `build_error`

Without this I read it as a "normal non-const function".

> +//! 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.
> +//!

I can work out what the code does, but I also happen to know what Rust's
const means and its behaviour in non-const context. Other kernel
developers may not. Even so the description is a bit difficult for me to
parse.

Maybe a few sentences about const and its behaviours can help?

Thanks,
Wei.

> +//! 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
> +//! functions could still be called in the runtime).
> +
> +#![no_std]
> +
> +/// Panics if executed in const context, or triggers a build error if not.
> +#[inline(never)]
> +#[cold]
> +#[export_name = "rust_build_error"]
> +#[track_caller]
> +pub const fn build_error(msg: &'static str) -> ! {
> +    panic!("{}", msg);
> +}

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

* Re: [PATCH v1 11/28] rust: prelude: add `error::code::*` constant items
  2022-11-10 16:41 ` [PATCH v1 11/28] rust: prelude: add `error::code::*` constant items Miguel Ojeda
@ 2022-11-14 14:32   ` Gary Guo
  0 siblings, 0 replies; 68+ messages in thread
From: Gary Guo @ 2022-11-14 14:32 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches

On Thu, 10 Nov 2022 17:41:23 +0100
Miguel Ojeda <ojeda@kernel.org> wrote:

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

Personally, I would prefer to have all error codes as associated
constants of the `kernel::Error` type so the code below would use
`Err(Error::EINVAL)` (more "Rusty" way of writing things). But IIRC
that we settled on the current approach because it's more similar to
existing C code.

> 
> 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>
> [Reworded, adapted for upstream and applied latest changes]
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

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

> ---
>  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;


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

* Re: [PATCH v1 27/28] rust: types: add `Either` type
  2022-11-10 16:41 ` [PATCH v1 27/28] rust: types: add `Either` type Miguel Ojeda
@ 2022-11-14 14:32   ` Wei Liu
  0 siblings, 0 replies; 68+ messages in thread
From: Wei Liu @ 2022-11-14 14:32 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Wei Liu

On Thu, Nov 10, 2022 at 05:41:39PM +0100, Miguel Ojeda 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>,
>     }
> 
> 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>

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

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

* Re: [PATCH v1 12/28] rust: alloc: add `RawVec::try_with_capacity_in()` constructor
  2022-11-10 16:41 ` [PATCH v1 12/28] rust: alloc: add `RawVec::try_with_capacity_in()` constructor Miguel Ojeda
@ 2022-11-14 14:34   ` Gary Guo
  0 siblings, 0 replies; 68+ messages in thread
From: Gary Guo @ 2022-11-14 14:34 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches

On Thu, 10 Nov 2022 17:41:24 +0100
Miguel Ojeda <ojeda@kernel.org> wrote:

> 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.
> 
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

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

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


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

* Re: [PATCH v1 13/28] rust: alloc: add `Vec::try_with_capacity{,_in}()` constructors
  2022-11-10 16:41 ` [PATCH v1 13/28] rust: alloc: add `Vec::try_with_capacity{,_in}()` constructors Miguel Ojeda
@ 2022-11-14 14:35   ` Gary Guo
  0 siblings, 0 replies; 68+ messages in thread
From: Gary Guo @ 2022-11-14 14:35 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches

On Thu, 10 Nov 2022 17:41:25 +0100
Miguel Ojeda <ojeda@kernel.org> wrote:

> 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.
> 
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

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

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


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

* Re: [PATCH v1 05/28] rust: macros: add `concat_idents!` proc macro
  2022-11-14 14:26   ` Gary Guo
@ 2022-11-14 14:39     ` Björn Roy Baron
  2022-11-14 17:22     ` Miguel Ojeda
  1 sibling, 0 replies; 68+ messages in thread
From: Björn Roy Baron @ 2022-11-14 14:39 UTC (permalink / raw)
  To: Gary Guo
  Cc: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	rust-for-linux, linux-kernel, patches

On Monday, November 14th, 2022 at 15:26, Gary Guo <gary@garyguo.net> wrote:


> On Thu, 10 Nov 2022 17:41:17 +0100
> Miguel Ojeda ojeda@kernel.org wrote:
> 
> > +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(&(a.to_string() + &b.to_string()), b.span());
> 
> 
> Probably clearer to write `Ident::new(&format!("{a}{b}"), b.span())`
> here?
> 
> Best,
> Gary

I agree that is clearer. I hadn't considered that Ident implements Display when I wrote it.

Cheers,
Björn

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

* Re: [PATCH v1 19/28] rust: str: add `c_str!` macro
  2022-11-10 16:41 ` [PATCH v1 19/28] rust: str: add `c_str!` macro Miguel Ojeda
@ 2022-11-14 14:39   ` Gary Guo
  2022-11-14 18:28     ` Miguel Ojeda
  0 siblings, 1 reply; 68+ messages in thread
From: Gary Guo @ 2022-11-14 14:39 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches

On Thu, 10 Nov 2022 17:41:31 +0100
Miguel Ojeda <ojeda@kernel.org> wrote:

> 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 | 32 ++++++++++++++++++++++++++++++++
>  1 file changed, 32 insertions(+)
> 
> diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
> index 3ed685cb5a3c..3fb73b888dce 100644
> --- a/rust/kernel/str.rs
> +++ b/rust/kernel/str.rs
> @@ -128,6 +128,18 @@ 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.

I wrote this code when `const_panic` was not yet stable. Now we have
stable const panic this function could be removed.

> +    #[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.
>      ///
> @@ -321,6 +333,26 @@ 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 = $crate::str::CStr::from_bytes_with_nul_unwrap(S.as_bytes());
> +        C
> +    }};
> +}

+#[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::*;


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

* Re: [PATCH v1 01/28] rust: prelude: split re-exports into groups
  2022-11-10 16:41 ` [PATCH v1 01/28] rust: prelude: split re-exports into groups Miguel Ojeda
  2022-11-10 18:05   ` Boqun Feng
@ 2022-11-14 14:40   ` Wei Liu
  1 sibling, 0 replies; 68+ messages in thread
From: Wei Liu @ 2022-11-14 14:40 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Wei Liu

On Thu, Nov 10, 2022 at 05:41:13PM +0100, Miguel Ojeda wrote:
> 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).
> 
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

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

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

* Re: [PATCH v1 02/28] rust: print: add more `pr_*!` levels
  2022-11-10 16:41 ` [PATCH v1 02/28] rust: print: add more `pr_*!` levels Miguel Ojeda
  2022-11-10 18:12   ` Boqun Feng
@ 2022-11-14 14:40   ` Wei Liu
  2022-11-14 15:01     ` Sergio González Collado
  1 sibling, 1 reply; 68+ messages in thread
From: Wei Liu @ 2022-11-14 14:40 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Adam Bratschi-Kaye, Wei Liu

On Thu, Nov 10, 2022 at 05:41:14PM +0100, Miguel Ojeda wrote:
> 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>
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

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

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

* Re: [PATCH v1 03/28] rust: print: add `pr_cont!` macro
  2022-11-10 16:41 ` [PATCH v1 03/28] rust: print: add `pr_cont!` macro Miguel Ojeda
@ 2022-11-14 14:40   ` Wei Liu
  2022-11-14 15:04   ` Sergio González Collado
  1 sibling, 0 replies; 68+ messages in thread
From: Wei Liu @ 2022-11-14 14:40 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Adam Bratschi-Kaye, Wei Liu

On Thu, Nov 10, 2022 at 05:41:15PM +0100, Miguel Ojeda wrote:
> 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>
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

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

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

* Re: [PATCH v1 04/28] rust: samples: add `rust_print` example
  2022-11-10 16:41 ` [PATCH v1 04/28] rust: samples: add `rust_print` example Miguel Ojeda
  2022-11-11  9:40   ` Finn Behrens
@ 2022-11-14 14:41   ` Wei Liu
  2022-11-21 22:51   ` Sergio González Collado
  2 siblings, 0 replies; 68+ messages in thread
From: Wei Liu @ 2022-11-14 14:41 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Wei Liu

On Thu, Nov 10, 2022 at 05:41:16PM +0100, Miguel Ojeda wrote:
> Add example to exercise the printing macros (`pr_*!`) introduced
> in the previous patches.
> 
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

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

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

* Re: [PATCH v1 20/28] rust: str: add `Formatter` type
  2022-11-10 16:41 ` [PATCH v1 20/28] rust: str: add `Formatter` type Miguel Ojeda
@ 2022-11-14 14:42   ` Gary Guo
  0 siblings, 0 replies; 68+ messages in thread
From: Gary Guo @ 2022-11-14 14:42 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Adam Bratschi-Kaye

On Thu, 10 Nov 2022 17:41:32 +0100
Miguel Ojeda <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>
> [Reworded, adapted for upstream and applied latest changes]
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

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

> ---
>  rust/kernel/str.rs | 57 ++++++++++++++++++++++++++++++++++++++++++++++
>  1 file changed, 57 insertions(+)
> 
> diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
> index 3fb73b888dce..db6473db31c6 100644
> --- a/rust/kernel/str.rs
> +++ b/rust/kernel/str.rs
> @@ -415,6 +415,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.
> @@ -448,3 +465,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(())
> +        }
> +    }
> +}


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

* Re: [PATCH v1 07/28] rust: macros: take string literals in `module!`
  2022-11-10 16:41 ` [PATCH v1 07/28] rust: macros: take string literals in `module!` Miguel Ojeda
@ 2022-11-14 14:47   ` Wei Liu
  2022-11-14 16:46     ` Miguel Ojeda
  0 siblings, 1 reply; 68+ messages in thread
From: Wei Liu @ 2022-11-14 14:47 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Wei Liu

On Thu, Nov 10, 2022 at 05:41:19PM +0100, Miguel Ojeda wrote:
> 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.

What's the rationale behind allowing UTF-8? Why not stick with ASCII
only?

Thanks,
Wei.

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

* Re: [PATCH v1 21/28] rust: str: add `CString` type
  2022-11-10 16:41 ` [PATCH v1 21/28] rust: str: add `CString` type Miguel Ojeda
@ 2022-11-14 14:53   ` Gary Guo
  0 siblings, 0 replies; 68+ messages in thread
From: Gary Guo @ 2022-11-14 14:53 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches

On Thu, 10 Nov 2022 17:41:33 +0100
Miguel Ojeda <ojeda@kernel.org> wrote:

> 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 db6473db31c6..877148b77e71 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};
>  
> @@ -393,13 +394,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
> @@ -438,6 +448,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 {
> @@ -478,7 +493,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) })
> @@ -505,3 +519,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")?;

I haven't checked the assembly, so this is possibly optimized out
already, but I feel that this line could be removed and we just use
`f.bytes_written() + 1` instead on the following line.

> +        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()) };

`f.bytes_written() <= size` does not always hold. It holds here because
otherwise the `?` operator above would return an error early
(guaranteed by `impl Write for Formatter`). I feel that this fact is
not clearly stated in the safety comment but I don't have a good way to
rephrase this either.

> +
> +        // 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 _) };

How about just use `if buf[..(f.bytes_written() - 1)].contains(&0) {`
here? libcore specialises `<[u8]>::contains` to use a faster search
than `.iter().any(...)`.

> +        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()) }
> +    }
> +}


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

* Re: [PATCH v1 22/28] rust: str: add `fmt!` macro
  2022-11-10 16:41 ` [PATCH v1 22/28] rust: str: add `fmt!` macro Miguel Ojeda
@ 2022-11-14 14:58   ` Gary Guo
  0 siblings, 0 replies; 68+ messages in thread
From: Gary Guo @ 2022-11-14 14:58 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches

On Thu, 10 Nov 2022 17:41:34 +0100
Miguel Ojeda <ojeda@kernel.org> wrote:

> 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>
> [Reworded, adapted for upstream and applied latest changes]
> Signed-off-by: Miguel Ojeda <ojeda@kernel.org>

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

> ---
>  rust/kernel/str.rs | 6 ++++++
>  1 file changed, 6 insertions(+)
> 
> diff --git a/rust/kernel/str.rs b/rust/kernel/str.rs
> index 877148b77e71..ffac633423db 100644
> --- a/rust/kernel/str.rs
> +++ b/rust/kernel/str.rs
> @@ -592,3 +592,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)*) )
> +}


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

* Re: [PATCH v1 02/28] rust: print: add more `pr_*!` levels
  2022-11-14 14:40   ` Wei Liu
@ 2022-11-14 15:01     ` Sergio González Collado
  0 siblings, 0 replies; 68+ messages in thread
From: Sergio González Collado @ 2022-11-14 15:01 UTC (permalink / raw)
  To: Wei Liu
  Cc: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, rust-for-linux, linux-kernel,
	patches, Adam Bratschi-Kaye

On Mon, 14 Nov 2022 at 09:43, Wei Liu <wei.liu@kernel.org> wrote:
>
> On Thu, Nov 10, 2022 at 05:41:14PM +0100, Miguel Ojeda wrote:
> > 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>
> > Signed-off-by: Miguel Ojeda <ojeda@kernel.org>
>
> Reviewed-by: Wei Liu <wei.liu@kernel.org>

Reviewed-by: Sergio Gonzalez Collado <sergio.collado@gmail.com>

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

* Re: [PATCH v1 28/28] rust: types: add `Opaque` type
  2022-11-10 16:41 ` [PATCH v1 28/28] rust: types: add `Opaque` type Miguel Ojeda
@ 2022-11-14 15:03   ` Gary Guo
  0 siblings, 0 replies; 68+ messages in thread
From: Gary Guo @ 2022-11-14 15:03 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches

On Thu, 10 Nov 2022 17:41:40 +0100
Miguel Ojeda <ojeda@kernel.org> wrote:

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

Shouldn't this be `UnsafeCell<MaybeUninit<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`.


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

* Re: [PATCH v1 03/28] rust: print: add `pr_cont!` macro
  2022-11-10 16:41 ` [PATCH v1 03/28] rust: print: add `pr_cont!` macro Miguel Ojeda
  2022-11-14 14:40   ` Wei Liu
@ 2022-11-14 15:04   ` Sergio González Collado
  1 sibling, 0 replies; 68+ messages in thread
From: Sergio González Collado @ 2022-11-14 15:04 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches,
	Adam Bratschi-Kaye

On Thu, 10 Nov 2022 at 11:43, Miguel Ojeda <ojeda@kernel.org> wrote:
>
> 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>
> 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
>
Reviewed-by: Sergio González Collado <sergio.collado@gmail.com>

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

* Re: [PATCH v1 06/28] rust: macros: add `#[vtable]` proc macro
  2022-11-10 16:41 ` [PATCH v1 06/28] rust: macros: add `#[vtable]` " Miguel Ojeda
@ 2022-11-14 15:06   ` Sergio González Collado
  0 siblings, 0 replies; 68+ messages in thread
From: Sergio González Collado @ 2022-11-14 15:06 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches

On Thu, 10 Nov 2022 at 11:43, Miguel Ojeda <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>
> [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
>
Reviewed-by: Sergio González Collado <sergio.collado@gmail.com>

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

* Re: [PATCH v1 07/28] rust: macros: take string literals in `module!`
  2022-11-14 14:47   ` Wei Liu
@ 2022-11-14 16:46     ` Miguel Ojeda
  2022-11-14 17:25       ` Wei Liu
  0 siblings, 1 reply; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-14 16:46 UTC (permalink / raw)
  To: Wei Liu
  Cc: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, rust-for-linux, linux-kernel,
	patches

On Mon, Nov 14, 2022 at 3:47 PM Wei Liu <wei.liu@kernel.org> wrote:
>
> What's the rationale behind allowing UTF-8? Why not stick with ASCII
> only?

The reason is that there are already some cases on the C side.

For authors, there are about 158 non-ASCII in the kernel tree (if I
grepped correctly), e.g.:

    MODULE_AUTHOR("漆鹏振 (Qi Pengzhen) <aric.pzqi@ingenic.com>");
    MODULE_AUTHOR("Martin Povišer <povik+lin@cutebit.org>");
    MODULE_AUTHOR("Jérôme Pouiller <jerome.pouiller@silabs.com>");
    MODULE_AUTHOR("Uwe Kleine-König <u.kleine-koenig@pengutronix.de>");

There are also a few descriptions too, e.g.:

    MODULE_DESCRIPTION("NAND flash driver for OLPC CAFÉ chip");
    MODULE_DESCRIPTION("NHPoly1305 ε-almost-∆-universal hash function");

Cheers,
Miguel

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

* Re: [PATCH v1 05/28] rust: macros: add `concat_idents!` proc macro
  2022-11-14 14:26   ` Gary Guo
  2022-11-14 14:39     ` Björn Roy Baron
@ 2022-11-14 17:22     ` Miguel Ojeda
  1 sibling, 0 replies; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-14 17:22 UTC (permalink / raw)
  To: Gary Guo
  Cc: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches

On Mon, Nov 14, 2022 at 3:26 PM Gary Guo <gary@garyguo.net> wrote:
>
> Probably clearer to write `Ident::new(&format!("{a}{b}"), b.span())`
> here?

Same as Björn, it also looks better to me. I will update it.

Cheers,
Miguel

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

* Re: [PATCH v1 07/28] rust: macros: take string literals in `module!`
  2022-11-14 16:46     ` Miguel Ojeda
@ 2022-11-14 17:25       ` Wei Liu
  0 siblings, 0 replies; 68+ messages in thread
From: Wei Liu @ 2022-11-14 17:25 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wei Liu, Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor,
	Boqun Feng, Gary Guo, Björn Roy Baron, rust-for-linux,
	linux-kernel, patches

On Mon, Nov 14, 2022 at 05:46:05PM +0100, Miguel Ojeda wrote:
> On Mon, Nov 14, 2022 at 3:47 PM Wei Liu <wei.liu@kernel.org> wrote:
> >
> > What's the rationale behind allowing UTF-8? Why not stick with ASCII
> > only?
> 
> The reason is that there are already some cases on the C side.
> 
> For authors, there are about 158 non-ASCII in the kernel tree (if I
> grepped correctly), e.g.:
> 
>     MODULE_AUTHOR("漆鹏振 (Qi Pengzhen) <aric.pzqi@ingenic.com>");
>     MODULE_AUTHOR("Martin Povišer <povik+lin@cutebit.org>");
>     MODULE_AUTHOR("Jérôme Pouiller <jerome.pouiller@silabs.com>");
>     MODULE_AUTHOR("Uwe Kleine-König <u.kleine-koenig@pengutronix.de>");
> 
> There are also a few descriptions too, e.g.:
> 
>     MODULE_DESCRIPTION("NAND flash driver for OLPC CAFÉ chip");
>     MODULE_DESCRIPTION("NHPoly1305 ε-almost-∆-universal hash function");

Okay. That's fair enough.

Thanks,
Wei.

> 
> Cheers,
> Miguel

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

* Re: [PATCH v1 25/28] rust: add `build_error` crate
  2022-11-14 14:30   ` Wei Liu
@ 2022-11-14 18:22     ` Miguel Ojeda
  2022-11-14 21:06       ` Wei Liu
  0 siblings, 1 reply; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-14 18:22 UTC (permalink / raw)
  To: Wei Liu
  Cc: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Gary Guo, Björn Roy Baron, rust-for-linux, linux-kernel,
	patches

On Mon, Nov 14, 2022 at 3:30 PM Wei Liu <wei.liu@kernel.org> wrote:
>
> a const function `build_error`
>
> Without this I read it as a "normal non-const function".

Sounds good to me, especially given the sentence that goes after that.

(I think "function" does not imply one or the other in principle. To
me, `const` ones are normal too, in the sense that they can be used as
any other function.)

> I can work out what the code does, but I also happen to know what Rust's
> const means and its behaviour in non-const context. Other kernel
> developers may not. Even so the description is a bit difficult for me to
> parse.
>
> Maybe a few sentences about const and its behaviours can help?

Not sure if we should explain language details in the documentation of
particular functions. But I agree this case is a bit special.

What about linking the Rust reference/book/... (so that those terms
are clickable when rendered)?

Thanks a lot for the reviews, Wei!

Cheers,
Miguel

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

* Re: [PATCH v1 19/28] rust: str: add `c_str!` macro
  2022-11-14 14:39   ` Gary Guo
@ 2022-11-14 18:28     ` Miguel Ojeda
  0 siblings, 0 replies; 68+ messages in thread
From: Miguel Ojeda @ 2022-11-14 18:28 UTC (permalink / raw)
  To: Gary Guo
  Cc: Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor, Boqun Feng,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches

On Mon, Nov 14, 2022 at 3:39 PM Gary Guo <gary@garyguo.net> wrote:
>
> I wrote this code when `const_panic` was not yet stable. Now we have
> stable const panic this function could be removed.

Indeed, we also took advantage of it in `static_assert!` when it got
stabilized but not here. I will update it.

Cheers,
Miguel

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

* Re: [PATCH v1 25/28] rust: add `build_error` crate
  2022-11-14 18:22     ` Miguel Ojeda
@ 2022-11-14 21:06       ` Wei Liu
  0 siblings, 0 replies; 68+ messages in thread
From: Wei Liu @ 2022-11-14 21:06 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wei Liu, Miguel Ojeda, Wedson Almeida Filho, Alex Gaynor,
	Boqun Feng, Gary Guo, Björn Roy Baron, rust-for-linux,
	linux-kernel, patches

On Mon, Nov 14, 2022 at 07:22:02PM +0100, Miguel Ojeda wrote:
> On Mon, Nov 14, 2022 at 3:30 PM Wei Liu <wei.liu@kernel.org> wrote:
> >
> > a const function `build_error`
> >
> > Without this I read it as a "normal non-const function".
> 
> Sounds good to me, especially given the sentence that goes after that.
> 
> (I think "function" does not imply one or the other in principle. To
> me, `const` ones are normal too, in the sense that they can be used as
> any other function.)
> 
> > I can work out what the code does, but I also happen to know what Rust's
> > const means and its behaviour in non-const context. Other kernel
> > developers may not. Even so the description is a bit difficult for me to
> > parse.
> >
> > Maybe a few sentences about const and its behaviours can help?
> 
> Not sure if we should explain language details in the documentation of
> particular functions. But I agree this case is a bit special.
> 
> What about linking the Rust reference/book/... (so that those terms
> are clickable when rendered)?

I think this works too.

> 
> Thanks a lot for the reviews, Wei!
> 

You're welcome.

Thanks,
Wei.

> Cheers,
> Miguel

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

* Re: [PATCH v1 04/28] rust: samples: add `rust_print` example
  2022-11-10 16:41 ` [PATCH v1 04/28] rust: samples: add `rust_print` example Miguel Ojeda
  2022-11-11  9:40   ` Finn Behrens
  2022-11-14 14:41   ` Wei Liu
@ 2022-11-21 22:51   ` Sergio González Collado
  2 siblings, 0 replies; 68+ messages in thread
From: Sergio González Collado @ 2022-11-21 22:51 UTC (permalink / raw)
  To: Miguel Ojeda
  Cc: Wedson Almeida Filho, Alex Gaynor, Boqun Feng, Gary Guo,
	Björn Roy Baron, rust-for-linux, linux-kernel, patches

On Thu, 10 Nov 2022 at 17:43, Miguel Ojeda <ojeda@kernel.org> wrote:
>
> Add example to exercise the printing macros (`pr_*!`) introduced
> in the previous patches.
>
> 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
>

Tested-by: Sergio González Collado <sergio.collado@gmail.com>

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

end of thread, other threads:[~2022-11-21 22:52 UTC | newest]

Thread overview: 68+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2022-11-10 16:41 [PATCH v1 00/28] Rust core additions Miguel Ojeda
2022-11-10 16:41 ` [PATCH v1 01/28] rust: prelude: split re-exports into groups Miguel Ojeda
2022-11-10 18:05   ` Boqun Feng
2022-11-14 14:40   ` Wei Liu
2022-11-10 16:41 ` [PATCH v1 02/28] rust: print: add more `pr_*!` levels Miguel Ojeda
2022-11-10 18:12   ` Boqun Feng
2022-11-14 14:40   ` Wei Liu
2022-11-14 15:01     ` Sergio González Collado
2022-11-10 16:41 ` [PATCH v1 03/28] rust: print: add `pr_cont!` macro Miguel Ojeda
2022-11-14 14:40   ` Wei Liu
2022-11-14 15:04   ` Sergio González Collado
2022-11-10 16:41 ` [PATCH v1 04/28] rust: samples: add `rust_print` example Miguel Ojeda
2022-11-11  9:40   ` Finn Behrens
2022-11-11 17:31     ` Miguel Ojeda
2022-11-14 14:41   ` Wei Liu
2022-11-21 22:51   ` Sergio González Collado
2022-11-10 16:41 ` [PATCH v1 05/28] rust: macros: add `concat_idents!` proc macro Miguel Ojeda
2022-11-11  9:25   ` Finn Behrens
2022-11-14 14:26   ` Gary Guo
2022-11-14 14:39     ` Björn Roy Baron
2022-11-14 17:22     ` Miguel Ojeda
2022-11-10 16:41 ` [PATCH v1 06/28] rust: macros: add `#[vtable]` " Miguel Ojeda
2022-11-14 15:06   ` Sergio González Collado
2022-11-10 16:41 ` [PATCH v1 07/28] rust: macros: take string literals in `module!` Miguel Ojeda
2022-11-14 14:47   ` Wei Liu
2022-11-14 16:46     ` Miguel Ojeda
2022-11-14 17:25       ` Wei Liu
2022-11-10 16:41 ` [PATCH v1 08/28] rust: error: declare errors using macro Miguel Ojeda
2022-11-14 14:28   ` Gary Guo
2022-11-10 16:41 ` [PATCH v1 09/28] rust: error: add codes from `errno-base.h` Miguel Ojeda
2022-11-14 14:29   ` Gary Guo
2022-11-10 16:41 ` [PATCH v1 10/28] rust: error: add `From` implementations for `Error` Miguel Ojeda
2022-11-11  9:50   ` Finn Behrens
2022-11-10 16:41 ` [PATCH v1 11/28] rust: prelude: add `error::code::*` constant items Miguel Ojeda
2022-11-14 14:32   ` Gary Guo
2022-11-10 16:41 ` [PATCH v1 12/28] rust: alloc: add `RawVec::try_with_capacity_in()` constructor Miguel Ojeda
2022-11-14 14:34   ` Gary Guo
2022-11-10 16:41 ` [PATCH v1 13/28] rust: alloc: add `Vec::try_with_capacity{,_in}()` constructors Miguel Ojeda
2022-11-14 14:35   ` Gary Guo
2022-11-10 16:41 ` [PATCH v1 14/28] rust: str: add `BStr` type Miguel Ojeda
2022-11-10 16:41 ` [PATCH v1 15/28] rust: str: add `b_str!` macro Miguel Ojeda
2022-11-10 16:41 ` [PATCH v1 16/28] rust: str: add `CStr` type Miguel Ojeda
2022-11-10 16:41 ` [PATCH v1 17/28] rust: str: implement several traits for `CStr` Miguel Ojeda
2022-11-10 16:41 ` [PATCH v1 18/28] rust: str: add `CStr` unit tests Miguel Ojeda
2022-11-10 16:41 ` [PATCH v1 19/28] rust: str: add `c_str!` macro Miguel Ojeda
2022-11-14 14:39   ` Gary Guo
2022-11-14 18:28     ` Miguel Ojeda
2022-11-10 16:41 ` [PATCH v1 20/28] rust: str: add `Formatter` type Miguel Ojeda
2022-11-14 14:42   ` Gary Guo
2022-11-10 16:41 ` [PATCH v1 21/28] rust: str: add `CString` type Miguel Ojeda
2022-11-14 14:53   ` Gary Guo
2022-11-10 16:41 ` [PATCH v1 22/28] rust: str: add `fmt!` macro Miguel Ojeda
2022-11-14 14:58   ` Gary Guo
2022-11-10 16:41 ` [PATCH v1 23/28] rust: std_vendor: add `dbg!` macro based on `std`'s one Miguel Ojeda
2022-11-10 18:01   ` Boqun Feng
2022-11-10 19:14     ` Miguel Ojeda
2022-11-10 19:16       ` Boqun Feng
2022-11-10 19:20         ` Miguel Ojeda
2022-11-10 16:41 ` [PATCH v1 24/28] rust: static_assert: add `static_assert!` macro Miguel Ojeda
2022-11-10 16:41 ` [PATCH v1 25/28] rust: add `build_error` crate Miguel Ojeda
2022-11-14 14:30   ` Wei Liu
2022-11-14 18:22     ` Miguel Ojeda
2022-11-14 21:06       ` Wei Liu
2022-11-10 16:41 ` [PATCH v1 26/28] rust: build_assert: add `build_{error,assert}!` macros Miguel Ojeda
2022-11-10 16:41 ` [PATCH v1 27/28] rust: types: add `Either` type Miguel Ojeda
2022-11-14 14:32   ` Wei Liu
2022-11-10 16:41 ` [PATCH v1 28/28] rust: types: add `Opaque` type Miguel Ojeda
2022-11-14 15:03   ` Gary Guo

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.