1#[derive(Clone, Copy)]
5pub struct AccountFieldSchema {
6 pub name: &'static str,
8 pub kind: &'static str,
10 pub mutable: bool,
12 pub signer: bool,
14 pub layout: Option<&'static str>,
16 pub policy: Option<&'static str>,
18 pub seeds: &'static [&'static str],
20 pub optional: bool,
22}
23
24#[derive(Clone, Copy)]
26pub struct ContextSchema {
27 pub name: &'static str,
29 pub fields: &'static [AccountFieldSchema],
31 pub policy_names: &'static [&'static str],
33 pub receipts_expected: bool,
35 pub mutation_classes: &'static [&'static str],
37}
38
39pub struct ContextExplain {
41 pub context_name: &'static str,
43 pub fields: &'static [AccountFieldSchema],
45 pub policies: &'static [&'static str],
47 pub receipts_expected: bool,
49 pub mutation_classes: &'static [&'static str],
51}
52
53impl ContextExplain {
54 pub fn from_schema(schema: Option<&'static ContextSchema>) -> Self {
56 match schema {
57 Some(s) => Self {
58 context_name: s.name,
59 fields: s.fields,
60 policies: s.policy_names,
61 receipts_expected: s.receipts_expected,
62 mutation_classes: s.mutation_classes,
63 },
64 None => Self {
65 context_name: "(unknown)",
66 fields: &[],
67 policies: &[],
68 receipts_expected: false,
69 mutation_classes: &[],
70 },
71 }
72 }
73
74 pub fn account_count(&self) -> usize {
76 self.fields.len()
77 }
78
79 pub fn signer_count(&self) -> usize {
81 self.fields.iter().filter(|f| f.signer).count()
82 }
83
84 pub fn writable_count(&self) -> usize {
86 self.fields.iter().filter(|f| f.mutable).count()
87 }
88}
89
90pub struct AccountExplain {
92 pub name: &'static str,
94 pub kind: &'static str,
96 pub layout: Option<&'static str>,
98 pub policy: Option<&'static str>,
100 pub mutable: bool,
102 pub signer: bool,
104 pub optional: bool,
106}
107
108#[cfg(test)]
109mod tests {
110 extern crate alloc;
111 use super::*;
112
113 static TEST_FIELDS: &[AccountFieldSchema] = &[
114 AccountFieldSchema {
115 name: "authority",
116 kind: "Signer",
117 mutable: true,
118 signer: true,
119 layout: None,
120 policy: None,
121 seeds: &[],
122 optional: false,
123 },
124 AccountFieldSchema {
125 name: "vault",
126 kind: "HopperAccount",
127 mutable: true,
128 signer: false,
129 layout: Some("VaultState"),
130 policy: Some("TREASURY_WRITE"),
131 seeds: &["b\"vault\"", "authority"],
132 optional: false,
133 },
134 AccountFieldSchema {
135 name: "system_program",
136 kind: "ProgramRef",
137 mutable: false,
138 signer: false,
139 layout: None,
140 policy: None,
141 seeds: &[],
142 optional: false,
143 },
144 ];
145
146 static TEST_SCHEMA: ContextSchema = ContextSchema {
147 name: "Deposit",
148 fields: TEST_FIELDS,
149 policy_names: &["TREASURY_WRITE"],
150 receipts_expected: true,
151 mutation_classes: &["Financial"],
152 };
153
154 #[test]
155 fn context_explain_from_schema() {
156 let explain = ContextExplain::from_schema(Some(&TEST_SCHEMA));
157 assert_eq!(explain.context_name, "Deposit");
158 assert_eq!(explain.fields.len(), 3);
159 assert_eq!(explain.fields[0].name, "authority");
160 assert_eq!(explain.fields[1].name, "vault");
161 assert_eq!(explain.policies.len(), 1);
162 assert_eq!(explain.policies[0], "TREASURY_WRITE");
163 assert!(explain.receipts_expected);
164 assert_eq!(explain.mutation_classes.len(), 1);
165 assert_eq!(explain.mutation_classes[0], "Financial");
166 assert_eq!(explain.account_count(), 3);
167 assert_eq!(explain.signer_count(), 1);
168 assert_eq!(explain.writable_count(), 2);
169 }
170
171 #[test]
172 fn context_explain_from_none() {
173 let explain = ContextExplain::from_schema(None);
174 assert_eq!(explain.context_name, "(unknown)");
175 assert!(!explain.receipts_expected);
176 assert!(explain.policies.is_empty());
177 assert_eq!(explain.account_count(), 0);
178 assert_eq!(explain.signer_count(), 0);
179 assert_eq!(explain.writable_count(), 0);
180 }
181
182 #[test]
183 fn account_field_schema_fields() {
184 assert_eq!(TEST_FIELDS[0].name, "authority");
185 assert!(TEST_FIELDS[0].signer);
186 assert!(TEST_FIELDS[0].mutable);
187 assert!(TEST_FIELDS[0].layout.is_none());
188
189 assert_eq!(TEST_FIELDS[1].name, "vault");
190 assert!(!TEST_FIELDS[1].signer);
191 assert!(TEST_FIELDS[1].mutable);
192 assert_eq!(TEST_FIELDS[1].layout, Some("VaultState"));
193 assert_eq!(TEST_FIELDS[1].seeds.len(), 2);
194 }
195
196 #[test]
197 fn context_schema_field_count() {
198 assert_eq!(TEST_SCHEMA.fields.len(), 3);
199 assert_eq!(TEST_SCHEMA.name, "Deposit");
200 assert_eq!(TEST_SCHEMA.policy_names.len(), 1);
201 assert_eq!(TEST_SCHEMA.mutation_classes.len(), 1);
202 }
203}