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