as_derive_utils/
parse_utils.rs
1use crate::utils::SynErrorExt;
2
3use syn::parse::{Parse, ParseBuffer, Peek};
4
5#[doc(hidden)]
6#[macro_export]
7macro_rules! ret_err_on_peek {
8 ($input:ident, $peeked:expr, $expected:expr, $found_msg:expr $(,)*) => {
9 if $input.peek($peeked) {
10 return Err($input.error(concat!("expected ", $expected, ", found ", $found_msg)));
11 }
12 };
13}
14
15#[doc(hidden)]
16#[macro_export]
17macro_rules! ret_err_on {
18 ($cond:expr, $span:expr, $expected:expr, $found_msg:expr $(,)*) => {
19 if $cond {
20 return Err(syn::Error::new(
21 $span,
22 concat!("expected ", $expected, ", found ", $found_msg),
23 ));
24 }
25 };
26}
27
28pub use crate::{ret_err_on, ret_err_on_peek};
29
30fn parse_with_prefix_err<T>(input: &ParseBuffer<'_>, prefix: &str) -> Result<T, syn::Error>
31where
32 T: Parse,
33{
34 input
35 .parse::<T>()
36 .map_err(|e| e.prepend_msg(format!("{}: ", prefix)))
37}
38
39pub trait ParseBufferExt {
40 fn as_pb(&self) -> &ParseBuffer<'_>;
41
42 fn peek_parse<F, X, P>(&self, f: F) -> Result<Option<P>, syn::Error>
43 where
44 F: FnOnce(X) -> P + Peek,
45 P: Parse,
46 {
47 let this = self.as_pb();
48 if this.peek(f) {
49 this.parse::<P>().map(Some)
50 } else {
51 Ok(None)
52 }
53 }
54
55 fn parse_type(&self) -> Result<syn::Type, syn::Error> {
57 let input = self.as_pb();
58
59 if input.peek(syn::Lit) {
60 Err(input.error("expected type, found literal"))
61 } else {
62 parse_with_prefix_err(input, "while parsing type")
63 }
64 }
65
66 fn parse_expr(&self) -> Result<syn::Expr, syn::Error> {
68 parse_with_prefix_err(self.as_pb(), "while parsing expression")
69 }
70
71 fn skip_tt(&self) {
73 let _ = self.as_pb().parse::<proc_macro2::TokenTree>();
74 }
75
76 fn ignore_rest(&self) {
78 let _ = self.as_pb().parse::<proc_macro2::TokenStream>();
79 }
80
81 fn check_parse<F, X, P>(&self, f: F) -> Result<bool, syn::Error>
88 where
89 F: FnOnce(X) -> P + Peek,
90 P: Parse,
91 {
92 let this = self.as_pb();
93 if this.peek(f) {
94 match this.parse::<P>() {
95 Ok(_) => Ok(true),
96 Err(e) => Err(e),
97 }
98 } else {
99 Ok(false)
100 }
101 }
102
103 fn parse_paren_buffer(&self) -> Result<ParseBuffer, syn::Error> {
104 let content;
105 let _ = syn::parenthesized!(content in self.as_pb());
106 Ok(content)
107 }
108
109 fn parse_paren_as<T>(&self) -> Result<T, syn::Error>
110 where
111 T: Parse,
112 {
113 self.as_pb().parse_paren_with(|x| x.parse::<T>())
114 }
115
116 fn parse_paren_with<T, F>(&self, f: F) -> Result<T, syn::Error>
117 where
118 F: FnOnce(&ParseBuffer<'_>) -> Result<T, syn::Error>,
119 {
120 let content;
121 let _ = syn::parenthesized!(content in self.as_pb());
122 f(&content)
123 }
124
125 fn parse_int<N>(&self) -> Result<N, syn::Error>
126 where
127 N: std::str::FromStr,
128 N::Err: std::fmt::Display,
129 {
130 self.as_pb().parse::<syn::LitInt>()?.base10_parse::<N>()
131 }
132
133 fn for_each_separated<F, G, P>(&self, _sep: G, mut func: F) -> Result<(), syn::Error>
134 where
135 F: FnMut(&ParseBuffer<'_>) -> Result<(), syn::Error>,
136 G: Fn(proc_macro2::Span) -> P + Copy,
137 P: Parse,
138 {
139 let this = self.as_pb();
140
141 if this.is_empty() {
142 return Ok(());
143 }
144
145 loop {
146 func(this)?;
147
148 if !this.is_empty() {
149 let _ = this.parse::<P>()?;
150 }
151 if this.is_empty() {
152 break Ok(());
153 }
154 }
155 }
156}
157
158impl ParseBufferExt for ParseBuffer<'_> {
159 #[inline(always)]
160 fn as_pb(&self) -> &ParseBuffer<'_> {
161 self
162 }
163}