deno_bindgen2_common/rust/
attr.rs1use crate::rust::util::*;
2use crate::rust::Item;
3
4#[derive(Clone, Debug, PartialEq)]
14pub enum Marker {
15 DenoBindgen, NonBlocking, }
22
23#[cfg(feature = "macro")]
28impl Marker {
29 pub fn deno_bindgen(input: proc_macro2::TokenStream) -> proc_macro2::TokenStream {
30 let input = TokenStream::from(input);
31 let mut item: Item = match syn::parse2(input.clone()) {
32 Ok(item) => item,
33 Err(err) => return err.to_compile_error().into(),
34 };
35 item.transform();
36 quote! {
37 #[cfg_attr(not(deno_bindgen), doc = "deno_bindgen")]
38 #input
39 #item
40 }
41 .into()
42 }
43
44 pub fn non_blocking(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
45 let input = TokenStream::from(input);
46 quote! {
47 #[cfg_attr(not(deno_bindgen), doc = "deno_bindgen_non_blocking")]
48 #input
49 }
50 .into()
51 }
52}
53
54#[derive(Clone, Debug, PartialEq)]
60pub struct Meta {
61 pub lit_str: LitStr,
62}
63
64impl TryFrom<&Meta> for Marker {
65 fn try_from(value: &Meta) -> Result<Self> {
66 match value.lit_str.value().as_str() {
67 "deno_bindgen" => Ok(Self::DenoBindgen),
68 "deno_bindgen_non_blocking" => Ok(Self::NonBlocking),
69 _ => Err(Error::new(
70 value.lit_str.span(),
71 "unknown value. expected one of `deno_bindgen`, `deno_bindgen_non_blocking`, `deno_bindgen_constructor`"
72 )),
73 }
74 }
75
76 type Error = Error;
77}
78
79impl Parse for Meta {
80 fn parse(input: ParseStream) -> Result<Self> {
81 let key = input.parse::<Ident>()?;
82
83 if input.is_empty() {
84 let key_str = key.to_string();
85 match key_str.as_str() {
86 "non_blocking" => {
87 let lit_str = LitStr::new(
88 format!("deno_bindgen_{key_str}").as_str(),
89 Span::mixed_site(),
90 );
91 return Ok(Self { lit_str });
92 },
93 _ => (),
94 }
95 }
96
97 input.parse::<Token![=]>()?;
98 if key.to_string().as_str() == "doc" {
99 let lit_str = input.parse()?;
100
101 if !input.is_empty() {
103 Err(input.error("unknown token"))
104 } else {
105 Ok(Self { lit_str })
106 }
107 } else {
108 Err(Error::new(key.span(), "expected `doc` key"))
109 }
110 }
111}
112
113#[derive(Clone, Debug, Default, PartialEq)]
118pub struct Attribute {
119 pub markers: Vec<Marker>,
120 pub meta: Vec<Meta>,
121 }
124
125impl Attribute {
126 pub fn has_deno_bindgen(&self) -> bool {
128 self.markers
129 .iter()
130 .find(|marker| match marker {
131 Marker::DenoBindgen => true,
132 _ => false,
133 })
134 .is_some()
135 }
136
137 pub fn has_non_blocking(&self) -> bool {
139 self.markers
140 .iter()
141 .find(|marker| match marker {
142 Marker::NonBlocking => true,
143 _ => false,
144 })
145 .is_some()
146 }
147}
148
149impl Attribute {
150 pub fn parse_outer(&mut self, input: ParseStream) -> Result<()> {
151 while input.peek(Token![#]) {
152 input.parse::<Token![#]>()?;
153 if input.peek(Token![!]) {
154 return Err(Error::new(
155 input.span(),
156 "attempted to parse inner attribute in a parser for outer attributes",
157 ));
158 }
159
160 let content;
161 bracketed!(content in input);
162
163 let fork = content.fork();
164 if let Ok(meta) = fork.parse::<Meta>() {
165 content.advance_to(&fork);
166 if let Ok(marker) = Marker::try_from(&meta) {
167 self.markers.push(marker);
168 } else {
169 self.meta.push(meta);
170 }
171 } else {
172 content.parse::<syn::Meta>()?;
174 }
175 }
176
177 Ok(())
178 }
179
180 pub fn parse_inner(&mut self, input: ParseStream) -> Result<()> {
181 while input.peek(Token![#]) && input.peek2(Token![!]) {
182 input.parse::<Token![#]>()?;
183 input.parse::<Token![!]>()?;
184 let content;
185 bracketed!(content in input);
186
187 let fork = content.fork();
188 if let Ok(meta) = fork.parse::<Meta>() {
189 content.advance_to(&fork);
190 self.meta.push(meta);
191 } else {
192 content.parse::<syn::Meta>()?;
193 }
194 }
195
196 Ok(())
197 }
198}
199
200#[cfg(test)]
205mod tests {
206 use super::*;
207
208 impl Parse for Attribute {
209 fn parse(input: ParseStream) -> Result<Self> {
212 let mut attr = Self::default();
213
214 let ahead = input.lookahead1();
215 if ahead.peek(Token![#]) {
216 if input.peek2(Token![!]) {
217 attr.parse_inner(input)?;
218 } else {
219 attr.parse_outer(input)?;
220 }
221 } else {
222 return Err(ahead.error());
223 }
224
225 Ok(attr)
226 }
227 }
228
229 #[test]
230 fn test_attr() {
231 dbg_quote!(Attribute,
232 #[some_attr]
233 #[doc = "some unknown value"]
234 #[another_attr]
235 );
236 }
237
238 #[test]
239 #[should_panic]
240 fn test_mix_attr() {
241 dbg_quote!(Attribute,
242 #[outer]
243 #![innter]
244 );
245 }
246
247 #[test]
248 fn test_marker() {
249 dbg_quote!(Attribute,
250 #[doc = "deno_bindgen_constructor"]
251 #[doc = "deno_bindgen"]
252 );
253 }
254
255 #[test]
256 fn test_cfg_attr() {
257 dbg_quote!(Attribute,
258 #[cfg_attr(not(deno_bindgen), doc = "deno_bindgen_constructor")]
259 );
260 }
261
262 #[test]
263 fn test_live_attr() {
264 dbg_quote!(Attribute,
265 #[constructor]
266 );
267 }
268}