Skip to main content

hotpath_macros_meta/
lib.rs

1use proc_macro::TokenStream;
2
3#[cfg(feature = "hotpath-meta")]
4mod lib_on;
5
6#[cfg(not(feature = "hotpath-meta"))]
7mod lib_off;
8
9/// Initializes the hotpath profiling system and generates a performance report on program exit.
10///
11/// This attribute macro should be applied to your program's main (or other entry point) function
12/// to enable profiling. It creates a guard that initializes the background measurement processing
13/// thread and automatically displays a performance summary when the program exits. Additionally
14/// it creates a measurement guard that will be used to measure the wrapper function itself.
15///
16/// For programmatic control over the same options, see
17/// [`HotpathGuardBuilder`](../hotpath_meta/struct.HotpathGuardBuilder.html).
18///
19/// # Parameters
20///
21/// * `percentiles` - Array of percentile values (0-100) to compute. Default: `[95]`
22/// * `format` - Output format: `"table"` (default), `"json"`, `"json-pretty"`, or `"none"`
23/// * `limit` - Maximum number of functions in the report (0 = unlimited). Default: `15`
24/// * `output_path` - File path for the report. Defaults to stdout. Overridden by `HOTPATH_META_OUTPUT_PATH` env var.
25/// * `report` - Comma-separated sections to include: `"functions-timing"`, `"functions-alloc"`, `"channels"`, `"streams"`, `"futures"`, `"threads"`, or `"all"`. Overridden by `HOTPATH_META_REPORT` env var.
26///
27/// # Examples
28///
29/// Basic usage with default settings (P95 percentile, table format):
30///
31/// ```rust,no_run
32/// #[hotpath_meta::main]
33/// fn main() {
34///     // Your code here
35/// }
36/// ```
37///
38/// Custom percentiles:
39///
40/// ```rust,no_run
41/// #[tokio::main]
42/// #[hotpath_meta::main(percentiles = [50, 90, 95, 99])]
43/// async fn main() {
44///     // Your code here
45/// }
46/// ```
47///
48/// JSON output to file:
49///
50/// ```rust,no_run
51/// #[hotpath_meta::main(format = "json-pretty", output_path = "report.json")]
52/// fn main() {
53///     // Your code here
54/// }
55/// ```
56///
57/// Select report sections:
58///
59/// ```rust,no_run
60/// #[hotpath_meta::main(report = "functions-timing,channels")]
61/// fn main() {
62///     // Your code here
63/// }
64/// ```
65///
66/// # Usage with Tokio
67///
68/// When using with tokio, place `#[tokio::main]` before `#[hotpath_meta::main]`:
69///
70/// ```rust,no_run
71/// #[tokio::main]
72/// #[hotpath_meta::main]
73/// async fn main() {
74///     // Your code here
75/// }
76/// ```
77///
78/// # Limitations
79///
80/// Only one hotpath guard can be active at a time. Creating a second guard (either via this
81/// macro or via [`HotpathGuardBuilder`](../hotpath_meta/struct.HotpathGuardBuilder.html)) will cause a panic.
82///
83/// # See Also
84///
85/// * [`measure`](macro@measure) - Attribute macro for instrumenting functions
86/// * [`measure_block!`](../hotpath_meta/macro.measure_block.html) - Macro for measuring code blocks
87/// * [`HotpathGuardBuilder`](../hotpath_meta/struct.HotpathGuardBuilder.html) - Programmatic alternative to this macro
88#[proc_macro_attribute]
89pub fn main(attr: TokenStream, item: TokenStream) -> TokenStream {
90    #[cfg(feature = "hotpath-meta")]
91    {
92        lib_on::main_impl(attr, item)
93    }
94    #[cfg(not(feature = "hotpath-meta"))]
95    {
96        lib_off::main_impl(attr, item)
97    }
98}
99
100/// Instruments a function to measure execution time or memory allocations.
101///
102/// Automatically detects sync vs async and inserts the appropriate measurement guard.
103/// Compiles to zero overhead when the `hotpath-meta` feature is disabled.
104///
105/// # Measurements
106///
107/// * **Time profiling** (default) — execution duration via high-precision timers
108/// * **Allocation profiling** (`hotpath-alloc-meta` feature) — bytes allocated and allocation count
109///
110/// # Parameters
111///
112/// * `log` - If `true`, logs the return value on each call (requires `Debug` on return type)
113/// * `future` - If `true`, also tracks the future lifecycle (poll count, state transitions, cancellation). Only valid on async functions.
114///
115/// # Examples
116///
117/// ```rust,no_run
118/// #[hotpath_meta::measure]
119/// fn process(data: &[u8]) -> usize {
120///     data.len()
121/// }
122///
123/// #[hotpath_meta::measure(log = true)]
124/// fn compute() -> i32 {
125///     42
126/// }
127///
128/// #[hotpath_meta::measure(future = true)]
129/// async fn fetch_data() -> Vec<u8> {
130///     vec![1, 2, 3]
131/// }
132/// ```
133///
134/// # Async Allocation Limitation
135///
136/// Allocation profiling requires `current_thread` tokio runtime because thread-local
137/// tracking cannot follow tasks across threads. Time profiling works with any runtime.
138///
139/// # See Also
140///
141/// * [`main`](macro@main) - Initializes the profiling system
142/// * [`measure_all`](macro@measure_all) - Bulk instrumentation for modules and impl blocks
143/// * [`measure_block!`](../hotpath_meta/macro.measure_block.html) - Instruments code blocks
144#[proc_macro_attribute]
145pub fn measure(attr: TokenStream, item: TokenStream) -> TokenStream {
146    #[cfg(feature = "hotpath-meta")]
147    {
148        lib_on::measure_impl(attr, item)
149    }
150    #[cfg(not(feature = "hotpath-meta"))]
151    {
152        lib_off::measure_impl(attr, item)
153    }
154}
155
156/// Instruments an async function to track its lifecycle as a Future.
157///
158/// Wraps the function body with the `future!` macro to track poll counts,
159/// state transitions (pending/ready/cancelled), and optionally the output value.
160/// Can only be applied to `async fn`.
161///
162/// # Parameters
163///
164/// * `log` - If `true`, logs the output value on completion (requires `Debug` on return type)
165///
166/// # Examples
167///
168/// ```rust,no_run
169/// #[hotpath_meta::future_fn]
170/// async fn fetch_data() -> Vec<u8> {
171///     vec![1, 2, 3]
172/// }
173///
174/// #[hotpath_meta::future_fn(log = true)]
175/// async fn compute() -> i32 {
176///     42
177/// }
178/// ```
179///
180/// # See Also
181///
182/// * [`measure`](macro@measure) - Instruments execution time / allocations
183/// * [`future!`](../hotpath_meta/macro.future.html) - Declarative macro for wrapping future expressions
184#[proc_macro_attribute]
185pub fn future_fn(attr: TokenStream, item: TokenStream) -> TokenStream {
186    #[cfg(feature = "hotpath-meta")]
187    {
188        lib_on::future_fn_impl(attr, item)
189    }
190    #[cfg(not(feature = "hotpath-meta"))]
191    {
192        lib_off::future_fn_impl(attr, item)
193    }
194}
195
196/// Marks a function to be excluded from profiling when used with [`measure_all`](macro@measure_all).
197///
198/// # Usage
199///
200/// ```rust,no_run
201/// #[hotpath_meta::measure_all]
202/// impl MyStruct {
203///     fn important_method(&self) {
204///         // This will be measured
205///     }
206///
207///     #[hotpath_meta::skip]
208///     fn not_so_important_method(&self) -> usize {
209///         // This will NOT be measured
210///         self.value
211///     }
212/// }
213/// ```
214///
215/// # See Also
216///
217/// * [`measure_all`](macro@measure_all) - Bulk instrumentation macro
218/// * [`measure`](macro@measure) - Individual function instrumentation
219#[proc_macro_attribute]
220pub fn skip(attr: TokenStream, item: TokenStream) -> TokenStream {
221    #[cfg(feature = "hotpath-meta")]
222    {
223        lib_on::skip_impl(attr, item)
224    }
225    #[cfg(not(feature = "hotpath-meta"))]
226    {
227        lib_off::skip_impl(attr, item)
228    }
229}
230
231/// Instruments all functions in a module or impl block with the `measure` profiling macro.
232///
233/// This attribute macro applies the [`measure`](macro@measure) macro to every function
234/// in the annotated module or impl block, providing bulk instrumentation without needing
235/// to annotate each function individually.
236///
237/// # Usage
238///
239/// On modules:
240///
241/// ```rust,no_run
242/// #[hotpath_meta::measure_all]
243/// mod my_module {
244///     fn function_one() {
245///         // This will be automatically measured
246///     }
247///
248///     fn function_two() {
249///         // This will also be automatically measured
250///     }
251/// }
252/// ```
253///
254/// On impl blocks:
255///
256/// ```rust,no_run
257/// struct MyStruct;
258///
259/// #[hotpath_meta::measure_all]
260/// impl MyStruct {
261///     fn method_one(&self) {
262///         // This will be automatically measured
263///     }
264///
265///     fn method_two(&self) {
266///         // This will also be automatically measured
267///     }
268/// }
269/// ```
270///
271/// # See Also
272///
273/// * [`measure`](macro@measure) - Attribute macro for instrumenting individual functions
274/// * [`main`](macro@main) - Attribute macro that initializes profiling
275/// * [`skip`](macro@skip) - Marker to exclude specific functions from measurement
276#[proc_macro_attribute]
277pub fn measure_all(attr: TokenStream, item: TokenStream) -> TokenStream {
278    #[cfg(feature = "hotpath-meta")]
279    {
280        lib_on::measure_all_impl(attr, item)
281    }
282    #[cfg(not(feature = "hotpath-meta"))]
283    {
284        lib_off::measure_all_impl(attr, item)
285    }
286}