cargo_what/
lib.rs

1//! Tells you what type things are.
2//!
3//! This crate provides the `what!` macro. This is functionally similar to the
4//! [`todo!`] macro, except that it also tells you type information.
5//!
6//! ``` rust
7//! # use cargo_what::what;
8//! # use std::error::Error;
9//! fn hello() -> Result<(), Box<dyn Error>> {
10//!     what!()
11//! }
12//! ```
13//!
14//! Just like [`todo!`], `what!` passes all type-checks and makes it easy to
15//! write/build/test unfinished code. If it ever ends up in a compiled program,
16//! attempted to execute a `what!` will panic.
17//!
18//! The fun part happens when you run `cargo what`.
19//!
20//! ``` bash
21//! $ cargo what
22//! hole: expecting `std::result::Result<(), Box<dyn std::error::Error>>`
23//!  --> src/hello.rs
24//!   |
25//! 2 |     what!()
26//!   |     ^^^^^^^
27//! ```
28//!
29//! Unfortunately, custom diagnostics aren't really available to Rust libraries,
30//! requiring the extra command. `cargo what` can be installed with `cargo`:
31//!
32//! ``` bash
33//! $ cargo install cargo-what
34//! ```
35//!
36//! `cargo what` wraps `cargo build` to show the type-info of any `what!`s
37//! you have in your code.
38//!
39//! `what!` also accepts arguments and shows their types, which can be useful
40//! for reducing the "unused variable" noise.
41//!
42//! ``` rust
43//! # use cargo_what::what;
44//! fn hello(a: usize, b: usize) -> usize {
45//!     let c = a..b;
46//!     what!(a, b, c)
47//! }
48//! ```
49//!
50//! And with `cargo what`:
51//!
52//! ```bash
53//! $ cargo what
54//! hole: expecting `usize`
55//!  --> src/hello.rs
56//!   |
57//! 3 |     what!(a, b, c)
58//!   |     ^^^^^^^^^^^^^^
59//!   |
60//!   = note: a is `usize`
61//!   = note: b is `usize`
62//!   = note: c is `std::ops::Range<usize>`
63//! ```
64//!
65//! Emacs keybindings left as an exercise to the reader.
66//!
67//! [`todo!`]: https://doc.rust-lang.org/std/macro.todo.html
68//!
69
70// we need this for token pasting
71#[doc(hidden)]
72pub use paste as __paste;
73
74
75/// This is the core `what!` macro.
76///
77/// It behaves similarly to [`todo!`], passes all type-checks,
78/// and panics if executed.
79///
80/// ```rust
81/// # use cargo_what::what;
82/// # use std::error::Error;
83/// fn hello() -> Result<(), Box<dyn Error>> {
84///     what!()
85/// }
86/// ```
87///
88/// One difference from [`todo!`] is that `what!` also accepts
89/// arbitrary arguments, which can help reduce "unused variable"
90/// noise.
91///
92/// ``` rust
93/// # use cargo_what::what;
94/// fn hello(a: usize, b: usize) -> usize {
95///     let c = a..b;
96///     what!(a, b, c)
97/// }
98/// ```
99///
100/// See the [crate-level documentation](/cargo_what) for more info
101/// on how you can show the type-info of `what!`s in a program.
102///
103/// [`todo!`]: https://doc.rust-lang.org/std/macro.todo.html
104///
105
106// cargo build => todo
107#[cfg(not(cargo_what_query))]
108#[macro_export]
109macro_rules! what {
110    ($($args:expr),* $(,)*) => {
111        ({
112            $(
113                let _ = $args;
114            )*
115            todo!()
116        })
117    };
118}
119
120// cargo what => query type info
121#[cfg(cargo_what_query)]
122#[macro_export]
123macro_rules! what {
124    (@[$($n:expr)*] $(,)*) => {};
125    (@[$($n:expr)*] $arg:ident, $($args:tt)*) => {
126        // we can use ident directly as a special case
127        $crate::__paste::paste! {
128            trait [<What_ $arg>] {};
129            let _: &dyn [<What_ $arg>] = &$arg;
130        }
131        what!(@[$($n)* 0] $($args)*);
132    };
133    (@[$($n:expr)*] $arg:expr, $($args:tt)*) => {
134        $crate::__paste::paste! {
135            trait [<What_ $($n)*>] {};
136            // yes you need these parens (tt munching?)
137            let _: &dyn [<What_ $($n)*>] = &($arg);
138        }
139        what!(@[$($n)* 0] $($args)*);
140    };
141    // actual macro
142    ($($args:tt)*) => {
143        ({
144            todo!();
145
146            #[allow(unreachable_code)]
147            {
148                what!(@[0] $($args)*,);
149
150                trait What {};
151                match true {
152                    true => {
153                        let what;
154                        let _: &dyn What = &what;
155                        what
156                    }
157                    false => {
158                        struct WhatTrait {};
159                        impl What for WhatTrait {};
160                        WhatTrait{}
161                    }
162                }
163            }
164        })
165    };
166}