Skip to main content

kernel/
std_vendor.rs

1// SPDX-License-Identifier: Apache-2.0 OR MIT
2
3//! Rust standard library vendored code.
4//!
5//! The contents of this file come from the Rust standard library, hosted in
6//! the <https://github.com/rust-lang/rust> repository, licensed under
7//! "Apache-2.0 OR MIT" and adapted for kernel use. For copyright details,
8//! see <https://github.com/rust-lang/rust/blob/master/COPYRIGHT>.
9
10/// [`std::dbg`], but using [`pr_info`] instead of [`eprintln`].
11///
12/// Prints and returns the value of a given expression for quick and dirty
13/// debugging.
14///
15/// An example:
16///
17/// ```rust
18/// let a = 2;
19/// # #[expect(clippy::disallowed_macros)]
20/// let b = dbg!(a * 2) + 1;
21/// //      ^-- prints: [src/main.rs:2] a * 2 = 4
22/// assert_eq!(b, 5);
23/// ```
24///
25/// The macro works by using the `Debug` implementation of the type of
26/// the given expression to print the value with [`printk`] along with the
27/// source location of the macro invocation as well as the source code
28/// of the expression.
29///
30/// Invoking the macro on an expression moves and takes ownership of it
31/// before returning the evaluated expression unchanged. If the type
32/// of the expression does not implement `Copy` and you don't want
33/// to give up ownership, you can instead borrow with `dbg!(&expr)`
34/// for some expression `expr`.
35///
36/// The `dbg!` macro works exactly the same in release builds.
37/// This is useful when debugging issues that only occur in release
38/// builds or when debugging in release mode is significantly faster.
39///
40/// Note that the macro is intended as a temporary debugging tool to be
41/// used during development. Therefore, avoid committing `dbg!` macro
42/// invocations into the kernel tree.
43///
44/// For debug output that is intended to be kept in the kernel tree,
45/// use [`pr_debug`] and similar facilities instead.
46///
47/// # Stability
48///
49/// The exact output printed by this macro should not be relied upon
50/// and is subject to future changes.
51///
52/// # Further examples
53///
54/// With a method call:
55///
56/// ```rust
57/// # #[expect(clippy::disallowed_macros)]
58/// fn foo(n: usize) {
59///     if dbg!(n.checked_sub(4)).is_some() {
60///         // ...
61///     }
62/// }
63///
64/// foo(3)
65/// ```
66///
67/// This prints to the kernel log:
68///
69/// ```text,ignore
70/// [src/main.rs:4] n.checked_sub(4) = None
71/// ```
72///
73/// Naive factorial implementation:
74///
75/// ```rust
76/// # #[expect(clippy::disallowed_macros)]
77/// # {
78/// fn factorial(n: u32) -> u32 {
79///     if dbg!(n <= 1) {
80///         dbg!(1)
81///     } else {
82///         dbg!(n * factorial(n - 1))
83///     }
84/// }
85///
86/// dbg!(factorial(4));
87/// # }
88/// ```
89///
90/// This prints to the kernel log:
91///
92/// ```text,ignore
93/// [src/main.rs:3] n <= 1 = false
94/// [src/main.rs:3] n <= 1 = false
95/// [src/main.rs:3] n <= 1 = false
96/// [src/main.rs:3] n <= 1 = true
97/// [src/main.rs:4] 1 = 1
98/// [src/main.rs:5] n * factorial(n - 1) = 2
99/// [src/main.rs:5] n * factorial(n - 1) = 6
100/// [src/main.rs:5] n * factorial(n - 1) = 24
101/// [src/main.rs:11] factorial(4) = 24
102/// ```
103///
104/// The `dbg!(..)` macro moves the input:
105///
106/// ```ignore
107/// /// A wrapper around `usize` which importantly is not Copyable.
108/// #[derive(Debug)]
109/// struct NoCopy(usize);
110///
111/// let a = NoCopy(42);
112/// let _ = dbg!(a); // <-- `a` is moved here.
113/// let _ = dbg!(a); // <-- `a` is moved again; error!
114/// ```
115///
116/// You can also use `dbg!()` without a value to just print the
117/// file and line whenever it's reached.
118///
119/// Finally, if you want to `dbg!(..)` multiple values, it will treat them as
120/// a tuple (and return it, too):
121///
122/// ```
123/// # #![expect(clippy::disallowed_macros)]
124/// assert_eq!(dbg!(1usize, 2u32), (1, 2));
125/// ```
126///
127/// However, a single argument with a trailing comma will still not be treated
128/// as a tuple, following the convention of ignoring trailing commas in macro
129/// invocations. You can use a 1-tuple directly if you need one:
130///
131/// ```
132/// # #[expect(clippy::disallowed_macros)]
133/// # {
134/// assert_eq!(1, dbg!(1u32,)); // trailing comma ignored
135/// assert_eq!((1,), dbg!((1u32,))); // 1-tuple
136/// # }
137/// ```
138///
139/// [`std::dbg`]: https://doc.rust-lang.org/std/macro.dbg.html
140/// [`eprintln`]: https://doc.rust-lang.org/std/macro.eprintln.html
141/// [`printk`]: https://docs.kernel.org/core-api/printk-basics.html
142/// [`pr_info`]: crate::pr_info!
143/// [`pr_debug`]: crate::pr_debug!
144#[macro_export]
145macro_rules! dbg {
146    // NOTE: We cannot use `concat!` to make a static string as a format argument
147    // of `pr_info!` because `file!` could contain a `{` or
148    // `$val` expression could be a block (`{ .. }`), in which case the `pr_info!`
149    // will be malformed.
150    () => {
151        $crate::pr_info!("[{}:{}:{}]\n", ::core::file!(), ::core::line!(), ::core::column!())
152    };
153    ($val:expr $(,)?) => {
154        // Use of `match` here is intentional because it affects the lifetimes
155        // of temporaries - https://stackoverflow.com/a/48732525/1063961
156        match $val {
157            tmp => {
158                $crate::pr_info!("[{}:{}:{}] {} = {:#?}\n",
159                    ::core::file!(), ::core::line!(), ::core::column!(),
160                    ::core::stringify!($val), &tmp);
161                tmp
162            }
163        }
164    };
165    ($($val:expr),+ $(,)?) => {
166        ($($crate::dbg!($val)),+,)
167    };
168}