Skip to main content

lattice_mode/
plugin_meta_sink.rs

1//! `PluginMetaSink` — the generic seam the plugin loader writes plugin
2//! provenance through (PL8.B).
3//!
4//! The host owns a `PluginMetaRegistry` (host-issued `PluginId` → manifest name +
5//! doc) that backs provenance display (`SourceLayer::Plugin(id)` renders as
6//! the manifest name) and the loaded-plugin introspection surfaces
7//! (`:list-plugins` / `:describe-plugin`). The plugin loader
8//! (`lattice-plugin-loader`) must populate it as each plugin loads — but the
9//! loader cannot name the host's `PluginMetaRegistry` type without a dependency
10//! cycle. So the host implements this trait over its registry and registers the
11//! same instance as a [`PluginMetaSinkHandle`] service; the loader looks the
12//! handle up ([`SubsystemBoot::service`](crate::SubsystemBoot::service)) and
13//! writes through it. Mirrors the `PluginEventSink` type-erasure pattern that
14//! keeps `lattice-runtime` free of a plugin-host dep.
15
16use std::sync::Arc;
17
18/// The host-owned plugin-metadata store, viewed as a write seam. Implemented by
19/// the host's `PluginMetaRegistry`; consumed by the plugin loader. All methods
20/// take `&self` (the store is interior-mutable behind a lock) so the shared
21/// `Arc` handle suffices — no `&mut` plumbing across the boundary.
22pub trait PluginMetaSink: Send + Sync {
23    /// Record a loaded plugin's manifest name + doc against its host-issued
24    /// numeric id, so `SourceLayer::Plugin(id)` provenance renders as the name
25    /// and `:list-plugins` shows it. Called once per plugin at load.
26    fn register_plugin(&self, id: u32, name: String, doc: String);
27
28    /// Record that `seam_ids` all belong to the plugin registered as `primary`.
29    ///
30    /// A plugin is instantiated once per seam and each instance gets its own
31    /// host id; `primary` (the first) is its identity, but a contribution is
32    /// stamped with the id of the seam that made it. Without this, a binding
33    /// the `keymap` seam registered renders as `<plugin:29>` while the same
34    /// plugin's grammar renders as its name. Aliases only — `:list-plugins`
35    /// must still show the plugin once. `unregister_plugin(primary)` drops
36    /// them.
37    ///
38    /// Defaults to a no-op so a test sink need not care; the host's registry
39    /// is the one implementation that must.
40    fn register_seam_ids(&self, primary: u32, seam_ids: &[u32]) {
41        let _ = (primary, seam_ids);
42    }
43
44    /// Forget a plugin's metadata (unload / reload). Idempotent — a
45    /// never-registered or already-removed id is a no-op.
46    fn unregister_plugin(&self, id: u32);
47}
48
49/// The service alias the host registers and the loader looks up. Per the
50/// `ServiceRegistry` Arc/TypeId rule, register and look up with this exact type.
51pub type PluginMetaSinkHandle = Arc<dyn PluginMetaSink>;