codama_attributes/codama_directives/
field_directive.rs1use crate::{
2 codama_directives::type_nodes::StructFieldMetaConsumer,
3 utils::{FromMeta, MetaConsumer},
4 Attribute, CodamaAttribute, CodamaDirective,
5};
6use codama_errors::CodamaError;
7use codama_nodes::{Docs, StructFieldTypeNode};
8use codama_syn_helpers::Meta;
9
10#[derive(Debug, PartialEq)]
11pub struct FieldDirective {
12 pub after: bool,
13 pub field: StructFieldTypeNode,
14}
15
16impl FieldDirective {
17 pub fn parse(meta: &Meta) -> syn::Result<Self> {
18 meta.assert_directive("field")?;
19 let consumer = StructFieldMetaConsumer::from_meta(meta)?
20 .consume_field()?
21 .consume_default_value()?
22 .consume_after()?
23 .assert_fully_consumed()?;
24
25 Ok(FieldDirective {
26 after: consumer.after.option().unwrap_or(false),
27 field: StructFieldTypeNode {
28 name: consumer.name.take(meta)?,
29 r#type: consumer.r#type.take(meta)?,
30 docs: Docs::default(),
31 default_value: consumer.default_value.option(),
32 default_value_strategy: consumer.default_value_strategy.option(),
33 },
34 })
35 }
36}
37
38impl<'a> TryFrom<&'a CodamaAttribute<'a>> for &'a FieldDirective {
39 type Error = CodamaError;
40
41 fn try_from(attribute: &'a CodamaAttribute) -> Result<Self, Self::Error> {
42 match attribute.directive {
43 CodamaDirective::Field(ref a) => Ok(a),
44 _ => Err(CodamaError::InvalidCodamaDirective {
45 expected: "field".to_string(),
46 actual: attribute.directive.name().to_string(),
47 }),
48 }
49 }
50}
51
52impl<'a> TryFrom<&'a Attribute<'a>> for &'a FieldDirective {
53 type Error = CodamaError;
54
55 fn try_from(attribute: &'a Attribute) -> Result<Self, Self::Error> {
56 <&CodamaAttribute>::try_from(attribute)?.try_into()
57 }
58}
59
60#[cfg(test)]
61mod tests {
62 use super::*;
63 use codama_nodes::{NumberFormat::U8, NumberTypeNode, NumberValueNode};
64
65 #[test]
66 fn ok() {
67 let meta: Meta = syn::parse_quote! { field("age", number(u8)) };
68 let directive = FieldDirective::parse(&meta).unwrap();
69 assert_eq!(
70 directive,
71 FieldDirective {
72 after: false,
73 field: StructFieldTypeNode::new("age", NumberTypeNode::le(U8)),
74 }
75 );
76 }
77
78 #[test]
79 fn after() {
80 let meta: Meta = syn::parse_quote! { field(after, "age", number(u8)) };
81 let directive = FieldDirective::parse(&meta).unwrap();
82 assert_eq!(
83 directive,
84 FieldDirective {
85 after: true,
86 field: StructFieldTypeNode::new("age", NumberTypeNode::le(U8)),
87 }
88 );
89 }
90
91 #[test]
92 fn with_default_value() {
93 let meta: Meta = syn::parse_quote! { field("age", number(u8), default_value = 42) };
94 let directive = FieldDirective::parse(&meta).unwrap();
95 assert_eq!(
96 directive,
97 FieldDirective {
98 after: false,
99 field: StructFieldTypeNode {
100 default_value: Some(NumberValueNode::new(42u8).into()),
101 ..StructFieldTypeNode::new("age", NumberTypeNode::le(U8))
102 },
103 }
104 );
105 }
106}