Skip to main content

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}