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.name() {
52 Some(name) => Some(StructFieldTypeNode::new(name, node).into()),
53 None => Some(node.into()),
54 },
55 }
56 }
57
58 pub fn set_type_node(&mut self, node: TypeNode) {
59 self.node = self.get_updated_type_node(node);
60 }
61}
62
63impl KorokTrait for FieldKorok<'_> {
64 fn node(&self) -> &Option<Node> {
65 &self.node
66 }
67
68 fn set_node(&mut self, node: Option<Node>) {
69 self.node = node;
70 }
71
72 fn attributes(&self) -> Option<&Attributes<'_>> {
73 Some(&self.attributes)
74 }
75}
76
77#[cfg(test)]
78mod tests {
79 use super::*;
80 use codama_nodes::{
81 NumberFormat::{U32, U64},
82 NumberTypeNode,
83 };
84
85 #[test]
86 fn get_updated_type_node_with_named_none() {
87 let korok = FieldKorok {
88 ast: &syn::parse_quote! { pub my_field: u32 },
89 attributes: Attributes(vec![]),
90 node: None,
91 };
92 assert_eq!(
93 korok.get_updated_type_node(NumberTypeNode::le(U32).into()),
94 Some(StructFieldTypeNode::new("my_field", NumberTypeNode::le(U32)).into())
95 );
96 }
97
98 #[test]
99 fn get_updated_type_node_with_unnamed_none() {
100 let korok = FieldKorok {
101 ast: &syn::parse_quote! { u32 },
102 attributes: Attributes(vec![]),
103 node: None,
104 };
105 assert_eq!(
106 korok.get_updated_type_node(NumberTypeNode::le(U32).into()),
107 Some(NumberTypeNode::le(U32).into())
108 );
109 }
110
111 #[test]
112 fn get_updated_type_node_with_some() {
113 let korok = FieldKorok {
114 ast: &syn::parse_quote! { pub my_field: u32 },
115 attributes: Attributes(vec![]),
116 node: Some(StructFieldTypeNode::new("my_node_name", NumberTypeNode::le(U32)).into()),
117 };
118 assert_eq!(
119 korok.get_updated_type_node(NumberTypeNode::le(U64).into()),
120 Some(StructFieldTypeNode::new("my_node_name", NumberTypeNode::le(U64)).into())
121 );
122 }
123}