codama_attributes/
codama_attribute.rs1use crate::{utils::SetOnce, AccountDirective, AttributeContext, CodamaDirective};
2use codama_syn_helpers::extensions::*;
3
4#[derive(Debug, PartialEq)]
5pub struct CodamaAttribute<'a> {
6 pub ast: &'a syn::Attribute,
7 pub directive: CodamaDirective,
8}
9
10impl<'a> CodamaAttribute<'a> {
11 pub fn parse(ast: &'a syn::Attribute, ctx: &AttributeContext) -> syn::Result<Self> {
12 let unfeatured = ast.unfeatured();
14 let attr = unfeatured.as_ref().unwrap_or(ast);
15
16 let list = attr.meta.require_list()?;
18 if !list.path.is_strict("codama") {
19 return Err(list.path.error("expected #[codama(...)]"));
20 };
21
22 let mut directive = SetOnce::<CodamaDirective>::new("codama");
23 list.each(|ref meta| directive.set(CodamaDirective::parse(meta, ctx)?, meta))?;
24 Ok(Self {
25 ast,
26 directive: directive.take(attr)?,
27 })
28 }
29
30 pub fn account(&self) -> Option<&AccountDirective> {
31 match &self.directive {
32 CodamaDirective::Account(a) => Some(a),
33 _ => None,
34 }
35 }
36}
37
38#[cfg(test)]
39mod tests {
40 use super::*;
41 use syn::parse_quote;
42
43 #[test]
44 fn test_codama_attribute() {
45 let ast = parse_quote! { #[codama(type = boolean)] };
46 let file = syn::File::empty();
47 let ctx = AttributeContext::File(&file);
48 let attribute = CodamaAttribute::parse(&ast, &ctx).unwrap();
49
50 assert_eq!(attribute.ast, &ast);
51 assert!(matches!(attribute.directive, CodamaDirective::Type(_)));
52 }
53
54 #[test]
55 fn test_feature_gated_codama_attribute() {
56 let ast = parse_quote! { #[cfg_attr(feature = "some_feature", codama(type = boolean))] };
57 let file = syn::File::empty();
58 let ctx = AttributeContext::File(&file);
59 let attribute = CodamaAttribute::parse(&ast, &ctx).unwrap();
60
61 assert_eq!(attribute.ast, &ast);
62 assert!(matches!(attribute.directive, CodamaDirective::Type(_)));
63 }
64}