Skip to main content

amalgam/
plugins.rs

1//! The plugin seam.
2//!
3//! A [`Plugin`] observes the cache's lifecycle and event stream. This is the
4//! Rust counterpart of FusionCache's `IFusionCachePlugin`. Plugins are notified
5//! synchronously on the (already cheap, non-blocking) event path — a plugin must
6//! not block; offload real work to its own task/channel.
7
8use std::sync::Arc;
9
10use crate::events::CacheEvent;
11
12/// A cache plugin: observes events and lifecycle transitions.
13///
14/// Register plugins via [`CacheBuilder::plugin`](crate::CacheBuilder::plugin).
15pub trait Plugin: Send + Sync {
16    /// A short name used in diagnostics.
17    fn name(&self) -> &str;
18
19    /// Called once when the owning cache is built and the plugin is attached.
20    fn on_start(&self) {}
21
22    /// Called for every [`CacheEvent`] the cache emits.
23    fn on_event(&self, event: &CacheEvent);
24}
25
26/// Holds the registered plugins and fans events out to them.
27#[derive(Clone, Default)]
28pub struct PluginHost {
29    plugins: Arc<[Arc<dyn Plugin>]>,
30}
31
32impl PluginHost {
33    /// Builds a host from a list of plugins, calling `on_start` for each.
34    #[must_use]
35    pub fn new(plugins: Vec<Arc<dyn Plugin>>) -> Self {
36        for plugin in &plugins {
37            plugin.on_start();
38        }
39        Self {
40            plugins: plugins.into(),
41        }
42    }
43
44    /// `true` if no plugins are registered (lets the cache skip work).
45    #[must_use]
46    pub fn is_empty(&self) -> bool {
47        self.plugins.is_empty()
48    }
49
50    /// Notifies every plugin of an event.
51    pub fn notify(&self, event: &CacheEvent) {
52        for plugin in self.plugins.iter() {
53            plugin.on_event(event);
54        }
55    }
56}
57
58impl std::fmt::Debug for PluginHost {
59    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
60        f.debug_struct("PluginHost")
61            .field("count", &self.plugins.len())
62            .finish()
63    }
64}