codama_nodes/
instruction_argument_node.rs

1use crate::{
2    CamelCaseString, DefaultValueStrategy, Docs, InstructionInputValueNode, StructFieldTypeNode,
3    StructTypeNode, TypeNode,
4};
5use codama_nodes_derive::node;
6
7#[node]
8pub struct InstructionArgumentNode {
9    // Data.
10    pub name: CamelCaseString,
11    #[serde(skip_serializing_if = "crate::is_default")]
12    pub default_value_strategy: Option<DefaultValueStrategy>,
13    #[serde(default, skip_serializing_if = "crate::is_default")]
14    pub docs: Docs,
15
16    // Children.
17    pub r#type: TypeNode,
18    #[serde(skip_serializing_if = "crate::is_default")]
19    pub default_value: Option<InstructionInputValueNode>,
20}
21
22impl InstructionArgumentNode {
23    pub fn new<T, U>(name: T, r#type: U) -> Self
24    where
25        T: Into<CamelCaseString>,
26        U: Into<TypeNode>,
27    {
28        Self {
29            name: name.into(),
30            default_value_strategy: None,
31            docs: Docs::default(),
32            r#type: r#type.into(),
33            default_value: None,
34        }
35    }
36}
37
38impl From<StructFieldTypeNode> for InstructionArgumentNode {
39    fn from(value: StructFieldTypeNode) -> Self {
40        Self {
41            name: value.name,
42            default_value_strategy: value.default_value_strategy,
43            docs: value.docs,
44            r#type: value.r#type,
45            default_value: value.default_value.map(InstructionInputValueNode::from),
46        }
47    }
48}
49
50impl From<StructTypeNode> for Vec<InstructionArgumentNode> {
51    fn from(val: StructTypeNode) -> Self {
52        val.fields
53            .into_iter()
54            .map(InstructionArgumentNode::from)
55            .collect()
56    }
57}
58
59#[cfg(test)]
60mod tests {
61    use super::*;
62    use crate::{ArgumentValueNode, NumberTypeNode, U32};
63
64    #[test]
65    fn new() {
66        let node = InstructionArgumentNode::new("my_argument", NumberTypeNode::le(U32));
67        assert_eq!(node.name, CamelCaseString::new("myArgument"));
68        assert_eq!(node.r#type, TypeNode::Number(NumberTypeNode::le(U32)));
69    }
70
71    #[test]
72    fn direct_instantiation() {
73        let node = InstructionArgumentNode {
74            name: "myArgument".into(),
75            default_value_strategy: Some(DefaultValueStrategy::Optional),
76            docs: vec!["Hello".to_string()].into(),
77            r#type: NumberTypeNode::le(U32).into(),
78            default_value: Some(ArgumentValueNode::new("myOtherArgument").into()),
79        };
80
81        assert_eq!(node.name, CamelCaseString::new("myArgument"));
82        assert_eq!(
83            node.default_value_strategy,
84            Some(DefaultValueStrategy::Optional)
85        );
86        assert_eq!(*node.docs, vec!["Hello".to_string()]);
87        assert_eq!(node.r#type, TypeNode::Number(NumberTypeNode::le(U32)));
88        assert_eq!(
89            node.default_value,
90            Some(InstructionInputValueNode::Argument(ArgumentValueNode::new(
91                "myOtherArgument"
92            )))
93        );
94    }
95
96    #[test]
97    fn to_json() {
98        let node = InstructionArgumentNode::new("myArgument", NumberTypeNode::le(U32));
99        let json = serde_json::to_string(&node).unwrap();
100        assert_eq!(
101            json,
102            r#"{"kind":"instructionArgumentNode","name":"myArgument","type":{"kind":"numberTypeNode","format":"u32","endian":"le"}}"#
103        );
104    }
105
106    #[test]
107    fn from_json() {
108        let json = r#"{"kind":"instructionArgumentNode","name":"myArgument","type":{"kind":"numberTypeNode","format":"u32","endian":"le"}}"#;
109        let node: InstructionArgumentNode = serde_json::from_str(json).unwrap();
110        assert_eq!(
111            node,
112            InstructionArgumentNode::new("myArgument", NumberTypeNode::le(U32))
113        );
114    }
115}