count_tts_inner/lib.rs
1#![doc = include_str!("../README.md")]
2
3use proc_macro::{Span, TokenStream};
4use proc_macro_tool::{pfunc, SetSpan, TokenTreeExt, Unsuffixed};
5
6fn count_tts_impl(stream: TokenStream, span: Span) -> TokenStream {
7 stream.into_iter()
8 .count()
9 .unsuffixed()
10 .set_spaned(span)
11 .tt()
12 .into()
13}
14
15/// Expands to the number of token trees in the macro arguments
16///
17/// # Examples
18///
19/// ```
20/// use count_tts_inner::count_tts;
21///
22/// assert_eq!(count_tts!(), 0);
23/// assert_eq!(count_tts!(a b c), 3);
24/// assert_eq!(count_tts!(a (b c)), 2);
25/// assert_eq!(count_tts!(a, b, c), 5);
26/// ```
27#[proc_macro]
28pub fn count_tts(stream: TokenStream) -> TokenStream {
29 count_tts_impl(stream, Span::call_site())
30}
31
32/// Expands to the number of token trees in the inner like macro arguments
33///
34/// Can be used in places where macro expansion is not possible
35///
36/// # Examples
37///
38/// ```
39/// use count_tts_inner::count_tts_inner;
40///
41/// macro_rules! foo {
42/// ($t:literal) => { $t };
43/// }
44///
45/// count_tts_inner! {
46/// assert_eq!(0, foo!(#count_tts()));
47/// assert_eq!(3, foo!(#count_tts(a b c)));
48/// assert_eq!(2, foo!(#count_tts(a (b c))));
49/// assert_eq!(5, foo!(#count_tts(a, b, c)));
50/// }
51/// ```
52///
53/// # Fail Cases
54///
55/// ```compile_fail
56/// use count_tts_inner::count_tts;
57///
58/// macro_rules! foo {
59/// ($t:literal) => { $t };
60/// }
61///
62/// // Expected literal, `count_tts` `!` `()` is not a literal
63/// assert_eq!(0, foo!(count_tts!()));
64/// assert_eq!(3, foo!(count_tts!(a b c)));
65/// assert_eq!(2, foo!(count_tts!(a (b c))));
66/// assert_eq!(5, foo!(count_tts!(a, b, c)));
67/// ```
68#[proc_macro]
69pub fn count_tts_inner(stream: TokenStream) -> TokenStream {
70 pfunc(stream, false, ["count_tts"], |_, param| {
71 count_tts_impl(param.stream(), param.span())
72 })
73}