crabtime/
lib.rs

1//! # πŸ¦€ Crabtime
2//!
3//! <img width="680" alt="banner" src="https://github.com/user-attachments/assets/d273e38d-951c-4183-b42e-ac5bdf939d69">
4//!
5//! <br/>
6//! <br/>
7//!
8//! **Crabtime** offers a novel way to write Rust macros, inspired by
9//! [Zig's comptime][zigs_comptime]. It provides even more flexibility and power than procedural
10//! macros, while remaining easier and more natural to read and write than
11//! [`macro_rules!`][macro_rules].
12//!
13//! <br/>
14//! <br/>
15//!
16//! # πŸ†š Comparison to Proc Macros and `macro_rules!`
17//!
18//! Below is a comparison of key aspects of Rust's macro systems:
19//!
20//! <h5><b>Input/Output</b></h5>
21//!
22//! | <div style="width:300px"/>                            | Crabtime | Proc Macro | `macro_rules!` |
23//! | :---                                                  | :---     | :---       | :---           |
24//! | Input as [Token Stream][token_stream]                 | βœ…       | βœ…         | ❌             |
25//! | Input as [Macro Fragments][macro_fragments]           | βœ…       | ❌         | βœ…             |
26//! | Input as Rust Code (String)                           | βœ…       | ❌         | ❌             |
27//! | Output as [Token Stream][token_stream]                | βœ…       | βœ…         | ❌             |
28//! | Output as [Macro Fragments Template][macro_fragments] | βœ…       | ❌         | βœ…             |
29//! | Output as Rust Code (String)                          | βœ…       | ❌         | ❌             |
30//!
31//! <h5><b>Functionalities</b></h5>
32//!
33//! | <div style="width:300px"/>                            | Crabtime | Proc Macro | `macro_rules!` |
34//! | :---                                                  | :---     | :---       | :---           |
35//! | Advanced transformations                              | βœ…       | βœ…         | ❌             |
36//! | [Space-aware interpolation](#-output)                 | βœ…       | ❌         | ❌             |
37//! | Can define [fn-like macros][fn_like_macros]           | βœ…       | βœ…         | βœ…             |
38//! | Can define [derive macros][derive_macros]             | 🚧       | βœ…         | ❌             |
39//! | Can define [attribute macros][attribute_macros]       | 🚧       | βœ…         | ❌             |
40//! | Reusable across modules and crates                    | βœ…       | βœ…         | βœ…             |
41//!
42//! <h5><b>Comfort of life</b></h5>
43//!
44//! | <div style="width:300px"/>                            | Crabtime | Proc Macro | `macro_rules!` |
45//! | :---                                                  | :---     | :---       | :---           |
46//! | Full expansion in IDEs[^supported_ides]               | βœ…       | βœ…         | βœ…             |
47//! | Full type hints in IDEs[^supported_ides]              | βœ…       | βœ…         | ❌             |
48//! | Works with [rustfmt][rustfmt]                         | βœ…       | βœ…         | ❌             |
49//! | Easy to define (inline, the same crate)               | βœ…       | ❌         | βœ…             |
50//! | Easy to read                                          | βœ…       | ❌         | ⚠️             |
51//! | [Hygienic][macro_hygiene]                             | ❌       | ❌         | βœ…             |
52//!
53//! <br/>
54//! <br/>
55//!
56//! # 🎯 One-shot evaluation
57//!
58//! The simplest and least exciting use of Crabtime is straightforward compile-time code
59//! evaluation. To evaluate an expression and paste its output as new code, just use
60//! `crabtime::eval`, as shown below:
61//!
62//! ```
63//! const MY_NUM: usize = crabtime::eval! {
64//!     (std::f32::consts::PI.sqrt() * 10.0).round() as usize
65//! };
66//! # fn main() {}
67//! ```
68//!
69//! <br/>
70//! <br/>
71//!
72//! # 🀩 Function-like macros
73//!
74//! Use the `crabtime::function` attribute to define a new [function-like macro][fn_like_macros].
75//! Crabtime will remove the annotated function and replace it with a macro definition of the same
76//! name. You can then call the macro to compile and execute the function at build time, and use
77//! its output as the generated Rust code. You can also use the standard `#[macro_export]`
78//! attribute to export your macro. Let's start with a simple example, and let's refine it down
79//! the line. Let's generate the following Rust code:
80//!
81//! ```
82//! enum Position1 { X }
83//! enum Position2 { X, Y }
84//! enum Position3 { X, Y, Z }
85//! enum Position4 { X, Y, Z, W }
86//! ```
87//!
88//! We can do it in this, not very exciting way:
89//!
90//! ```
91//! // Replaces the function definition with a `gen_positions1!` macro.
92//! #[crabtime::function]
93//! #[macro_export] // <- This is how you export it!
94//! fn gen_positions1() -> &str {
95//!     "
96//!     enum Position1 { X }
97//!     enum Position2 { X, Y }
98//!     enum Position3 { X, Y, Z }
99//!     enum Position4 { X, Y, Z, W }
100//!     "
101//! }
102//!
103//! // Compiles and evaluates the gen_positions1 function at build-time and
104//! // uses its output as the new code source.
105//! gen_positions1!();
106//! # fn main() {}
107//! ```
108//!
109//! <br/>
110//!
111//! <div class="warning">
112//! Due to limitations of `macro_rules!` (which `Crabtime` uses under the hood), you must either
113//! wrap the  macro call in extra braces when using it in an expression context, or use
114//! `crabtime::expression` instead of `crabtime::function`, which does this step for you. For
115//! example, if you want to assign the macro’s output to a variable, do this:
116//!
117//! ```
118//! #[crabtime::expression]
119//! fn gen_expr() {
120//!     let output_num = 3;
121//!     crabtime::output! {
122//!         {{output_num}}
123//!     }
124//! }
125//!
126//! fn test() {
127//!     let x = gen_expr!();
128//! }
129//! ```
130//!
131//! Alternatively, you can wrap the macro call in extra braces by yourself if you want to use the
132//! macro both in expression and statement contexts:
133//!
134//! ```
135//! #[crabtime::function]
136//! fn gen_expr() {
137//!     let output_num = 3;
138//!     crabtime::output! {
139//!         {{output_num}}
140//!     }
141//! }
142//!
143//! fn test() {
144//!     // `let x = gen_expr!{};` would not work here!
145//!     let x = { gen_expr!{} };
146//! }
147//! ```
148//!
149//! </div>
150//!
151//! <br/>
152//! <br/>
153//!
154//! # 🀩 Attribute and derive macros
155//! Currently, generating [attribute macros][attribute_macros] and [derive macros][derive_macros]
156//! is not supported, but there are several ways to achieve it. If you want to help, ping us on
157//! [GitHub](https://github.com/wdanilo/crabtime).
158//!
159//! <br/>
160//! <br/>
161//!
162//! # πŸ“€ Output
163//!
164//! There are several ways to generate the output code from a Crabtime macro. We recommend you to
165//! use either `crabtime::output!` or `crabtime::quote!` macros, as they allow for the most
166//! concise, easy-to-understand, and maintainable implementations. Supported input types are
167//! described later, for now just ignore them.
168//!
169//! <br/>
170//!
171//! <h5><b>Generating output by using <code>crabtime::output!</code></b></h5>
172//!
173//! The simplest and most recommended way to generate macro output is by using the
174//! `crabtime::output!` macro. It allows for space-aware variable interpolation. It's like the
175//! `format!` macro, but with inversed rules regarding curly braces – it preserves single braces
176//! and uses double braces for interpolation. Please note that it preserves spaces, so
177//! `Position {{ix}}` and `Position{{ix}}` mean different things, and the latter will generate
178//! `Position1`, `Position2`, etc.
179//!
180//! ```
181//! #[crabtime::function]
182//! fn gen_positions2(components: Vec<String>) {
183//!     for dim in 1 ..= components.len() {
184//!         let cons = components[0..dim].join(",");
185//!         crabtime::output! {
186//!             enum Position{{dim}} {
187//!                 {{cons}}
188//!             }
189//!         }
190//!     }
191//! }
192//! gen_positions2!(["X", "Y", "Z", "W"]);
193//! # fn main() {}
194//! ```
195//!
196//! <br/>
197//!
198//! <div class="warning">
199//!
200//! ⚠️ **Note:** Interpolated variables are inserted *as-is*, without additional quotes or escape
201//! characters.
202//!
203//! This means that if you want to insert a string literal, you must manually wrap or escape it.
204//! For example, the following code computes a `full_url` that includes quotes, because it is being
205//! inserted as a string literal into the `println!` macro within the generated code:
206//!
207//! ```rust
208//! #[crabtime::function]
209//! fn gen_urls(components: Vec<String>) {
210//!     for (idx, path) in components.iter().enumerate() {
211//!         let full_url = format!("\"{}\"", ["http://localhost:3000", path].join("/"));
212//!         crabtime::output! {
213//!             println!("{}", {{full_url}});
214//!         }
215//!     }
216//! }
217//!
218//! fn main() {
219//!     gen_urls!(["home", "about", "contact"]);
220//! }
221//! ```
222//!
223//! </div>
224//!
225//! <br/>
226//!
227//! <h5><b>Generating output by using <code>crabtime::quote!</code></b></h5>
228//!
229//! The `crabtime::quote!` macro is just like `crabtime::output!`, but instead of outputting the
230//! code immediately, it returns it (as a `String`), so you can store it in a variable and re-use
231//! it across different subsequent calls to `crabtime::quote!` or `crabtime::output!`.
232//!
233//! ```
234//! #[crabtime::function]
235//! fn gen_positions3(components: Vec<String>) -> String {
236//!     let structs = (1 ..= components.len()).map(|dim| {
237//!         let cons = components[0..dim].join(",");
238//!         crabtime::quote! {
239//!             enum Position{{dim}} {
240//!                 {{cons}}
241//!             }
242//!         }
243//!     }).collect::<Vec<String>>();
244//!     structs.join("\n")
245//! }
246//! gen_positions3!(["X", "Y", "Z", "W"]);
247//! # fn main() {}
248//! ```
249//!
250//! <br/>
251//!
252//! <h5><b>Generating output by returning a string or number</b></h5>
253//!
254//! You can simply return a string or number from the function. It will be used as the generated
255//! macro code.
256//!
257//! ```
258//! #[crabtime::function]
259//! fn gen_positions4(components: Vec<String>) -> String {
260//!     (1 ..= components.len()).map(|dim| {
261//!         let cons = components[0..dim].join(",");
262//!         format!("enum Position{dim} {{ {cons} }}")
263//!     }).collect::<Vec<_>>().join("\n")
264//! }
265//! gen_positions4!(["X", "Y", "Z", "W"]);
266//! # fn main() {}
267//! ```
268//!
269//! <br/>
270//!
271//! <h5><b>Generating output by using <code>crabtime::output_str!</code></b></h5>
272//!
273//! Alternatively, you can use the `crabtime::output_str!` macro to immediately write strings to
274//! the code output buffer:
275//!
276//! ```
277//! #[crabtime::function]
278//! fn gen_positions5(components: Vec<String>) {
279//!     for dim in 1 ..= components.len() {
280//!         let cons = components[0..dim].join(",");
281//!         crabtime::output_str!("enum Position{dim} {{ {cons} }}")
282//!     }
283//! }
284//! gen_positions5!(["X", "Y", "Z", "W"]);
285//! # fn main() {}
286//! ```
287//!
288//! <br/>
289//!
290//! <h5><b>Generating output by returning a <code>TokenStream</code></b></h5>
291//!
292//! Finally, you can output [TokenStream][token_stream] from the macro. Please note that for
293//! brevity the below example uses [inline dependency injection](inline_dependency_injection),
294//! which is described later. In real code you should use your `Cargo.toml`'s
295//! `[build-dependencies]` section to include the necessary dependencies instead.
296//!
297//! ```
298//! #[crabtime::function]
299//! fn gen_positions6() -> proc_macro2::TokenStream {
300//!     // Inline dependencies used for brevity.
301//!     // You should use [build-dependencies] section in your Cargo.toml instead.
302//!     #![dependency(proc-macro2 = "1")]
303//!     #![dependency(syn = "2")]
304//!     #![dependency(quote = "1")]
305//!     use proc_macro2::Span;
306//!     use quote::quote;
307//!
308//!     let components = ["X", "Y", "Z", "W"];
309//!     let defs = (1 ..= components.len()).map(|dim| {
310//!         let cons = components[0..dim].iter().map(|t|
311//!             syn::Ident::new(t, Span::call_site())
312//!         );
313//!         let ident = syn::Ident::new(&format!("Position{dim}"), Span::call_site());
314//!         quote! {
315//!             enum #ident {
316//!                 #(#cons),*
317//!             }
318//!         }
319//!     }).collect::<Vec<_>>();
320//!     quote! {
321//!         #(#defs)*
322//!     }
323//! }
324//! gen_positions6!();
325//! # fn main() {}
326//! ```
327//!
328//! <br/>
329//! <br/>
330//!
331//! # πŸ“₯ Input
332//!
333//! Similarly to generating output, there are several ways to parametrize macros and provide them
334//! with input at their call site. We recommend you use the pattern parametrization, as it's the
335//! simplest and easiest to maintain.
336//!
337//! <br/>
338//!
339//! <h5><b>Input by using supported arguments</b></h5>
340//!
341//! Currently, you can use any combination of the following types as arguments to your macro and
342//! they will be automatically translated to patterns: `Vec<...>`, `&str`, `String`, and numbers.
343//! If the expected argument is a string, you can pass either a string literal or an identifier,
344//! which will automatically be converted to a string.
345//!
346//! ```
347//! #[crabtime::function]
348//! fn gen_positions7(name: String, components: Vec<String>) {
349//!     for dim in 1 ..= components.len() {
350//!         let cons = components[0..dim].join(",");
351//!         crabtime::output! {
352//!             enum {{name}}{{dim}} {
353//!                 {{cons}}
354//!             }
355//!         }
356//!     }
357//! }
358//! gen_positions7!(Position, ["X", "Y", "Z", "W"]);
359//! gen_positions7!(Color, ["R", "G", "B"]);
360//! # fn main() {}
361//! ```
362//!
363//! <br/>
364//!
365//! <h5><b>Input by using patterns</b></h5>
366//!
367//! In case you want even more control, you can use the same patterns as
368//! [`macro_rules!`][macro_rules] by using a special `pattern!` macro, and you can expand any pattern
369//! using the `expand!` macro:
370//!
371//! <div style="background-color:#397be440; padding: 8px; border-radius: 8px; margin-bottom: 8px;">
372//! πŸ’‘ Please note that the <code>expand!</code> macro simply passes its input along. It is used
373//! only to make the code within the function a valid Rust code block. Thus, you do not need to use
374//! it if you want to expand variables within other macros, like <code>stringify!</code>.
375//! </div>
376//!
377//! ```
378//! // Please note that we need to type the pattern argument as `_` to make the
379//! // code a valid Rust code.
380//! #[crabtime::function]
381//! fn gen_positions8(pattern!($name:ident, $components:tt): _) {
382//!     let components = expand!($components);
383//!     for dim in 1 ..= components.len() {
384//!         let cons = components[0..dim].join(",");
385//!         // We don't need to use `expand!` here.
386//!         let name = stringify!($name);
387//!         crabtime::output! {
388//!             enum {{name}}{{dim}} {
389//!                 {{cons}}
390//!             }
391//!         }
392//!     }
393//! }
394//! gen_positions8!(Position, ["X", "Y", "Z", "W"]);
395//! gen_positions8!(Color, ["R", "G", "B"]);
396//! # fn main() {}
397//! ```
398//!
399//! <br/>
400//!
401//! <h5><b>Input by using <code>TokenStream</code></b></h5>
402//!
403//! Alternatively, you can consume the provided input as a [TokenStream][token_stream]:
404//!
405//! ```
406//! #[crabtime::function]
407//! fn gen_positions9(name: TokenStream) {
408//!     #![dependency(proc-macro2 = "1")]
409//!     let components = ["X", "Y", "Z", "W"];
410//!     let name_str = name.to_string();
411//!     for dim in 1 ..= components.len() {
412//!         let cons = components[0..dim].join(",");
413//!         crabtime::output! {
414//!             enum {{name_str}}{{dim}} {
415//!                 {{cons}}
416//!             }
417//!         }
418//!     }
419//! }
420//! gen_positions9!(Position);
421//! # fn main() {}
422//! ```
423//!
424//! <br/>
425//! <br/>
426//!
427//! # πŸš€ Performance
428//!
429//! The lifecycle of a Crabtime macro is similar to that of a procedural macro. It is compiled as a
430//! separate crate and then invoked to transform input tokens into output tokens. On the unstable
431//! Rust channel, Crabtime and procedural macros have the same performance. On the stable channel,
432//! Crabtime requires slightly more time than a procedural macro after you change your macro
433//! definition. In other words, Crabtime’s performance is similar to procedural macros. It has
434//! higher compilation overhead than [`macro_rules!`][macro_rules] but processes tokens and complex
435//! transformations faster.
436//!
437//! |                                            | <div style="width:200px">Proc Macro</div> | <div style="width:200px">Crabtime</div>               | <div style="width:200px"><code>macro_rules!</code></div> |
438//! | :---                                       | :---                                      | :---                                                  | :---                                               |
439//! | First evaluation (incl. compilation)       | ⚠️ Relatively slow                        | ⚠️ Relatively slow                                    | βœ… Fast                                            |
440//! | Next evaluation (on call-site change)      | βœ… Fast                                   | βœ… Fast on nightly <br/> ⚠️ Relatively slow on stable |  ❌ Slow for complex transformations               |
441//! | Cost after changing module code without changing macro-call site code | βœ… Zero        | βœ… Zero                                               | βœ… Zero                                            |
442//!
443//! <br/>
444//!
445//! <h5><b>Cache</b></h5>
446//!
447//! When a Crabtime macro is called, it creates a new Rust project, compiles it, evaluates it, and
448//! interprets the results as the generated Rust code. When you call the macro again (for example,
449//! after changing the macro’s parameters or calling the same macro in a different place), Crabtime
450//! can reuse the previously generated project. This feature is called β€œcaching.” It is enabled by
451//! default on the nightly channel and can be enabled on the stable channel by providing a `module`
452//! attribute, for example:
453//!
454//! ```ignore
455//! #[crabtime::function(cache_key=my_key)]
456//! #[module(my_crate::my_module)]
457//! fn my_macro() {
458//!     // ...
459//! }
460//! ```
461//!
462//! The cache is always written to
463//! `<project_dir>/target/debug/build/crabtime/<module>/<macro_name>`. The defaults are presented
464//! below:
465//!
466//! |                      | Rust Unstable           | Rust Stable                               |
467//! | :---                 | :---                    | :---                                      |
468//! | Cache enabled        | βœ…                      | ❌ by default, βœ… when `module` used.    |
469//! | `module` default     | path to def-site module | __none__                                 |
470//!
471//! Please note that caching will be automatically enabled on the stable channel as soon as the
472//! [proc_macro_span][proc_macro_span] feature is stabilized. That feature allows Crabtime to read
473//! the path of the file where the macro was used, so it can build a unique cache key.
474//!
475//! <br/>
476//!
477//! <h5><b>Performance Stats</b></h5>
478//!
479//! Crabtime also generates runtime and performance statistics to help you understand how much time
480//! was spent evaluating your macros, where projects were generated, and which options were used.
481//! If you expand any usage of `#[crabtime::function]` (for example, in your IDE), you will see
482//! compilation stats like:
483//!
484//! ```text
485//! # Compilation Stats
486//! Start: 13:17:09 (825)
487//! Duration: 0.35 s
488//! Cached: true
489//! Output Dir: /Users/crabtime_user/my_project/target/debug/build/crabtime/macro_path
490//! Macro Options: MacroOptions {
491//!     cache: true,
492//!     content_base_name: false,
493//! }
494//! ```
495//!
496//! Please note that you can be presented with the `Cached: true` result even after the first
497//! macro evaluation if your IDE or build system evaluated it earlier in the background.
498//!
499//! <br/>
500//! <br/>
501//!
502//! # πŸͺ² Logging & Debugging
503//!
504//! There are several ways to log from your Crabtime macros. Because
505//! [proc_macro::Diagnostic](https://doc.rust-lang.org/proc_macro/struct.Diagnostic.html) is
506//! currently a nightly-only feature, Crabtime prints nicer warnings and errors if you are using
507//! nightly Rust channel. They look just like warnings and errors from the Rust compiler.
508//! Otherwise, your warnings and errors will be printed to the console with a `[WARNING]` or
509//! `[ERROR]` prefix.
510//!
511//! | Method               | Behavior on stable | Behavior on nightly |
512//! | :---                 | :---               | :---                |
513//! | `println!`           | Debug log in console | Debug log in console |
514//! | `crabtime::warning!` | Debug log in console | Warning in console   |
515//! | `crabtime::error!`   | Debug log in console | Error in console     |
516//!
517//! <br/>
518//!
519//! <h5><b>Stdout Protocol</b></h5>
520//!
521//! Please note that Crabtime uses stdout for all communication between the code generation process
522//! and the host process. Depending on the prefix of each stdout line, it is interpreted according
523//! to the following table. In particular, instead of using the methods shown above, you can
524//! generate code from your macros by printing it to stdout (like
525//! `println!("[OUTPUT] struct T {}")`), but it's highly discouraged.
526//!
527//! | Prefix      | Meaning |
528//! | :---        | :---    |
529//! | _(none)_    | Debug log message (informational output). |
530//! | `[OUTPUT]`  | A line of generated Rust code to be included in the final macro output. |
531//! | `[WARNING]` | A compilation warning. |
532//! | `[ERROR]`   | A compilation error. |
533//!
534//! <br/>
535//!
536//! <h5><b>Stdout Protocol Utilities</b></h5>
537//!
538//! Although you are not supposed to generate the Stdout Protocol messages manually, we believe that
539//! it is better to expose the underlying utilities so that in rare cases, you can use them to
540//! reduce the risk of malformed output. These functions allow you to transform multi-line strings
541//! by adding the appropriate prefixes:
542//!
543//! ```
544//! mod crabtime {
545//!     fn prefix_lines_with(prefix: &str, input: &str) -> String {
546//!         // Adds the given prefix to each line of the input string.
547//!         # panic!()
548//!     }
549//!
550//!     fn prefix_lines_with_output(input: &str) -> String {
551//!         // Adds `[OUTPUT]` to each line of the input string.
552//!         # panic!()
553//!     }
554//!
555//!     fn prefix_lines_with_warning(input: &str) -> String {
556//!         // Adds `[WARNING]` to each line of the input string.
557//!         # panic!()
558//!     }
559//!
560//!     fn prefix_lines_with_error(input: &str) -> String {
561//!         // Adds `[ERROR]` to each line of the input string.
562//!         # panic!()
563//!     }
564//! }
565//! ```
566//!
567//! These macros allow you to directly print prefixed lines to `stdout`, following the protocol:
568//!
569//! ```
570//! mod crabtime {
571//!     macro_rules! output_str {
572//!         // Outputs code by printing a line prefixed with `[OUTPUT]`.
573//!         # () => {};
574//!     }
575//!
576//!     macro_rules! warning {
577//!         // On the nightly channel prints a compilation warning.
578//!         // On the stable channel prints a log prefixed with `[WARNING]`.
579//!         # () => {};
580//!     }
581//!
582//!     macro_rules! error {
583//!         // On the nightly channel prints a compilation error.
584//!         // On the stable channel prints a log prefixed with `[ERROR]`.
585//!         # () => {};
586//!     }
587//! }
588//! ```
589//!
590//! <br/>
591//! <br/>
592//!
593//! # βš™οΈ Macro Cargo Configuration
594//!
595//! <div style="background-color:#397be440; padding: 8px; border-radius: 8px; margin-bottom: 8px;">
596//! πŸ’‘ On the Rust unstable channel, all configuration is automatically gathered from your
597//! Cargo.toml. It includes build-dependencies and code lints, including those defined in your
598//! workspace.
599//! </div>
600//!
601//! Every Crabtime macro is a separate Cargo project with its own configuration and dependencies.
602//! If you use nightly, Crabtime automatically uses your Cargo.toml configuration. On stable, due
603//! to lack of [proc_macro_span][proc_macro_span] stabilization, Crabtime cannot discover your
604//! Cargo.toml automatically. You must provide cargo configuration in your macro blocks, for
605//! example:
606//!
607//! ```
608//! #[crabtime::function]
609//! fn my_macro() {
610//!     // Do this only on Rust stable channel. On the unstable channel
611//!     // use your Cargo.toml's [build-dependencies] section instead.
612//!     #![edition(2024)]
613//!     #![resolver(3)]
614//!     #![dependency(anyhow = "1.0")]
615//!
616//!     type Result<T> = anyhow::Result<T>;
617//!     // ...
618//! }
619//! # fn main() {}
620//! ```
621//!
622//! Crabtime recognizes these Cargo configuration attributes. The attributes below override any
623//! configuration discovered in your Cargo.toml, even on nightly:
624//!
625//! <br/>
626//!
627//! <h5><b>Supported Cargo Configuration Attributes</b></h5>
628//!
629//! | Attribute             | Default |
630//! | :---                  | :---    |
631//! | `#![edition(...)]`    | 2024    |
632//! | `#![resolver(...)]`   | 3       |
633//! | `#![dependency(...)]` | []      |
634//!
635//! <br/>
636//! <br/>
637//!
638//! # πŸ“š Attributes
639//!
640//! You can provide any set of global attributes (`#![...]`) on top of your Crabtime macro
641//! definition for them to be applied to the given generated Crabtime crate.
642//!
643//! <br/>
644//! <br/>
645//!
646//! # πŸ—ΊοΈ Paths
647//!
648//! Crabtime macros provide access to several path variables, allowing you to traverse your
649//! project's folder structure during macro evaluation. All paths are accessible within the
650//! `crabtime::` namespace.
651//!
652//!
653//! | Path                  | Availability     | Description |
654//! | :---                  | :---             | :---        |
655//! | `WORKSPACE_PATH`      | Stable & Nightly | Path to the root of your project. This is where the top-most `Cargo.toml` resides, whether it's a single-crate project or a Cargo workspace. |
656//! | `CRATE_CONFIG_PATH`   | Nightly only     | Path to the `Cargo.toml` file of the current crate. |
657//! | `CALL_SITE_FILE_PATH` | Nightly only     | Path to the file where the macro was invoked. |
658//!
659//!
660//! ```
661//! #[crabtime::function]
662//! fn check_paths() {
663//!     println!("Workspace path: {}", crabtime::WORKSPACE_PATH);
664//! }
665//! check_paths!();
666//! # fn main() {}
667//! ```
668//!
669//! <br/>
670//! <br/>
671//!
672//! # πŸ“– How It Works Under The Hood
673//!
674//! The content of a function annotated with `crabtime::function` is pasted into the `main`
675//! function of a temporary Rust project. This project is created, compiled, executed, and (if
676//! caching is disabled) removed at build time, and its `stdout` becomes the generated Rust code.
677//! The generated `main` function looks something like this:
678//!
679//! ```
680//! const SOURCE_CODE: &str = "..."; // Your code as a string.
681//!
682//! # mod phantom_for_crabtime_name_crash_resolution {
683//! mod crabtime {
684//!     // Various utils described in this documentation.
685//!     # pub fn push_as_str(str: &mut String, result: &()) {}
686//!     # pub fn prefix_lines_with_output(input: &str) -> String { String::new() }
687//! }
688//!
689//! fn main() {
690//!     let mut __output_buffer__ = String::new();
691//!     let result = {
692//!         // Your code.
693//!     };
694//!     crabtime::push_as_str(&mut __output_buffer__, &result);
695//!     println!("{}", crabtime::prefix_lines_with_output(&__output_buffer__));
696//! }
697//! # }
698//! # fn main() {}
699//! ```
700//!
701//! The `output!` macro is essentially a shortcut for writing to output buffer using `format!`, so
702//! this:
703//!
704//! ```
705//! #[crabtime::function]
706//! fn my_macro_expansion1(components: Vec<String>) {
707//!     for dim in 1 ..= components.len() {
708//!         let cons = components[0..dim].join(",");
709//!         crabtime::output! {
710//!             enum Position{{dim}} {
711//!                 {{cons}}
712//!             }
713//!         }
714//!     }
715//! }
716//! my_macro_expansion1!(["X", "Y", "Z", "W"]);
717//! # fn main() {}
718//! ```
719//!
720//! Is equivalent to:
721//!
722//! ```
723//! #[crabtime::function]
724//! fn my_macro_expansion2(pattern!([$($components_arg:expr),*$(,)?]): _) {
725//!     let components: Vec<String> = expand!(
726//!         [$(crabtime::stringify_if_needed!($components_arg).to_string()),*]
727//!     ).into_iter().collect();
728//!     for dim in 1 ..= components.len() {
729//!         let cons = components[0..dim].join(",");
730//!         crabtime::output_str! {"
731//!             enum Position{dim} {{
732//!                 {cons}
733//!             }}
734//!         "}
735//!     }
736//! }
737//! my_macro_expansion2!(["X", "Y", "Z", "W"]);
738//! # fn main() {}
739//! ```
740//!
741//! And that, in turn, is just the same as:
742//!
743//! ```
744//! #[crabtime::function]
745//! fn my_macro_expansion3() {
746//!     let components = ["X", "Y", "Z", "W"];
747//!     for dim in 1 ..= components.len() {
748//!         let cons = components[0..dim].join(",");
749//!         __output_buffer__.push_str(
750//!             &format!("enum Position{dim} {{ {cons} }}\n")
751//!         );
752//!     }
753//! }
754//! my_macro_expansion3!();
755//! # fn main() {}
756//! ```
757//!
758//! Which, ultimately, is equivalent to:
759//!
760//! ```
761//! #[crabtime::function]
762//! fn my_macro_expansion4() {
763//!     let components = ["X", "Y", "Z", "W"];
764//!     for dim in 1 ..= components.len() {
765//!         let cons = components[0..dim].join(",");
766//!         println!("[OUTPUT] enum Position{dim} {{");
767//!         println!("[OUTPUT]     {cons}");
768//!         println!("[OUTPUT] }}");
769//!     }
770//! }
771//! my_macro_expansion4!();
772//! # fn main() {}
773//! ```
774//!
775//! <br/>
776//! <br/>
777//!
778//! # ⚠️ Corner Cases
779//! There are a few things you should be aware of when using Crabtime:
780//! - Caching is associated with the current file path. It means that if in a single file you have
781//!   multiple Crabtime macros of the same name (e.g. by putting them in different modules within a
782//!   single file), they will use the same Rust project under the hood, which effectively breaks
783//!   the whole purpose of caching.
784//! - You can't use Crabtime functions to generate consts. Instead, use `Crabtime::eval!` as shown
785//!   above. This is because when expanding constants, macros need to produce an additional pair of
786//!   `{` and `}` around the expanded tokens. If anyone knows how to improve this, please contact
787//!   us.
788//! - Error spans from the generated code are not mapped to your source code. It means that you
789//!   will still get nice, colored error messages, but the line/column numbers will be pointing to
790//!   the generated file, not to your source file. This is an area for improvement, and I'd be
791//!   happy to accept a PR that fixes this.
792//! - `Crabtime::eval!` does not use caching, as there is no name we can associate the cache with.
793//!
794//! <br/>
795//! <br/>
796//!
797//! # ⚠️ Troubleshooting
798//!
799//! ⚠️ **Note:** Rust IDEs differ in how they handle macro expansion. This macro is tuned for
800//! `rustc` and `RustRover`’s expansion engines.
801//!
802//! If your IDE struggles to correctly expand `crabtime::output!`, you can switch to the
803//! `crabtime::output_str!` syntax described above. If you encounter this, please
804//! [open an issue](https://github.com/wdanilo/eval-macro/issues) to let us know!
805//!
806//! [zigs_comptime]: https://zig.guide/language-basics/comptime
807//! [token_stream]: https://doc.rust-lang.org/proc_macro/struct.TokenStream.html
808//! [macro_fragments]: https://doc.rust-lang.org/reference/macros-by-example.html#metavariables
809//! [macro_rules]: https://doc.rust-lang.org/rust-by-example/macros.html
810//! [fn_like_macros]: https://doc.rust-lang.org/reference/procedural-macros.html#function-like-procedural-macros
811//! [derive_macros]: https://doc.rust-lang.org/reference/procedural-macros.html#derive-macros
812//! [attribute_macros]: https://doc.rust-lang.org/reference/procedural-macros.html#attribute-macros
813//! [proc_macro_span]: https://github.com/rust-lang/rust/issues/54725
814//! [rustfmt]: https://github.com/rust-lang/rustfmt
815//! [macro_hygiene]: https://doc.rust-lang.org/reference/macros-by-example.html#hygiene
816//!
817//! [^supported_ides]: This code was thoroughly tested in `rustc`, the IntelliJ/RustRover Rust expansion engine, and Rust Analyzer (VS Code, etc.).
818//!
819//! [inline_dependency_injection]: ...
820//! [space_aware_interpolation]: ...
821#![cfg_attr(not(feature = "std"), no_std)]
822
823extern crate self as crabtime;
824pub use crabtime_internal::*;
825
826// =====================
827// === Macro Helpers ===
828// =====================
829
830#[macro_export]
831macro_rules! eval {
832    ($($ts:tt)*) => {
833        {
834            #[crabtime::eval_function(cache=true, content_base_name=true)]
835            fn run() -> _ {
836                $($ts)*
837            }
838        }
839    };
840}
841
842// ==========================
843// === Type Hints Mockups ===
844// ==========================
845// The following items are defined to prevent IDE error messages. The real definition is placed
846// in the generated project per macro usage.
847
848/// AVAILABLE ONLY WITHIN THE CRABTIME MACRO.
849#[macro_export]
850macro_rules! output {
851    ($($ts:tt)*) => {};
852}
853
854/// AVAILABLE ONLY WITHIN THE CRABTIME MACRO.
855#[macro_export]
856macro_rules! quote {
857    ($($ts:tt)*) => { String::new() };
858}
859
860/// AVAILABLE ONLY WITHIN THE CRABTIME MACRO.
861#[macro_export]
862macro_rules! write_ln {
863    ($($ts:tt)*) => {};
864}
865
866/// AVAILABLE ONLY WITHIN THE CRABTIME MACRO.
867///
868/// Returns all ordered combinations of positive integers that sum to `n` (with at least two
869/// summands). For example `sum_combinations(4)` returns
870///
871/// ```text
872/// [1, 1, 1, 1]
873/// [1, 1, 2]
874/// [1, 2, 1]
875/// [2, 1, 1]
876/// [1, 3]
877/// [3, 1]
878/// [2, 2]
879/// ```
880#[cfg(feature = "std")]
881#[allow(clippy::panic)]
882pub fn sum_combinations(_n: usize) -> Vec<Vec<usize>> {
883    panic!("AVAILABLE ONLY WITHIN THE CRABTIME MACRO.")
884}
885
886pub const WORKSPACE_PATH: &str = "AVAILABLE ONLY WITHIN THE CRABTIME MACRO.";
887pub const CRATE_CONFIG_PATH: &str = "AVAILABLE ONLY WITHIN THE CRABTIME MACRO.";
888pub const CALL_SITE_FILE_PATH: &str = "AVAILABLE ONLY WITHIN THE CRABTIME MACRO.";
889
890// =============
891// === Tests ===
892// =============
893
894/// Most of the tests are included in the documentation above. These tests cover corner cases to
895/// ensure that the macro works as expected.
896#[cfg(all(test, feature = "std"))]
897mod tests {
898    #[test]
899    fn empty_def_compilation() {
900        #[crabtime::function]
901        fn empty_def_compilation() {}
902        empty_def_compilation!();
903    }
904
905    // ===
906
907    mod mod_a {
908        #[crabtime::function]
909        fn inter_module_macro() -> &str {
910            "pub struct Generated;"
911        }
912        #[allow(clippy::single_component_path_imports)]
913        pub(super) use inter_module_macro;
914    }
915
916    mod mod_b {
917        super::mod_a::inter_module_macro!();
918    }
919
920    #[test]
921    fn inter_module_macro() {
922        let _p = mod_b::Generated;
923    }
924
925    #[test] fn interpolation_before_brace() {
926        #[crabtime::function]
927        fn interpolation_before_brace() {
928            let is_a_branches = "A => true, B => false";
929            crabtime::output! {
930                enum E { A, B }
931                impl E {
932                    fn is_a(&self) -> bool {
933                        match self {
934                            {{is_a_branches}}
935                        }
936                    }
937                }
938            }
939        }
940        interpolation_before_brace!();
941    }
942
943    // ===
944
945    // https://github.com/wdanilo/crabtime/issues/25
946    mod test_impl_interpolation_compilation {
947        #[crabtime::function]
948        fn fn_in_impl() -> &str {
949            "pub fn test(&self) {}"
950        }
951        struct Test;
952        impl Test {
953            fn_in_impl!();
954        }
955    }
956}