codama_attributes/
derive_attribute.rs

1use crate::Attribute;
2use codama_errors::CodamaError;
3use codama_syn_helpers::extensions::*;
4
5#[derive(Debug, PartialEq)]
6pub struct DeriveAttribute<'a> {
7    pub ast: &'a syn::Attribute,
8    pub derives: Vec<syn::Path>,
9}
10
11impl<'a> DeriveAttribute<'a> {
12    pub fn parse(ast: &'a syn::Attribute) -> syn::Result<Self> {
13        // Check if the attribute is feature-gated.
14        let unfeatured = ast.unfeatured();
15        let attr = unfeatured.as_ref().unwrap_or(ast);
16
17        // Check if the attribute is a #[derive(...)] attribute.
18        let list = attr.meta.require_list()?;
19        if !list.path.is_strict("derive") {
20            return Err(list.path.error("expected #[derive(...)]"));
21        };
22
23        // Parse the list of derives.
24        let derives = list.parse_comma_args::<syn::Path>()?;
25        Ok(Self { ast, derives })
26    }
27}
28
29impl<'a> TryFrom<&'a Attribute<'a>> for &'a DeriveAttribute<'a> {
30    type Error = CodamaError;
31
32    fn try_from(attribute: &'a Attribute) -> Result<Self, Self::Error> {
33        match attribute {
34            Attribute::Derive(a) => Ok(a),
35            _ => Err(CodamaError::InvalidAttribute {
36                expected: "derive".to_string(),
37                actual: attribute.name(),
38            }),
39        }
40    }
41}
42
43#[cfg(test)]
44mod tests {
45    use super::*;
46    use syn::parse_quote;
47
48    #[test]
49    fn test_derive_attribute() {
50        let ast = parse_quote! { #[derive(Debug, PartialEq)] };
51        let attribute = DeriveAttribute::parse(&ast).unwrap();
52
53        assert_eq!(attribute.ast, &ast);
54        assert_eq!(
55            attribute.derives,
56            [(parse_quote! { Debug }), (parse_quote! { PartialEq }),]
57        );
58    }
59
60    #[test]
61    fn test_feature_gated_derive_attribute() {
62        let ast = parse_quote! { #[cfg_attr(feature = "some_feature", derive(Debug, PartialEq))] };
63        let attribute = DeriveAttribute::parse(&ast).unwrap();
64
65        assert_eq!(attribute.ast, &ast);
66        assert_eq!(
67            attribute.derives,
68            [(parse_quote! { Debug }), (parse_quote! { PartialEq })]
69        );
70    }
71}