rustledger_plugin/native/plugins/
check_commodity.rs1use std::collections::HashSet;
4
5use crate::types::{DirectiveData, PluginError, PluginInput, PluginOutput};
6
7use super::super::NativePlugin;
8
9pub struct CheckCommodityPlugin;
11
12impl NativePlugin for CheckCommodityPlugin {
13 fn name(&self) -> &'static str {
14 "check_commodity"
15 }
16
17 fn description(&self) -> &'static str {
18 "Verify all commodities are declared"
19 }
20
21 fn process(&self, input: PluginInput) -> PluginOutput {
22 let mut declared_commodities: HashSet<String> = HashSet::new();
23 let mut used_commodities: HashSet<String> = HashSet::new();
24 let mut errors = Vec::new();
25
26 for wrapper in &input.directives {
28 if wrapper.directive_type == "commodity"
29 && let DirectiveData::Commodity(ref comm) = wrapper.data
30 {
31 declared_commodities.insert(comm.currency.clone());
32 }
33 }
34
35 for wrapper in &input.directives {
37 match &wrapper.data {
38 DirectiveData::Transaction(txn) => {
39 for posting in &txn.postings {
40 if let Some(ref units) = posting.units {
41 used_commodities.insert(units.currency.clone());
42 }
43 if let Some(ref cost) = posting.cost
44 && let Some(ref currency) = cost.currency
45 {
46 used_commodities.insert(currency.clone());
47 }
48 }
49 }
50 DirectiveData::Balance(bal) => {
51 used_commodities.insert(bal.amount.currency.clone());
52 }
53 DirectiveData::Price(price) => {
54 used_commodities.insert(price.currency.clone());
55 used_commodities.insert(price.amount.currency.clone());
56 }
57 _ => {}
58 }
59 }
60
61 for currency in &used_commodities {
63 if !declared_commodities.contains(currency) {
64 errors.push(PluginError::warning(format!(
65 "commodity '{currency}' used but not declared"
66 )));
67 }
68 }
69
70 PluginOutput {
71 directives: input.directives,
72 errors,
73 }
74 }
75}