codama_nodes/
instruction_node.rs

1use crate::{
2    CamelCaseString, DiscriminatorNode, Docs, HasName, InstructionAccountNode,
3    InstructionArgumentNode, 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
33impl HasName for InstructionNode {
34    fn name(&self) -> &CamelCaseString {
35        &self.name
36    }
37}
38
39#[derive(Debug, PartialEq, Eq, Clone, Copy, Default, Serialize, Deserialize)]
40#[serde(rename_all = "camelCase")]
41pub enum InstructionOptionalAccountStrategy {
42    Omitted,
43    #[default]
44    ProgramId,
45}
46
47#[cfg(test)]
48mod tests {
49    use super::*;
50
51    #[test]
52    fn empty_instruction() {
53        let node = InstructionNode {
54            name: "myInstruction".into(),
55            ..InstructionNode::default()
56        };
57        assert_eq!(node.name, CamelCaseString::new("myInstruction"));
58        assert_eq!(node.docs, Docs::default());
59        assert_eq!(
60            node.optional_account_strategy,
61            InstructionOptionalAccountStrategy::ProgramId
62        );
63        assert_eq!(node.accounts, vec![]);
64        assert_eq!(node.arguments, vec![]);
65        assert_eq!(node.extra_arguments, vec![]);
66        assert_eq!(node.remaining_accounts, vec![]);
67        assert_eq!(node.byte_deltas, vec![]);
68        assert_eq!(node.discriminators, vec![]);
69        assert_eq!(node.sub_instructions, vec![]);
70    }
71
72    #[test]
73    fn instruction_with_sub_instructions() {
74        let node = InstructionNode {
75            name: "myInstruction".into(),
76            sub_instructions: vec![
77                InstructionNode {
78                    name: "mySubInstructionA".into(),
79                    ..InstructionNode::default()
80                },
81                InstructionNode {
82                    name: "mySubInstructionB".into(),
83                    ..InstructionNode::default()
84                },
85            ],
86            ..InstructionNode::default()
87        };
88        assert_eq!(
89            node.sub_instructions,
90            vec![
91                InstructionNode {
92                    name: "mySubInstructionA".into(),
93                    ..InstructionNode::default()
94                },
95                InstructionNode {
96                    name: "mySubInstructionB".into(),
97                    ..InstructionNode::default()
98                },
99            ]
100        );
101    }
102
103    #[test]
104    fn to_json() {
105        let node = InstructionNode {
106            name: "myInstruction".into(),
107            ..InstructionNode::default()
108        };
109        let json = serde_json::to_string(&node).unwrap();
110        assert_eq!(
111            json,
112            r#"{"kind":"instructionNode","name":"myInstruction","accounts":[],"arguments":[]}"#
113        );
114    }
115
116    #[test]
117    fn from_json() {
118        let json =
119            r#"{"kind":"instructionNode","name":"myInstruction","accounts":[],"arguments":[]}"#;
120        let node: InstructionNode = serde_json::from_str(json).unwrap();
121        assert_eq!(
122            node,
123            InstructionNode {
124                name: "myInstruction".into(),
125                ..InstructionNode::default()
126            }
127        );
128    }
129}