attr_parser_fn/meta/
mod.rs1use std::fmt::Write;
2
3use impl_variadics::impl_variadics;
4use proc_macro2::{Span, TokenStream};
5use syn::{
6 meta::ParseNestedMeta,
7 parenthesized,
8 parse::{Parse, ParseStream, Parser},
9 token::Paren,
10 Error, LitStr, Result, Token,
11};
12
13use crate::ParseAttrTrait;
14
15pub use self::{
16 conflicts::{conflicts, ConflictGroup},
17 utils::{meta_list, Map, MetaList, Optional, ParseMetaExt},
18};
19
20mod conflicts;
21mod utils;
22
23pub trait ParseMeta {
24 type Output;
25
26 fn conflict_alternative_arm(&self, f: &mut dyn Write) -> std::fmt::Result;
27 fn parse(&mut self, nested: &ParseNestedMeta) -> Result<bool>;
28 fn finish(self) -> Result<Self::Output>;
29 fn ok_to_finish(&self) -> bool;
30}
31
32pub trait ParseMetaUnnamed {
33 type Output;
34
35 fn parse(&mut self, nested: &ParseNestedMeta) -> Result<bool>;
36 fn finish(self) -> Option<Self::Output>;
37 fn ok_to_finish(&self) -> bool;
38}
39
40impl<T> ParseMeta for (&str, T)
41where
42 T: ParseMetaUnnamed,
43{
44 type Output = T::Output;
45
46 fn conflict_alternative_arm(&self, f: &mut dyn Write) -> std::fmt::Result {
47 write!(f, "`{}`", self.0)
48 }
49
50 fn parse(&mut self, nested: &ParseNestedMeta) -> Result<bool> {
51 if nested.path.is_ident(self.0) {
52 self.1.parse(nested)
53 } else {
54 Ok(false)
55 }
56 }
57
58 fn finish(self) -> Result<Self::Output> {
59 self.1.finish().ok_or_else(|| {
60 Error::new(
61 Span::call_site(),
62 format!("attribute `{}` must be specified", self.0),
63 )
64 })
65 }
66
67 fn ok_to_finish(&self) -> bool {
68 self.1.ok_to_finish()
69 }
70}
71
72pub fn path_only() -> PathOnly {
73 PathOnly { assigned: false }
74}
75
76pub struct PathOnly {
77 assigned: bool,
78}
79
80impl ParseMetaUnnamed for PathOnly {
81 type Output = bool;
82
83 fn parse(&mut self, nested: &ParseNestedMeta) -> Result<bool> {
84 if nested.input.peek(Token![,]) || nested.input.is_empty() {
85 self.assigned = true;
86 Ok(true)
87 } else {
88 Ok(false)
89 }
90 }
91
92 fn finish(self) -> Option<Self::Output> {
93 Some(self.assigned)
94 }
95
96 fn ok_to_finish(&self) -> bool {
97 true
98 }
99}
100
101pub fn key_value<T>() -> KeyValue<T>
102where
103 T: Parse,
104{
105 KeyValue { value: None }
106}
107
108pub struct KeyValue<T> {
109 value: Option<T>,
110}
111
112impl<T> ParseMetaUnnamed for KeyValue<T>
113where
114 T: Parse,
115{
116 type Output = T;
117
118 fn parse(&mut self, nested: &ParseNestedMeta) -> Result<bool> {
119 if nested.input.peek(Token![=]) {
120 self.value = Some(nested.value()?.parse::<T>()?);
121 Ok(true)
122 } else {
123 Ok(false)
124 }
125 }
126
127 fn finish(self) -> Option<Self::Output> {
128 self.value
129 }
130
131 fn ok_to_finish(&self) -> bool {
132 self.value.is_some()
133 }
134}
135
136pub fn key_str<T>() -> KeyStr<T>
137where
138 T: Parse,
139{
140 KeyStr { value: None }
141}
142
143pub struct KeyStr<T> {
144 value: Option<T>,
145}
146
147impl<T> ParseMetaUnnamed for KeyStr<T>
148where
149 T: Parse,
150{
151 type Output = T;
152
153 fn parse(&mut self, nested: &ParseNestedMeta) -> Result<bool> {
154 if nested.input.peek(Token![=]) {
155 let litstr: LitStr = nested.value()?.parse()?;
156 self.value = Some(litstr.parse()?);
157 Ok(true)
158 } else {
159 Ok(false)
160 }
161 }
162
163 fn finish(self) -> Option<Self::Output> {
164 self.value
165 }
166
167 fn ok_to_finish(&self) -> bool {
168 self.value.is_some()
169 }
170}
171
172pub fn list<P>(parser: P) -> List<P>
173where
174 P: ParseAttrTrait,
175{
176 List(ListInner::Unassigned(parser))
177}
178
179enum ListInner<P>
180where
181 P: ParseAttrTrait,
182{
183 Unassigned(P),
184 Assigned(P::Output),
185 Intermediate,
186}
187
188pub struct List<P>(ListInner<P>)
189where
190 P: ParseAttrTrait;
191
192impl<P> ParseMetaUnnamed for List<P>
193where
194 P: ParseAttrTrait,
195{
196 type Output = P::Output;
197
198 fn parse(&mut self, nested: &ParseNestedMeta) -> Result<bool> {
199 if !nested.input.peek(Paren) {
200 return Ok(false);
201 }
202
203 let inner = &mut self.0;
204
205 let content;
206 parenthesized!(content in nested.input);
207
208 let ListInner::Unassigned(parser) = std::mem::replace(inner, ListInner::Intermediate)
209 else {
210 unreachable!("cannot assign a list twice");
211 };
212
213 *inner = ListInner::Assigned(parser.parse(&content)?);
214 Ok(true)
215 }
216
217 fn finish(self) -> Option<Self::Output> {
218 match self.0 {
219 ListInner::Assigned(output) => Some(output),
220 ListInner::Intermediate => unreachable!("this list is not correctly assigned"),
221 ListInner::Unassigned(parser) => {
222 let new_parser = |input: ParseStream| parser.parse(input);
223 new_parser.parse2(TokenStream::new()).ok()
224 }
225 }
226 }
227
228 fn ok_to_finish(&self) -> bool {
229 matches!(self.0, ListInner::Assigned(_))
230 }
231}
232
233impl_variadics! {
234 ..21 "T*" => {
235 impl<#(#T0,)*> ParseMeta for (#(#T0,)*)
236 where
237 #(#T0: ParseMeta,)*
238 {
239 type Output = (#(#T0::Output,)*);
240
241 fn conflict_alternative_arm(&self, _f: &mut dyn Write) -> std::fmt::Result {
242 let mut _comma = "";
243
244 #(
245 write!(_f, "{_comma}")?;
246 self.#index.conflict_alternative_arm(_f)?;
247 _comma = ", ";
248 )*
249
250 Ok(())
251 }
252
253 fn parse(&mut self, _nested: &ParseNestedMeta) -> Result<bool> {
254 Ok(false #(|| self.#index.parse(_nested)?)*)
255 }
256
257 fn finish(self) -> Result<Self::Output> {
258 Ok((
259 #(self.#index.finish()?,)*
260 ))
261 }
262
263 fn ok_to_finish(&self) -> bool {
264 true #(&& self.#index.ok_to_finish())*
265 }
266 }
267 }
268}