lkml.org 
[lkml]   [2022]   [Nov]   [10]   [last100]   RSS Feed
Views: [wrap][no wrap]   [headers]  [forward] 
 
Messages in this thread
    Patch in this message
    /
    From
    Subject[PATCH v1 23/28] rust: std_vendor: add `dbg!` macro based on `std`'s one
    Date
    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
    \
     
     \ /
      Last update: 2022-11-10 17:45    [W:2.375 / U:0.024 seconds]
    ©2003-2020 Jasper Spaans|hosted at Digital Ocean and TransIP|Read the blog|Advertise on this site