testutils/
lib.rs

1#![cfg_attr(not(feature = "std"), no_std)]
2#![cfg_attr(__unstable_doc, feature(doc_auto_cfg, doc_notable_trait))]
3/*!
4## Features
5
6- **all**
7  All available features enabled
8
9- **std**
10  Enables standard library support. When enabled, the crate cannot be used in `no_std` environments.
11
12- **ext_traits**
13  Additional trait extensions:
14  - `BoolExt` - Adds `.ok_or_else()` method for `bool` type
15  - Re-exports `Pipe` and `Tap` traits from `tap` crate
16
17- **tiny_container**
18  Compact string (<=N: Inline(Stack), >N: Overflow to Heap):
19  - `TString<const N: usize>` type alias for `TinyString<[u8; N]>`
20  - `Formattable` trait
21    - Enables `format` support for `TString`
22  - `IntoBoxedStr` trait
23    - Adds `.into_boxed_str()` conversion
24
25- **os_cmd**
26  Configurable command builders:
27  - Preconfigured cargo command structs (e.g., `CargoDoc`, `CargoCmd`)
28  - Cross-platform command execution utilities
29*/
30extern crate alloc;
31
32#[cfg(feature = "os_cmd")]
33pub mod os_cmd;
34
35#[cfg(feature = "ext_traits")]
36/// Provides BoolExt(`.ok_or_else()`)
37pub mod traits;
38
39#[cfg(feature = "tiny_container")]
40/// TString & TinyVec
41pub mod tiny_container;
42
43/// Runs the given function and prints the elapsed time.
44/// It supports stable Rust.
45///
46/// ## Example
47///
48/// ```ignore
49/// fn bench_foo() {
50///   testutils::simple_benchmark(|| {
51///     foo() // Your code here...
52///   })
53/// }
54/// ```
55#[cfg(feature = "std")]
56pub fn simple_benchmark<U, F: FnOnce() -> U>(f: F) {
57  let start = std::time::Instant::now();
58  f();
59  eprintln!("Time taken: {:?}", start.elapsed());
60}
61
62/// `env!("CARGO_PKG_NAME")`
63#[macro_export]
64macro_rules! get_pkg_name {
65  () => {
66    env!("CARGO_PKG_NAME")
67  };
68}
69
70/// Similar to the `dbg!` macro, but inspects values by reference without moving
71/// them. This allows debugging values without transferring ownership, while
72/// showing the underlying value's type information (not reference types).
73///
74/// This macro uses [`log::debug!`] internally, so you must:
75/// 1. Configure a logger (e.g., `env_logger`) with debug level enabled
76/// 2. Initialize the logger before use
77///
78/// ## Key Differences from `dbg!`
79/// - Returns `()` instead of the original value
80/// - Requires explicit logger initialization
81///
82/// ## Examples
83///
84/// Basic usage with automatic type deduction
85///
86/// ```
87/// use testutils::dbg_ref;
88/// // Must initialize logger first:
89/// // env_logger::builder().filter_level(log::LevelFilter::Debug).init();
90///
91/// let counter = 42;
92/// dbg_ref!(counter); // [DEBUG] counter: i32 = 42
93///
94/// let message = "Hello";
95/// dbg_ref!(message); // [DEBUG] message: &str = "Hello"
96///
97/// let values = vec![(1, "a"), (2, "b")];
98/// dbg_ref!(values); // [DEBUG] values: alloc::vec::Vec<(i32, &str)> = [...]
99/// ```
100///
101/// Debugging multiple values
102///
103/// ```
104/// use testutils::dbg_ref;
105/// let width = 30;
106/// let label = "size";
107///
108/// dbg_ref!(width, label);
109/// // Outputs:
110/// // [DEBUG] width: i32 = 30
111/// // [DEBUG] label: &str = "size"
112/// ```
113///
114/// ## Implementation Notes
115/// 1. Uses `core::any::type_name_of_val` for type information
116/// 2. Formats output as: `{variable_name}: {type} = {debug_representation}`
117/// 3. Multiple arguments generate separate log entries
118#[macro_export]
119macro_rules! dbg_ref {
120  ($val:expr $(,)?) => {{
121    match &$val {
122      tmp => {
123        log::debug!(
124          "{name}: {type_name} = {tmp:?}",
125          name = stringify!($val),
126          type_name = core::any::type_name_of_val(tmp),
127        );
128      }
129    }
130  }};
131  ($($val:expr),+ $(,)?) => {
132    ($($crate::dbg_ref!($val)),+,)
133  };
134}
135
136/// Outputs the information of the expression(s) to stderr.
137///
138/// ```
139/// use testutils::dbg;
140/// let width = 30;
141/// let label = "size";
142///
143/// dbg!(width, label);
144/// // Outputs:
145/// //  width: i32 = 30
146/// //  label: &str = "size"
147/// ```
148#[cfg(feature = "std")]
149#[macro_export]
150macro_rules! dbg {
151  ($val:expr $(,)?) => {{
152    match &$val {
153      tmp => {
154        eprintln!(
155          "\u{1B}[35m{name}\u{1B}[0m: \u{1B}[33m{type_name}\u{1B}[0m = {tmp:?}",
156          name = stringify!($val),
157          type_name = core::any::type_name_of_val(tmp),
158        );
159      }
160    }
161  }};
162  ($($val:expr),+ $(,)?) => {
163    ($($crate::dbg_ref!($val)),+,)
164  };
165}
166
167/// Generates a list of tuples containing field names and their values
168///
169/// ## Example
170///
171/// ```
172/// use testutils::generate_struct_arr;
173///
174/// struct BuildStd {
175///   std: bool,
176///   core: bool,
177///   alloc: bool,
178/// }
179///
180/// let b = BuildStd {
181///   std: false,
182///   core: true,
183///   alloc: true,
184/// };
185///
186/// let arr = generate_struct_arr![ b => core, alloc, std ];
187/// assert_eq!(
188///   arr,
189///   [("core", true), ("alloc", true), ("std", false)]
190/// );
191/// ```
192#[macro_export]
193macro_rules! generate_struct_arr {
194  ($self:ident => $( $field:ident ),* $(,)? ) => {{
195    [
196      $( ( stringify!($field), $self.$field ), )*
197    ]
198  }};
199}