codama_nodes/
instruction_node.rs

1use crate::{
2    CamelCaseString, DiscriminatorNode, Docs, InstructionAccountNode, InstructionArgumentNode,
3    InstructionByteDeltaNode, InstructionRemainingAccountsNode,
4};
5use codama_nodes_derive::node;
6use serde::{Deserialize, Serialize};
7
8#[node]
9#[derive(Default)]
10pub struct InstructionNode {
11    // Data.
12    pub name: CamelCaseString,
13    #[serde(default, skip_serializing_if = "crate::is_default")]
14    pub docs: Docs,
15    #[serde(default, skip_serializing_if = "crate::is_default")]
16    pub optional_account_strategy: InstructionOptionalAccountStrategy,
17
18    // Children.
19    pub accounts: Vec<InstructionAccountNode>,
20    pub arguments: Vec<InstructionArgumentNode>,
21    #[serde(default, skip_serializing_if = "crate::is_default")]
22    pub extra_arguments: Vec<InstructionArgumentNode>,
23    #[serde(default, skip_serializing_if = "crate::is_default")]
24    pub remaining_accounts: Vec<InstructionRemainingAccountsNode>,
25    #[serde(default, skip_serializing_if = "crate::is_default")]
26    pub byte_deltas: Vec<InstructionByteDeltaNode>,
27    #[serde(default, skip_serializing_if = "crate::is_default")]
28    pub discriminators: Vec<DiscriminatorNode>,
29    #[serde(default, skip_serializing_if = "crate::is_default")]
30    pub sub_instructions: Vec<InstructionNode>,
31}
32
33#[derive(Debug, PartialEq, Eq, Clone, Copy, Default, Serialize, Deserialize)]
34#[serde(rename_all = "camelCase")]
35pub enum InstructionOptionalAccountStrategy {
36    Omitted,
37    #[default]
38    ProgramId,
39}
40
41#[cfg(test)]
42mod tests {
43    use super::*;
44
45    #[test]
46    fn empty_instruction() {
47        let node = InstructionNode {
48            name: "myInstruction".into(),
49            ..InstructionNode::default()
50        };
51        assert_eq!(node.name, CamelCaseString::new("myInstruction"));
52        assert_eq!(node.docs, Docs::default());
53        assert_eq!(
54            node.optional_account_strategy,
55            InstructionOptionalAccountStrategy::ProgramId
56        );
57        assert_eq!(node.accounts, vec![]);
58        assert_eq!(node.arguments, vec![]);
59        assert_eq!(node.extra_arguments, vec![]);
60        assert_eq!(node.remaining_accounts, vec![]);
61        assert_eq!(node.byte_deltas, vec![]);
62        assert_eq!(node.discriminators, vec![]);
63        assert_eq!(node.sub_instructions, vec![]);
64    }
65
66    #[test]
67    fn instruction_with_sub_instructions() {
68        let node = InstructionNode {
69            name: "myInstruction".into(),
70            sub_instructions: vec![
71                InstructionNode {
72                    name: "mySubInstructionA".into(),
73                    ..InstructionNode::default()
74                },
75                InstructionNode {
76                    name: "mySubInstructionB".into(),
77                    ..InstructionNode::default()
78                },
79            ],
80            ..InstructionNode::default()
81        };
82        assert_eq!(
83            node.sub_instructions,
84            vec![
85                InstructionNode {
86                    name: "mySubInstructionA".into(),
87                    ..InstructionNode::default()
88                },
89                InstructionNode {
90                    name: "mySubInstructionB".into(),
91                    ..InstructionNode::default()
92                },
93            ]
94        );
95    }
96
97    #[test]
98    fn to_json() {
99        let node = InstructionNode {
100            name: "myInstruction".into(),
101            ..InstructionNode::default()
102        };
103        let json = serde_json::to_string(&node).unwrap();
104        assert_eq!(
105            json,
106            r#"{"kind":"instructionNode","name":"myInstruction","accounts":[],"arguments":[]}"#
107        );
108    }
109
110    #[test]
111    fn from_json() {
112        let json =
113            r#"{"kind":"instructionNode","name":"myInstruction","accounts":[],"arguments":[]}"#;
114        let node: InstructionNode = serde_json::from_str(json).unwrap();
115        assert_eq!(
116            node,
117            InstructionNode {
118                name: "myInstruction".into(),
119                ..InstructionNode::default()
120            }
121        );
122    }
123}