Skip to main content

rustledger_plugin/native/
mod.rs

1//! Native (non-WASM) plugin support.
2//!
3//! These plugins run as native Rust code for maximum performance.
4//! They implement the same interface as WASM plugins.
5
6mod plugins;
7
8pub use plugins::*;
9
10use crate::types::PluginInput;
11use crate::types::PluginOutput;
12
13/// Trait for native plugins.
14pub trait NativePlugin: Send + Sync {
15    /// Plugin name.
16    fn name(&self) -> &'static str;
17
18    /// Plugin description.
19    fn description(&self) -> &'static str;
20
21    /// Process directives and return modified directives + errors.
22    fn process(&self, input: PluginInput) -> PluginOutput;
23}
24
25/// Registry of built-in native plugins.
26pub struct NativePluginRegistry {
27    plugins: Vec<Box<dyn NativePlugin>>,
28}
29
30impl NativePluginRegistry {
31    /// Create a new registry with all built-in plugins.
32    pub fn new() -> Self {
33        Self {
34            plugins: vec![
35                Box::new(ImplicitPricesPlugin),
36                Box::new(CheckCommodityPlugin),
37                Box::new(AutoTagPlugin::new()),
38                Box::new(AutoAccountsPlugin),
39                Box::new(LeafOnlyPlugin),
40                Box::new(NoDuplicatesPlugin),
41                Box::new(OneCommodityPlugin),
42                Box::new(UniquePricesPlugin),
43                Box::new(CheckClosingPlugin),
44                Box::new(CloseTreePlugin),
45                Box::new(CoherentCostPlugin),
46                Box::new(SellGainsPlugin),
47                Box::new(PedanticPlugin),
48                Box::new(UnrealizedPlugin::new()),
49                Box::new(NoUnusedPlugin),
50                Box::new(CheckDrainedPlugin),
51                Box::new(CommodityAttrPlugin::new()),
52                Box::new(CheckAverageCostPlugin::new()),
53                Box::new(CurrencyAccountsPlugin::new()),
54            ],
55        }
56    }
57
58    /// Find a plugin by name.
59    pub fn find(&self, name: &str) -> Option<&dyn NativePlugin> {
60        // Check for beancount.plugins.* prefix
61        let name = name.strip_prefix("beancount.plugins.").unwrap_or(name);
62
63        self.plugins
64            .iter()
65            .find(|p| p.name() == name)
66            .map(std::convert::AsRef::as_ref)
67    }
68
69    /// List all available plugins.
70    pub fn list(&self) -> Vec<&dyn NativePlugin> {
71        self.plugins.iter().map(AsRef::as_ref).collect()
72    }
73
74    /// Check if a name refers to a built-in plugin.
75    pub fn is_builtin(name: &str) -> bool {
76        let name = name.strip_prefix("beancount.plugins.").unwrap_or(name);
77
78        matches!(
79            name,
80            "implicit_prices"
81                | "check_commodity"
82                | "auto_tag"
83                | "auto_accounts"
84                | "leafonly"
85                | "noduplicates"
86                | "onecommodity"
87                | "unique_prices"
88                | "check_closing"
89                | "close_tree"
90                | "coherent_cost"
91                | "sellgains"
92                | "pedantic"
93                | "unrealized"
94                | "nounused"
95                | "check_drained"
96                | "commodity_attr"
97                | "check_average_cost"
98                | "currency_accounts"
99        )
100    }
101}
102
103impl Default for NativePluginRegistry {
104    fn default() -> Self {
105        Self::new()
106    }
107}