codama_attributes/
attribute.rs

1use crate::{
2    AttributeContext, CodamaAttribute, DeriveAttribute, ReprAttribute, UnsupportedAttribute,
3};
4use codama_syn_helpers::extensions::*;
5use derive_more::derive::From;
6
7#[derive(Debug, PartialEq, From)]
8pub enum Attribute<'a> {
9    // E.g. `#[codama(type = number(u8))]` or `#[codama(fixed_size = 32)]`.
10    Codama(CodamaAttribute<'a>),
11    // E.g. `#[derive(Debug, CodamaType)]`.
12    Derive(DeriveAttribute<'a>),
13    // E.g. `#[repr(u32, align(8))]`.
14    Repr(ReprAttribute<'a>),
15    // E.g. `#[some_unsupported_attribute = 42]`.
16    Unsupported(UnsupportedAttribute<'a>),
17}
18
19impl<'a> Attribute<'a> {
20    pub fn parse(ast: &'a syn::Attribute, ctx: &AttributeContext) -> syn::Result<Self> {
21        let unfeatured = ast.unfeatured();
22        let effective = unfeatured.as_ref().unwrap_or(ast);
23        Self::parse_from(ast, effective, ctx)
24    }
25
26    /// Parse an attribute using the effective attribute for content extraction.
27    /// `ast` is stored as the original attribute reference (for error spans).
28    /// `effective` is used to determine the attribute type and parse its content.
29    pub fn parse_from(
30        ast: &'a syn::Attribute,
31        effective: &syn::Attribute,
32        ctx: &AttributeContext,
33    ) -> syn::Result<Self> {
34        let path = effective.path();
35        match (path.prefix().as_str(), path.last_str().as_str()) {
36            ("" | "codama_macros" | "codama", "codama") => {
37                Ok(CodamaAttribute::parse_from(ast, effective, ctx)?.into())
38            }
39            ("", "derive") => Ok(DeriveAttribute::parse_from(ast, effective)?.into()),
40            ("", "repr") => Ok(ReprAttribute::parse_from(ast, effective)?.into()),
41            _ => Ok(UnsupportedAttribute::new(ast).into()),
42        }
43    }
44
45    pub fn ast(&self) -> &syn::Attribute {
46        match self {
47            Attribute::Codama(a) => a.ast,
48            Attribute::Derive(a) => a.ast,
49            Attribute::Repr(a) => a.ast,
50            Attribute::Unsupported(a) => a.ast,
51        }
52    }
53
54    pub fn name(&self) -> String {
55        self.ast().path().last_str()
56    }
57}