parse_more/lib.rs
1//! # parse-more
2//! Parse-more is an extension of the [syn::parse::Parse] trait from the [syn](https://docs.rs/syn/) crate, allowing to parse input from procedural macros directly, without having to create a custom structure and implementing the [syn::parse::Parse] trait on it.
3//!
4//! It provides classic [syn](https://docs.rs/syn/) macros and functions variant, using the [ParseMore] trait instead.
5//!
6//! # Example
7//!
8//! ```
9//! # extern crate proc_macro;
10//! use quote::quote;
11//! use parse_more::{parse_more_macro_input, Concat, Braced};
12//! use proc_macro::TokenStream;
13//! use syn::{Expr, Ident, Token, punctuated::Punctuated};
14//!
15//! # const IGNORE_TOKENS: &str = stringify! {
16//! #[proc_macro]
17//! # };
18//! pub fn complex_args(input: TokenStream) -> TokenStream {
19//! let content = parse_more_macro_input!(
20//! input as Punctuated<Concat<Ident, Token![=>], Braced<(Ident, Expr)>>, Token![,]>
21//! );
22//! content
23//! .into_iter()
24//! .map(|concat| {
25//! // Second item is discarded (it's the => arrow)
26//! let (ident, _, Braced((other_ident, literal))) = concat.into();
27//! quote! {
28//! println!("{}: {} versus other type {}", #literal, (-1i8) as #ident, (-1i8) as #other_ident);
29//! }
30//! })
31//! .collect::<proc_macro2::TokenStream>()
32//! .into()
33//! }
34//! ```
35//! And then :
36//! ```
37//! # macro_rules! complex_args { ($($tt:tt)*) => {} }
38//! complex_args! {
39//! u8 => {
40//! (i8, "u8 integer")
41//! },
42//! u16 => {
43//! (i16, "u16 integer")
44//! },
45//! Foo => {
46//! (Bar, 8 + 42)
47//! }
48//! }
49//! ```
50
51extern crate proc_macro;
52
53pub mod syn_types;
54
55/// Re-export `crate` as `parse_more` to use the `parse_more` macro easily.
56pub use crate as parse_more;
57
58/// Re-export proc macro.
59pub use parse_more_macros::{filler, parse_more};
60
61use syn::{
62 braced, bracketed, parenthesized,
63 parse::{Nothing, Parse},
64 punctuated::Punctuated,
65 LitInt, LitStr,
66};
67
68/// Parsing interface implemented by all types from the [syn] crate which already implement [syn::parse::Parse], and some others usefull ones.
69/// Use the [parse_more_auto_impl] macros to easily implement [ParseMore] on a type which already implement [syn::parse::Parse].
70pub trait ParseMore: Sized {
71 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self>;
72}
73
74/// This wrapper implements [syn::parse::Parse] when T implements [ParseMore]. It permits to use this wrapper and a type implementing [ParseMore] in a parsing function from [syn].
75///
76/// You should probably use [parse_more()], [parse_more_macro_input], or any other function from this crate instead of using this type directly.
77///
78/// # Example
79///
80/// ```
81/// # extern crate proc_macro;
82/// use quote::quote;
83/// use parse_more::ParseMoreWrapper;
84/// use proc_macro::TokenStream;
85/// use syn::{Ident, Token};
86///
87/// # const IGNORE_TOKENS: &str = stringify! {
88/// #[proc_macro]
89/// # };
90/// pub fn flip_identifiers(input: TokenStream) -> TokenStream {
91/// let (ident_a, arrow, ident_b) = syn::parse::<ParseMoreWrapper<(Ident, Token![=>], Ident)>>(input).unwrap().0;
92/// quote! {
93/// #ident_b <= #ident_a
94/// }.into()
95/// }
96/// ```
97pub struct ParseMoreWrapper<T>(pub T);
98
99/// Call the [ParseMore::parse] method.
100impl<T: ParseMore> Parse for ParseMoreWrapper<T> {
101 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
102 Ok(ParseMoreWrapper(ParseMore::parse(input)?))
103 }
104}
105
106/// This macro auto-implements the [ParseMore] traits on its arguments, which *MUST* implement the [syn::parse::Parse] trait.
107/// It allows using custom types inside of any parse-more macros/functions.
108///
109/// See the [macro@parse_more] macro.
110///
111/// # Example
112///
113/// ```
114/// use parse_more::parse_more_auto_impl;
115/// use syn::{Ident, Token};
116///
117/// struct MyParsedStruct(Ident, Ident);
118///
119/// impl syn::parse::Parse for MyParsedStruct {
120/// fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
121/// let a = input.parse()?;
122/// input.parse::<Token![=>]>()?;
123/// let b = input.parse()?;
124/// Ok(Self(a, b))
125/// }
126/// }
127///
128/// parse_more_auto_impl! {
129/// MyParsedStruct
130/// }
131/// ```
132#[macro_export]
133macro_rules! parse_more_auto_impl {
134 ($($ty:ty),*) => {
135 $(impl $crate::ParseMore for $ty {
136 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
137 <Self as syn::parse::Parse>::parse(input)
138 }
139 })*
140 }
141}
142
143/// Implement [ParseMore] for a given tuple.
144macro_rules! tuple_impls {
145 ($first:ident) => {
146 impl<$first:ParseMore> ParseMore for ($first, ) {
147 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
148 let content;
149 parenthesized!(content in input);
150 let first = content.parse::<ParseMoreWrapper<$first>>()?.0;
151 content.parse::<syn::Token![,]>()?;
152 Ok((first,))
153 }
154 }
155 };
156 ($first:ident $($generics:ident)*) => {
157 impl<$first:ParseMore, $($generics: ParseMore),*> ParseMore for ($first, $($generics,)*) {
158 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
159 let content;
160 parenthesized!(content in input);
161 let first = content.parse::<ParseMoreWrapper<$first>>()?.0;
162 let res = Ok((first,
163 $({
164 content.parse::<syn::Token![,]>()?;
165 content.parse::<ParseMoreWrapper<$generics>>()?.0
166 },)*
167 ));
168
169 // If there is a remaining comma, parse it
170 if content.peek(syn::Token![,]) {
171 content.parse::<syn::Token![,]>().unwrap();
172 }
173 res
174 }
175 }
176 };
177}
178
179/// Inner code of the [for_each_tuple] macro.
180macro_rules! for_each_tuple_ {
181 ($mac:ident =>) => {};
182 ($mac:ident => $first:ident, $($generics:ident,)*) => {
183 $mac! {
184 $first $($generics)*
185 }
186 for_each_tuple_ ! {
187 $mac => $($generics,)*
188 }
189 };
190}
191
192/// Call a macro over every tuple size between 1 and 20.
193macro_rules! for_each_tuple {
194 ($mac:ident) => {
195 for_each_tuple_! {
196 $mac => A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T,
197 }
198 };
199}
200
201// Generate [ParseMore] impls for tuples.
202for_each_tuple! {
203 tuple_impls
204}
205
206/// Implement [ParseMore] for the array type.
207/// ```
208/// # extern crate proc_macro;
209/// use quote::quote;
210/// use parse_more::parse_more_macro_input;
211/// use proc_macro::TokenStream;
212/// use syn::{Ident, Token};
213///
214/// # const IGNORE_TOKENS: &str = stringify! {
215/// #[proc_macro]
216/// # };
217/// pub fn identifiers_sum(input: TokenStream) -> TokenStream {
218/// let idents = parse_more_macro_input!(input as [Ident; 3]);
219/// let [a, b, c] = idents;
220/// quote! {
221/// #a + #b + #c
222/// }.into()
223/// }
224/// ```
225impl<T: ParseMore, const N: usize> ParseMore for [T; N] {
226 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
227 let content;
228 bracketed!(content in input);
229
230 let mut res = vec![];
231 for i in 0..N {
232 if i != 0 {
233 content.parse::<syn::Token![,]>()?;
234 }
235 res.push(content.parse::<ParseMoreWrapper<T>>()?.0)
236 }
237
238 // If there is a remaining comma, parse it
239 if content.peek(syn::Token![,]) {
240 content.parse::<syn::Token![,]>().unwrap();
241 }
242 Ok(unsafe { res.try_into().unwrap_unchecked() })
243 }
244}
245
246/// Implement [ParseMore] for the [Vec] type, with a behaviour similar to [syn::punctuated::Punctuated<T, syn::parse::Nothing>]
247/// ```
248/// # extern crate proc_macro;
249/// use quote::quote;
250/// use parse_more::parse_more_macro_input;
251/// use proc_macro::TokenStream;
252/// use syn::Ident;
253///
254/// # const IGNORE_TOKENS: &str = stringify! {
255/// #[proc_macro]
256/// # };
257/// pub fn identifiers_sum(input: TokenStream) -> TokenStream {
258/// let idents = parse_more_macro_input!(input as Vec<Ident>);
259/// idents.into_iter().map(|ident| quote! {
260/// #ident
261/// }).collect::<proc_macro2::TokenStream>().into()
262/// }
263/// ```
264impl<T: ParseMore> ParseMore for Vec<T> {
265 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
266 let mut res = vec![];
267 while let Ok(parsed) = input.parse::<ParseMoreWrapper<T>>() {
268 res.push(parsed.0);
269 }
270 Ok(res)
271 }
272}
273
274/// Implement [ParseMore] for the [syn::punctuated::Punctuated] type.
275/// ```
276/// # extern crate proc_macro;
277/// use quote::quote;
278/// use parse_more::parse_more_macro_input;
279/// use proc_macro::TokenStream;
280/// use syn::{Ident, Token, punctuated::Punctuated};
281///
282/// # const IGNORE_TOKENS: &str = stringify! {
283/// #[proc_macro]
284/// # };
285/// pub fn identifiers_sum(input: TokenStream) -> TokenStream {
286/// let idents = parse_more_macro_input!(input as Punctuated<Ident, Token![,]>);
287/// idents.into_iter().map(|ident| quote! {
288/// #ident
289/// }).collect::<proc_macro2::TokenStream>().into()
290/// }
291/// ```
292impl<T: ParseMore, P: ParseMore> ParseMore for Punctuated<T, P> {
293 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
294 let mut res = Punctuated::new();
295 let wrapped =
296 Punctuated::<ParseMoreWrapper<T>, ParseMoreWrapper<P>>::parse_terminated(input)?;
297
298 // Unwrap parsed values
299 wrapped.into_pairs().for_each(|pair| {
300 let pair = pair.into_tuple();
301 res.push_value(pair.0 .0);
302 if let Some(punct) = pair.1 {
303 res.push_punct(punct.0);
304 }
305 });
306
307 Ok(res)
308 }
309}
310
311/// Parse successive items.
312#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
313#[parse_more]
314pub struct Concat<A, B, C = Nothing, D = Nothing, E = Nothing, F = Nothing, G = Nothing> {
315 first: A,
316 second: B,
317 third: C,
318 fourth: D,
319 fifth: E,
320 sixth: F,
321 seventh: G,
322}
323
324impl<A, B, C, D, E, F, G> From<Concat<A, B, C, D, E, F, G>> for (A, B, C, D, E, F, G) {
325 fn from(value: Concat<A, B, C, D, E, F, G>) -> Self {
326 (
327 value.first,
328 value.second,
329 value.third,
330 value.fourth,
331 value.fifth,
332 value.sixth,
333 value.seventh,
334 )
335 }
336}
337impl<A, B, C, D, E, F> From<Concat<A, B, C, D, E, F>> for (A, B, C, D, E, F) {
338 fn from(value: Concat<A, B, C, D, E, F>) -> Self {
339 (
340 value.first,
341 value.second,
342 value.third,
343 value.fourth,
344 value.fifth,
345 value.sixth,
346 )
347 }
348}
349impl<A, B, C, D, E> From<Concat<A, B, C, D, E>> for (A, B, C, D, E) {
350 fn from(value: Concat<A, B, C, D, E>) -> Self {
351 (
352 value.first,
353 value.second,
354 value.third,
355 value.fourth,
356 value.fifth,
357 )
358 }
359}
360impl<A, B, C, D> From<Concat<A, B, C, D>> for (A, B, C, D) {
361 fn from(value: Concat<A, B, C, D>) -> Self {
362 (value.first, value.second, value.third, value.fourth)
363 }
364}
365impl<A, B, C> From<Concat<A, B, C>> for (A, B, C) {
366 fn from(value: Concat<A, B, C>) -> Self {
367 (value.first, value.second, value.third)
368 }
369}
370impl<A, B> From<Concat<A, B>> for (A, B) {
371 fn from(value: Concat<A, B>) -> Self {
372 (value.first, value.second)
373 }
374}
375impl<A, B> Concat<A, B> {
376 /// Convert itself to a tuple containing the parsed values.
377 pub fn into_tuple2(self) -> (A, B) {
378 self.into()
379 }
380}
381impl<A, B, C> Concat<A, B, C> {
382 /// Convert itself to a tuple containing the parsed values.
383 pub fn into_tuple3(self) -> (A, B, C) {
384 self.into()
385 }
386}
387impl<A, B, C, D> Concat<A, B, C, D> {
388 /// Convert itself to a tuple containing the parsed values.
389 pub fn into_tuple4(self) -> (A, B, C, D) {
390 self.into()
391 }
392}
393impl<A, B, C, D, E> Concat<A, B, C, D, E> {
394 /// Convert itself to a tuple containing the parsed values.
395 pub fn into_tuple5(self) -> (A, B, C, D, E) {
396 self.into()
397 }
398}
399impl<A, B, C, D, E, F> Concat<A, B, C, D, E, F> {
400 /// Convert itself to a tuple containing the parsed values.
401 pub fn into_tuple6(self) -> (A, B, C, D, E, F) {
402 self.into()
403 }
404}
405impl<A, B, C, D, E, F, G> Concat<A, B, C, D, E, F, G> {
406 /// Convert itself to a tuple containing the parsed values.
407 pub fn into_tuple7(self) -> (A, B, C, D, E, F, G) {
408 self.into()
409 }
410}
411
412/// Parse an item surrounded by braces.
413#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
414pub struct Braced<T>(pub T);
415
416/// Imlement [ParseMore] for the [Braced] type.
417impl<T: ParseMore> ParseMore for Braced<T> {
418 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
419 let content;
420 braced!(content in input);
421 Ok(Self(content.parse::<ParseMoreWrapper<T>>()?.0))
422 }
423}
424
425impl<T> Braced<T> {
426 /// Get the parsed value.
427 pub fn value(self) -> T {
428 self.0
429 }
430}
431
432/// Parse an item surrounded by parenthesis.
433#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
434pub struct Parenthesized<T>(pub T);
435
436/// Imlement [ParseMore] for the [Parenthesized] type.
437impl<T: ParseMore> ParseMore for Parenthesized<T> {
438 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
439 let content;
440 parenthesized!(content in input);
441 Ok(Self(content.parse::<ParseMoreWrapper<T>>()?.0))
442 }
443}
444
445impl<T> Parenthesized<T> {
446 /// Get the parsed value.
447 pub fn value(self) -> T {
448 self.0
449 }
450}
451
452/// Parse an item surrounded by brackets.
453#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
454pub struct Bracketed<T>(pub T);
455
456/// Imlement [ParseMore] for the [Bracketed] type.
457impl<T: ParseMore> ParseMore for Bracketed<T> {
458 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
459 let content;
460 bracketed!(content in input);
461 Ok(Self(content.parse::<ParseMoreWrapper<T>>()?.0))
462 }
463}
464
465impl<T> Bracketed<T> {
466 /// Get the parsed value.
467 pub fn value(self) -> T {
468 self.0
469 }
470}
471
472/// Imlement [ParseMore] for the [Option] type.
473impl<T: ParseMore> ParseMore for Option<T> {
474 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
475 // Fork the input to be sure to don't advance the cursor if the parsing fails.
476 let input_forked = input.fork();
477 if let Ok(parsed) = input_forked.parse::<ParseMoreWrapper<T>>() {
478 // Parse it on the primary stream too to advance the cursor
479 // It should not fails.
480 assert!(input.parse::<ParseMoreWrapper<T>>().is_ok());
481 Ok(Some(parsed.0))
482 } else {
483 Ok(None)
484 }
485 }
486}
487
488/// Parse an item surrounded by brackets.
489#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
490pub struct Invalid;
491
492/// Imlement [ParseMore] for the [Invalid] type.
493impl ParseMore for Invalid {
494 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
495 Err(syn::Error::new(input.span(), "Invalid can never be parsed"))
496 }
497}
498
499/// Parse an item in a given list. If multiple types can be parsed, the first one is chosen.
500#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
501#[parse_more]
502pub enum Either<A, B, C = Invalid, D = Invalid, E = Invalid, F = Invalid, G = Invalid> {
503 First(A),
504 Second(B),
505 Third(C),
506 Fourth(D),
507 Fifth(E),
508 Sixth(F),
509 Seventh(G),
510}
511
512impl<A, B, C, D, E, F, G> Either<A, B, C, D, E, F, G> {
513 /// Check if the type of the parsed value is the first one.
514 pub fn is_first(&self) -> bool {
515 matches!(self, Either::First(_))
516 }
517 /// Check if the type of the parsed value is the second one.
518 pub fn is_second(&self) -> bool {
519 matches!(self, Either::Second(_))
520 }
521 /// Check if the type of the parsed value is the third one.
522 pub fn is_third(&self) -> bool {
523 matches!(self, Either::Third(_))
524 }
525 /// Check if the type of the parsed value is the fourth one.
526 pub fn is_fourth(&self) -> bool {
527 matches!(self, Either::Fourth(_))
528 }
529 /// Check if the type of the parsed value is the fifth one.
530 pub fn is_fifth(&self) -> bool {
531 matches!(self, Either::Fifth(_))
532 }
533 /// Check if the type of the parsed value is the sixth one.
534 pub fn is_sixth(&self) -> bool {
535 matches!(self, Either::Sixth(_))
536 }
537 /// Check if the type of the parsed value is the seveth one.
538 pub fn is_seventh(&self) -> bool {
539 matches!(self, Either::Seventh(_))
540 }
541}
542
543macro_rules! integer_impls {
544 ($($ty:ty),*) => {
545 $(
546 /// Imlement [ParseMore] for the [u8] type.
547 impl ParseMore for $ty {
548 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
549 input.parse::<LitInt>()?.base10_parse::<Self>()
550 }
551 }
552 )*
553 };
554}
555
556integer_impls! {
557 u8, u16, u32, u64, u128, usize,
558 i8, i16, i32, i64, i128, isize
559}
560
561/// Imlement [ParseMore] for the [String] type.
562impl ParseMore for String {
563 fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
564 Ok(input.parse::<LitStr>()?.value())
565 }
566}
567
568/// Same as the [syn::parse_quote] macro, but using the [ParseMore] trait.
569#[macro_export]
570macro_rules! parse_more_quote {
571 ($($tt:tt)*) => {{
572 // Add an type hint for the compiler
573 let __tmp: $crate::ParseMoreWrapper<_> = syn::parse_quote!($($tt:tt)*);
574 __tmp.0
575 }};
576}
577
578/// Same as the [syn::parse_macro_input] macro, but using the [ParseMore] trait.
579#[macro_export]
580macro_rules! parse_more_macro_input {
581 ($tokenstream:ident as $ty:ty) => {
582 match $crate::parse_more::<$ty>($tokenstream) {
583 Ok(data) => data,
584 Err(err) => {
585 return proc_macro::TokenStream::from(err.to_compile_error());
586 }
587 }
588 };
589 ($tokenstream:ident) => {
590 $crate::parse_more_macro_input!($tokenstream as _)
591 };
592}
593
594/// Same as the [syn::parse()] function, but using the [ParseMore] trait.
595pub fn parse_more<T: ParseMore>(tokens: proc_macro::TokenStream) -> syn::Result<T> {
596 Ok(syn::parse::<ParseMoreWrapper<T>>(tokens)?.0)
597}
598
599/// Same as the [syn::parse2] function, but using the [ParseMore] trait.
600pub fn parse2_more<T: ParseMore>(tokens: proc_macro2::TokenStream) -> syn::Result<T> {
601 Ok(syn::parse2::<ParseMoreWrapper<T>>(tokens)?.0)
602}
603
604/// Same as the [syn::parse_str] function, but using the [ParseMore] trait.
605pub fn parse_more_str<T: ParseMore>(s: &str) -> syn::Result<T> {
606 Ok(syn::parse_str::<ParseMoreWrapper<T>>(s)?.0)
607}