codama_koroks/
field_korok.rs1use crate::KorokTrait;
2use codama_attributes::{Attributes, NameDirective, TryFromFilter};
3use codama_errors::{CodamaResult, IteratorCombineErrors};
4use codama_nodes::{CamelCaseString, Node, RegisteredTypeNode, StructFieldTypeNode, TypeNode};
5
6#[derive(Debug, PartialEq)]
7pub struct FieldKorok<'a> {
8 pub ast: &'a syn::Field,
9 pub attributes: Attributes<'a>,
10 pub node: Option<Node>,
11}
12
13impl<'a> FieldKorok<'a> {
14 pub fn parse(ast: &'a syn::Field) -> CodamaResult<Self> {
15 let attributes = Attributes::parse(&ast.attrs, ast.into())?;
16 Ok(Self {
17 ast,
18 attributes,
19 node: None,
20 })
21 }
22
23 pub fn parse_all(ast: &'a syn::Fields) -> CodamaResult<Vec<Self>> {
24 match ast {
25 syn::Fields::Named(f) => f.named.iter().map(Self::parse).collect_and_combine_errors(),
26 syn::Fields::Unnamed(f) => f
27 .unnamed
28 .iter()
29 .map(Self::parse)
30 .collect_and_combine_errors(),
31 syn::Fields::Unit => Ok(vec![]),
32 }
33 }
34
35 pub fn name(&self) -> Option<CamelCaseString> {
36 self.attributes
37 .get_last(NameDirective::filter)
38 .map(|n| n.name.clone())
39 .or_else(|| self.ast.ident.as_ref().map(|i| i.to_string().into()))
40 }
41
42 pub fn get_updated_type_node(&self, node: TypeNode) -> Option<Node> {
43 match &self.node {
44 Some(Node::Type(RegisteredTypeNode::StructField(field))) => Some(
45 StructFieldTypeNode {
46 r#type: node,
47 ..field.clone()
48 }
49 .into(),
50 ),
51 _ => match self.ast.ident.as_ref() {
55 Some(_) => Some(StructFieldTypeNode::new(self.name().unwrap(), node).into()),
56 None => Some(node.into()),
57 },
58 }
59 }
60
61 pub fn set_type_node(&mut self, node: TypeNode) {
62 self.node = self.get_updated_type_node(node);
63 }
64}
65
66impl KorokTrait for FieldKorok<'_> {
67 fn node(&self) -> &Option<Node> {
68 &self.node
69 }
70
71 fn set_node(&mut self, node: Option<Node>) {
72 self.node = node;
73 }
74
75 fn attributes(&self) -> Option<&Attributes<'_>> {
76 Some(&self.attributes)
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83 use codama_nodes::{
84 NumberFormat::{U32, U64},
85 NumberTypeNode,
86 };
87
88 #[test]
89 fn get_updated_type_node_with_named_none() {
90 let korok = FieldKorok {
91 ast: &syn::parse_quote! { pub my_field: u32 },
92 attributes: Attributes(vec![]),
93 node: None,
94 };
95 assert_eq!(
96 korok.get_updated_type_node(NumberTypeNode::le(U32).into()),
97 Some(StructFieldTypeNode::new("my_field", NumberTypeNode::le(U32)).into())
98 );
99 }
100
101 #[test]
102 fn get_updated_type_node_with_unnamed_none() {
103 let korok = FieldKorok {
104 ast: &syn::parse_quote! { u32 },
105 attributes: Attributes(vec![]),
106 node: None,
107 };
108 assert_eq!(
109 korok.get_updated_type_node(NumberTypeNode::le(U32).into()),
110 Some(NumberTypeNode::le(U32).into())
111 );
112 }
113
114 #[test]
115 fn get_updated_type_node_with_some() {
116 let korok = FieldKorok {
117 ast: &syn::parse_quote! { pub my_field: u32 },
118 attributes: Attributes(vec![]),
119 node: Some(StructFieldTypeNode::new("my_node_name", NumberTypeNode::le(U32)).into()),
120 };
121 assert_eq!(
122 korok.get_updated_type_node(NumberTypeNode::le(U64).into()),
123 Some(StructFieldTypeNode::new("my_node_name", NumberTypeNode::le(U64)).into())
124 );
125 }
126}