synthez_core/parse/
ext.rs1use std::{any::TypeId, iter};
6
7use proc_macro2::Span;
8use sealed::sealed;
9use syn::{
10 parse::Parse,
11 punctuated::Punctuated,
12 token::{self, Token},
13};
14
15#[sealed]
18pub trait ParseBuffer {
19 fn try_parse<T: Default + Parse + Token>(&self) -> syn::Result<Option<T>>;
27
28 #[must_use]
32 fn is_next<T: Default + Token>(&self) -> bool;
33
34 fn parse_any_ident(&self) -> syn::Result<syn::Ident>;
46
47 fn skip_any_ident(&self) -> syn::Result<()> {
59 self.parse_any_ident().map(drop)
60 }
61
62 fn parse_wrapped_and_punctuated<T, W, P>(
71 &self,
72 ) -> syn::Result<Punctuated<T, P>>
73 where
74 T: Parse,
75 W: Default + Token + AcceptedWrapper + 'static,
76 P: Default + Parse + Token;
77
78 fn parse_maybe_wrapped_and_punctuated<T, W, P>(
89 &self,
90 ) -> syn::Result<Punctuated<T, P>>
91 where
92 T: Parse,
93 W: Default + Token + AcceptedWrapper + 'static,
94 P: Default + Parse + Token;
95
96 fn parse_eq_or_wrapped_and_punctuated<T, W, P>(
109 &self,
110 ) -> syn::Result<Punctuated<T, P>>
111 where
112 T: Parse,
113 W: Default + Token + AcceptedWrapper + 'static,
114 P: Default + Parse + Token;
115}
116
117#[sealed]
118impl<'buf> ParseBuffer for syn::parse::ParseBuffer<'buf> {
119 fn try_parse<T: Default + Parse + Token>(&self) -> syn::Result<Option<T>> {
120 self.is_next::<T>().then(|| self.parse()).transpose()
121 }
122
123 fn is_next<T: Default + Token>(&self) -> bool {
124 self.lookahead1().peek(|_| T::default())
125 }
126
127 fn parse_any_ident(&self) -> syn::Result<syn::Ident> {
128 <syn::Ident as syn::ext::IdentExt>::parse_any(self)
129 }
130
131 fn parse_wrapped_and_punctuated<T, W, P>(
132 &self,
133 ) -> syn::Result<Punctuated<T, P>>
134 where
135 T: Parse,
136 W: Default + Token + AcceptedWrapper + 'static,
137 P: Default + Parse + Token,
138 {
139 let inner;
140 if TypeId::of::<W>() == TypeId::of::<token::Bracket>() {
141 _ = syn::bracketed!(inner in self);
142 } else if TypeId::of::<W>() == TypeId::of::<token::Brace>() {
143 _ = syn::braced!(inner in self);
144 } else if TypeId::of::<W>() == TypeId::of::<token::Paren>() {
145 _ = syn::parenthesized!(inner in self);
146 } else {
147 return Err(syn::Error::new(
148 Span::call_site(),
149 "`ParseBufferExt::parse_wrapped_and_punctuated` supports only \
150 brackets, braces and parentheses as wrappers.",
151 ));
152 }
153 Punctuated::parse_terminated(&inner)
154 }
155
156 fn parse_maybe_wrapped_and_punctuated<T, W, P>(
157 &self,
158 ) -> syn::Result<Punctuated<T, P>>
159 where
160 T: Parse,
161 W: Default + Token + AcceptedWrapper + 'static,
162 P: Default + Parse + Token,
163 {
164 Ok(if self.is_next::<W>() {
165 self.parse_wrapped_and_punctuated::<T, W, P>()?
166 } else {
167 iter::once(self.parse::<T>()?).collect()
168 })
169 }
170
171 fn parse_eq_or_wrapped_and_punctuated<T, W, P>(
172 &self,
173 ) -> syn::Result<Punctuated<T, P>>
174 where
175 T: Parse,
176 W: Default + Token + AcceptedWrapper + 'static,
177 P: Default + Parse + Token,
178 {
179 Ok(if self.is_next::<W>() {
180 self.parse_wrapped_and_punctuated::<T, W, P>()?
181 } else {
182 _ = self.parse::<token::Eq>()?;
183 iter::once(self.parse::<T>()?).collect()
184 })
185 }
186}
187
188#[sealed]
193pub trait AcceptedWrapper {}
194
195#[sealed]
196impl AcceptedWrapper for token::Bracket {}
197
198#[sealed]
199impl AcceptedWrapper for token::Brace {}
200
201#[sealed]
202impl AcceptedWrapper for token::Paren {}