macro_tools/attr.rs
1//!
2//! Attributes analyzys and manipulation.
3//!
4
5/// Define a private namespace for all its items.
6mod private
7{
8 #[ allow( clippy::wildcard_imports ) ]
9 use crate::*;
10
11 /// Checks if the given iterator of attributes contains an attribute named `debug`.
12 ///
13 /// This function iterates over an input sequence of `syn::Attribute`, typically associated with a struct,
14 /// enum, or other item in a Rust Abstract Syntax Tree ( AST ), and determines whether any of the attributes
15 /// is exactly named `debug`.
16 ///
17 /// # Parameters
18 /// - `attrs` : An iterator over `syn::Attribute`. This could be obtained from parsing Rust code
19 /// with the `syn` crate, where the iterator represents attributes applied to a Rust item ( like a struct or function ).
20 ///
21 /// # Returns
22 /// - `Ok( true )` if the `debug` attribute is present.
23 /// - `Ok( false )` if the `debug` attribute is not found.
24 /// - `Err( syn::Error )` if an unknown or improperly formatted attribute is encountered.
25 ///
26 /// # Example
27 ///
28 /// Suppose you have the following struct definition in a procedural macro input:
29 ///
30 /// ```rust, ignore
31 /// #[ derive( SomeDerive ) ]
32 /// #[ debug ]
33 /// struct MyStruct
34 /// {
35 /// field : i32,
36 /// }
37 /// ```
38 ///
39 /// You can use `has_debug` to check for the presence of the `debug` attribute:
40 ///
41 /// ```rust
42 /// use macro_tools::exposed::*;
43 ///
44 /// // Example struct attribute
45 /// let attrs : Vec< syn::Attribute > = vec![ syn::parse_quote!( #[ debug ] ) ];
46 ///
47 /// // Checking for 'debug' attribute
48 /// let contains_debug = attr::has_debug( ( &attrs ).into_iter() ).unwrap();
49 ///
50 /// assert!( contains_debug, "Expected to find 'debug' attribute" );
51 /// ```
52 /// # Errors
53 /// qqq: doc
54 pub fn has_debug< 'a >( attrs : impl Iterator< Item = &'a syn::Attribute > ) -> syn::Result< bool >
55 {
56 for attr in attrs
57 {
58 if let Some( ident ) = attr.path().get_ident()
59 {
60 let ident_string = format!( "{ident}" );
61 if ident_string == "debug"
62 {
63 return Ok( true )
64 }
65 }
66 else
67 {
68 return_syn_err!( "Unknown structure attribute:\n{}", qt!{ attr } );
69 }
70 }
71 Ok( false )
72 }
73
74 /// Checks if the given attribute name is a standard Rust attribute.
75 ///
76 /// Standard Rust attributes are those which are recognized and processed
77 /// directly by the Rust compiler. They influence various aspects of compilation,
78 /// including but not limited to conditional compilation, optimization hints,
79 /// code visibility, and procedural macro behavior.
80 ///
81 /// This function is useful when developing tools that need to interact with or
82 /// understand the significance of specific attributes in Rust source code, such
83 /// as linters, code analyzers, or procedural macros.
84 ///
85 /// This function does not cover all possible attributes but includes many of the
86 /// common ones that are relevant to most Rust projects. Developers are encouraged
87 /// to update this function as needed to suit more specialized needs, especially
88 /// when dealing with nightly-only compiler attributes or deprecated ones.
89 ///
90 /// # Parameters
91 /// - `attr_name`: A string slice that holds the name of the attribute to check.
92 ///
93 /// # Returns
94 /// Returns `true` if `attr_name` is a recognized standard Rust attribute. Otherwise,
95 /// returns `false`.
96 ///
97 /// # Examples
98 ///
99 /// Standard attributes:
100 ///
101 /// ```
102 /// assert_eq!( macro_tools::attr::is_standard( "cfg" ), true );
103 /// assert_eq!( macro_tools::attr::is_standard( "inline" ), true );
104 /// assert_eq!( macro_tools::attr::is_standard( "derive" ), true );
105 /// ```
106 ///
107 /// Non-standard or custom attributes:
108 ///
109 /// ```
110 /// assert_eq!( macro_tools::attr::is_standard( "custom_attr" ), false );
111 /// assert_eq!( macro_tools::attr::is_standard( "my_attribute" ), false );
112 /// ```
113 ///
114 #[ must_use ]
115 #[ allow( clippy::match_same_arms ) ]
116 pub fn is_standard( attr_name : &str ) -> bool
117 {
118 match attr_name
119 {
120 // Conditional compilation
121 "cfg" | "cfg_attr" => true,
122
123 // Compiler instructions and optimizations
124 "inline" | "repr" | "derive" | "allow" | "warn" | "deny" | "forbid" => true,
125
126 // Testing attributes
127 "test" | "bench" => true,
128
129 // Documentation attributes
130 "doc" => true,
131
132 // Visibility and accessibility
133 "pub" => true, // This would typically need context to be accurate
134
135 // Safety and ABI
136 "unsafe" | "no_mangle" | "extern" => true,
137
138 // Module and Crate configuration
139 "path" | "macro_use" | "crate_type" | "crate_name" => true,
140
141 // Linking
142 "link" | "link_name" | "link_section" => true,
143
144 // Usage warnings
145 "must_use" => true,
146
147 // Other attributes
148 "cold" | "export_name" | "global_allocator" => true,
149
150 // Module handling
151 "used" | "unused" => true,
152
153 // Procedural macros and hygiene
154 "proc_macro" | "proc_macro_derive" | "proc_macro_attribute" => true,
155
156 // Stability attributes
157 "stable" | "unstable" | "rustc_const_unstable" | "rustc_const_stable" |
158 "rustc_diagnostic_item" | "rustc_deprecated" | "rustc_legacy_const_generics" => true,
159
160 // Special compiler attributes
161 "feature" | "non_exhaustive" => true,
162
163 // Future compatibility
164 "rustc_paren_sugar" | "rustc_insignificant_dtor" => true,
165
166 // Type system extensions
167 "opaque" => true,
168
169 // Miscellaneous
170 "track_caller" => true,
171
172 // Default case
173 _ => false,
174 }
175 }
176
177 ///
178 /// Attribute which is inner.
179 ///
180 /// For example: `// #![ deny( missing_docs ) ]`.
181 ///
182
183 #[ derive( Debug, PartialEq, Eq, Clone, Default ) ]
184 pub struct AttributesInner( pub Vec< syn::Attribute > );
185
186 impl From< Vec< syn::Attribute > > for AttributesInner
187 {
188 #[ inline( always ) ]
189 fn from( src : Vec< syn::Attribute > ) -> Self
190 {
191 Self( src )
192 }
193 }
194
195 impl From< AttributesInner > for Vec< syn::Attribute >
196 {
197 #[ inline( always ) ]
198 fn from( src : AttributesInner ) -> Self
199 {
200 src.0
201 }
202 }
203
204 #[ allow( clippy::iter_without_into_iter ) ]
205 impl AttributesInner
206 {
207 /// Iterator
208 pub fn iter( &self ) -> core::slice::Iter< '_, syn::Attribute >
209 {
210 self.0.iter()
211 }
212 }
213
214 #[ allow( clippy::default_trait_access ) ]
215 impl syn::parse::Parse
216 for AttributesInner
217 {
218 fn parse( input : ParseStream< '_ > ) -> syn::Result< Self >
219 {
220 // let mut result : Self = from!();
221 let mut result : Self = Default::default();
222 loop
223 {
224 if !input.peek( Token![ # ] ) || !input.peek2( Token![ ! ] )
225 {
226 break;
227 }
228 let input2;
229 let element = syn::Attribute
230 {
231 pound_token : input.parse()?,
232 style : syn::AttrStyle::Inner( input.parse()? ),
233 bracket_token : bracketed!( input2 in input ),
234 // path : input2.call( syn::Path::parse_mod_style )?,
235 // tokens : input2.parse()?,
236 meta : input2.parse()?,
237 };
238 result.0.push( element );
239 }
240 Ok( result )
241 }
242 }
243
244 impl quote::ToTokens
245 for AttributesInner
246 {
247 fn to_tokens( &self, tokens : &mut proc_macro2::TokenStream )
248 {
249 use crate::quote::TokenStreamExt;
250 tokens.append_all( self.0.iter() );
251 }
252 }
253
254 /// Represents a collection of outer attributes.
255 ///
256 /// This struct wraps a `Vec< syn::Attribute >`, providing utility methods for parsing,
257 /// converting, and iterating over outer attributes. Outer attributes are those that
258 /// appear outside of an item, such as `#[ ... ]` annotations in Rust.
259 ///
260 #[ derive( Debug, PartialEq, Eq, Clone, Default ) ]
261 pub struct AttributesOuter( pub Vec< syn::Attribute > );
262
263 impl From< Vec< syn::Attribute > > for AttributesOuter
264 {
265 #[ inline( always ) ]
266 fn from( src : Vec< syn::Attribute > ) -> Self
267 {
268 Self( src )
269 }
270 }
271
272 impl From< AttributesOuter > for Vec< syn::Attribute >
273 {
274 #[ inline( always ) ]
275 fn from( src : AttributesOuter ) -> Self
276 {
277 src.0
278 }
279 }
280
281 #[ allow( clippy::iter_without_into_iter ) ]
282 impl AttributesOuter
283 {
284 /// Iterator
285 pub fn iter( &self ) -> core::slice::Iter< '_, syn::Attribute >
286 {
287 self.0.iter()
288 }
289 }
290
291 #[ allow( clippy::default_trait_access ) ]
292 impl syn::parse::Parse
293 for AttributesOuter
294 {
295 fn parse( input : ParseStream< '_ > ) -> syn::Result< Self >
296 {
297 let mut result : Self = Default::default();
298 loop
299 {
300 if !input.peek( Token![ # ] ) || input.peek2( Token![ ! ] )
301 {
302 break;
303 }
304 let input2;
305 let element = syn::Attribute
306 {
307 pound_token : input.parse()?,
308 style : syn::AttrStyle::Outer,
309 bracket_token : bracketed!( input2 in input ),
310 // path : input2.call( syn::Path::parse_mod_style )?,
311 // tokens : input2.parse()?,
312 meta : input2.parse()?,
313 };
314 result.0.push( element );
315 }
316 Ok( result )
317 }
318 }
319
320 impl quote::ToTokens
321 for AttributesOuter
322 {
323 fn to_tokens( &self, tokens : &mut proc_macro2::TokenStream )
324 {
325 use crate::quote::TokenStreamExt;
326 tokens.append_all( self.0.iter() );
327 }
328 }
329
330 impl syn::parse::Parse
331 for Many< AttributesInner >
332 {
333 fn parse( input : ParseStream< '_ > ) -> syn::Result< Self >
334 {
335 let mut result = Self::new();
336 loop
337 {
338 // let lookahead = input.lookahead1();
339 if !input.peek( Token![ # ] )
340 {
341 break;
342 }
343 result.0.push( input.parse()? );
344 }
345 Ok( result )
346 }
347 }
348
349 impl syn::parse::Parse
350 for Many< AttributesOuter >
351 {
352 fn parse( input : ParseStream< '_ > ) -> syn::Result< Self >
353 {
354 let mut result = Self::new();
355 loop
356 {
357 // let lookahead = input.lookahead1();
358 if !input.peek( Token![ # ] )
359 {
360 break;
361 }
362 result.0.push( input.parse()? );
363 }
364 Ok( result )
365 }
366 }
367
368 impl AsMuchAsPossibleNoDelimiter for syn::Item {}
369
370 /// Trait for components of a structure aggregating attributes that can be constructed from a meta attribute.
371 ///
372 /// The `AttributeComponent` trait defines the interface for components that can be created
373 /// from a `syn::Attribute` meta item. Implementors of this trait are required to define
374 /// a constant `KEYWORD` that identifies the type of the component and a method `from_meta`
375 /// that handles the construction of the component from the given attribute.
376 ///
377 /// This trait is designed to facilitate modular and reusable parsing of attributes applied
378 /// to structs, enums, or other constructs. By implementing this trait, you can create specific
379 /// components from attributes and then aggregate these components into a larger structure.
380 ///
381 /// # Example
382 ///
383 /// ```rust
384 /// use macro_tools::{ AttributeComponent, syn::Result };
385 /// use syn::{ Attribute, Error };
386 ///
387 /// struct MyComponent;
388 ///
389 /// impl AttributeComponent for MyComponent
390 /// {
391 /// const KEYWORD : &'static str = "my_component";
392 ///
393 /// fn from_meta( attr : &Attribute ) -> syn::Result<Self>
394 /// {
395 /// // Parsing logic here
396 /// // Return Ok(MyComponent) if parsing is successful
397 /// // Return Err(Error::new_spanned(attr, "error message")) if parsing fails
398 /// Ok( MyComponent )
399 /// }
400 /// }
401 /// ```
402 ///
403 /// # Parameters
404 ///
405 /// - `attr` : A reference to the `syn::Attribute` from which the component is to be constructed.
406 ///
407 /// # Returns
408 ///
409 /// A `syn::Result` containing the constructed component if successful, or an error if the parsing fails.
410 ///
411 pub trait AttributeComponent
412 where
413 Self : Sized,
414 {
415 /// The keyword that identifies the component.
416 ///
417 /// This constant is used to match the attribute to the corresponding component.
418 /// Each implementor of this trait must provide a unique keyword for its type.
419 const KEYWORD : &'static str;
420
421 /// Constructs the component from the given meta attribute.
422 ///
423 /// This method is responsible for parsing the provided `syn::Attribute` and
424 /// returning an instance of the component. If the attribute cannot be parsed
425 /// into the component, an error should be returned.
426 ///
427 /// # Parameters
428 ///
429 /// - `attr` : A reference to the `syn::Attribute` from which the component is to be constructed.
430 ///
431 /// # Returns
432 ///
433 /// A `syn::Result` containing the constructed component if successful, or an error if the parsing fails.
434 ///
435 /// # Errors
436 /// qqq: doc
437 fn from_meta( attr : &syn::Attribute ) -> syn::Result< Self >;
438
439 // zzz : redo maybe
440 }
441
442}
443
444#[ doc( inline ) ]
445#[ allow( unused_imports ) ]
446pub use own::*;
447
448/// Own namespace of the module.
449#[ allow( unused_imports ) ]
450pub mod own
451{
452 #[ allow( clippy::wildcard_imports ) ]
453 use super::*;
454 #[ doc( inline ) ]
455 pub use orphan::*;
456 #[ doc( inline ) ]
457 pub use private::
458 {
459 // equation,
460 has_debug,
461 is_standard,
462 };
463}
464
465/// Orphan namespace of the module.
466#[ allow( unused_imports ) ]
467pub mod orphan
468{
469 #[ allow( clippy::wildcard_imports ) ]
470 use super::*;
471 #[ doc( inline ) ]
472 pub use exposed::*;
473}
474
475/// Exposed namespace of the module.
476#[ allow( unused_imports ) ]
477pub mod exposed
478{
479 #[ allow( clippy::wildcard_imports ) ]
480 use super::*;
481 pub use super::super::attr;
482
483 #[ doc( inline ) ]
484 pub use prelude::*;
485 #[ doc( inline ) ]
486 pub use private::
487 {
488 AttributesInner,
489 AttributesOuter,
490 AttributeComponent,
491 };
492}
493
494/// Prelude to use essentials: `use my_module::prelude::*`.
495#[ allow( unused_imports ) ]
496pub mod prelude
497{
498 use super::*;
499}