codama_nodes/
instruction_node.rs1use 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 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 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}