#[derive(Clone, Copy)]
pub struct AccountFieldSchema {
pub name: &'static str,
pub kind: &'static str,
pub mutable: bool,
pub signer: bool,
pub layout: Option<&'static str>,
pub policy: Option<&'static str>,
pub seeds: &'static [&'static str],
pub optional: bool,
}
#[derive(Clone, Copy)]
pub struct ContextSchema {
pub name: &'static str,
pub fields: &'static [AccountFieldSchema],
pub policy_names: &'static [&'static str],
pub receipts_expected: bool,
pub mutation_classes: &'static [&'static str],
}
pub struct ContextExplain {
pub context_name: &'static str,
pub fields: &'static [AccountFieldSchema],
pub policies: &'static [&'static str],
pub receipts_expected: bool,
pub mutation_classes: &'static [&'static str],
}
impl ContextExplain {
pub fn from_schema(schema: Option<&'static ContextSchema>) -> Self {
match schema {
Some(s) => Self {
context_name: s.name,
fields: s.fields,
policies: s.policy_names,
receipts_expected: s.receipts_expected,
mutation_classes: s.mutation_classes,
},
None => Self {
context_name: "(unknown)",
fields: &[],
policies: &[],
receipts_expected: false,
mutation_classes: &[],
},
}
}
pub fn account_count(&self) -> usize {
self.fields.len()
}
pub fn signer_count(&self) -> usize {
self.fields.iter().filter(|f| f.signer).count()
}
pub fn writable_count(&self) -> usize {
self.fields.iter().filter(|f| f.mutable).count()
}
}
pub struct AccountExplain {
pub name: &'static str,
pub kind: &'static str,
pub layout: Option<&'static str>,
pub policy: Option<&'static str>,
pub mutable: bool,
pub signer: bool,
pub optional: bool,
}
#[cfg(test)]
mod tests {
extern crate alloc;
use super::*;
static TEST_FIELDS: &[AccountFieldSchema] = &[
AccountFieldSchema {
name: "authority",
kind: "Signer",
mutable: true,
signer: true,
layout: None,
policy: None,
seeds: &[],
optional: false,
},
AccountFieldSchema {
name: "vault",
kind: "HopperAccount",
mutable: true,
signer: false,
layout: Some("VaultState"),
policy: Some("TREASURY_WRITE"),
seeds: &["b\"vault\"", "authority"],
optional: false,
},
AccountFieldSchema {
name: "system_program",
kind: "ProgramRef",
mutable: false,
signer: false,
layout: None,
policy: None,
seeds: &[],
optional: false,
},
];
static TEST_SCHEMA: ContextSchema = ContextSchema {
name: "Deposit",
fields: TEST_FIELDS,
policy_names: &["TREASURY_WRITE"],
receipts_expected: true,
mutation_classes: &["Financial"],
};
#[test]
fn context_explain_from_schema() {
let explain = ContextExplain::from_schema(Some(&TEST_SCHEMA));
assert_eq!(explain.context_name, "Deposit");
assert_eq!(explain.fields.len(), 3);
assert_eq!(explain.fields[0].name, "authority");
assert_eq!(explain.fields[1].name, "vault");
assert_eq!(explain.policies.len(), 1);
assert_eq!(explain.policies[0], "TREASURY_WRITE");
assert!(explain.receipts_expected);
assert_eq!(explain.mutation_classes.len(), 1);
assert_eq!(explain.mutation_classes[0], "Financial");
assert_eq!(explain.account_count(), 3);
assert_eq!(explain.signer_count(), 1);
assert_eq!(explain.writable_count(), 2);
}
#[test]
fn context_explain_from_none() {
let explain = ContextExplain::from_schema(None);
assert_eq!(explain.context_name, "(unknown)");
assert!(!explain.receipts_expected);
assert!(explain.policies.is_empty());
assert_eq!(explain.account_count(), 0);
assert_eq!(explain.signer_count(), 0);
assert_eq!(explain.writable_count(), 0);
}
#[test]
fn account_field_schema_fields() {
assert_eq!(TEST_FIELDS[0].name, "authority");
assert!(TEST_FIELDS[0].signer);
assert!(TEST_FIELDS[0].mutable);
assert!(TEST_FIELDS[0].layout.is_none());
assert_eq!(TEST_FIELDS[1].name, "vault");
assert!(!TEST_FIELDS[1].signer);
assert!(TEST_FIELDS[1].mutable);
assert_eq!(TEST_FIELDS[1].layout, Some("VaultState"));
assert_eq!(TEST_FIELDS[1].seeds.len(), 2);
}
#[test]
fn context_schema_field_count() {
assert_eq!(TEST_SCHEMA.fields.len(), 3);
assert_eq!(TEST_SCHEMA.name, "Deposit");
assert_eq!(TEST_SCHEMA.policy_names.len(), 1);
assert_eq!(TEST_SCHEMA.mutation_classes.len(), 1);
}
}