codama_attributes/
derive_attribute.rs1use 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 let unfeatured = ast.unfeatured();
15 let attr = unfeatured.as_ref().unwrap_or(ast);
16
17 let list = attr.meta.require_list()?;
19 if !list.path.is_strict("derive") {
20 return Err(list.path.error("expected #[derive(...)]"));
21 };
22
23 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}