Skip to main content

nemo_flow_adaptive/acg/
plugin_registry.rs

1// SPDX-FileCopyrightText: Copyright (c) 2026, NVIDIA CORPORATION & AFFILIATES. All rights reserved.
2// SPDX-License-Identifier: Apache-2.0
3
4//! Plugin registry for storing and retrieving provider plugins.
5//!
6//! [`PluginRegistry`] is an instance-scoped (not global static) store for
7//! [`ProviderPlugin`] trait objects. Plugins are stored as
8//! `Arc<dyn ProviderPlugin>` keyed by plugin ID.
9//!
10//! Instance-scoped design is more testable and can be promoted to a static
11//! later if needed.
12
13use std::collections::HashMap;
14use std::sync::Arc;
15
16use crate::acg::error::{AcgError, Result};
17use crate::acg::plugin::ProviderPlugin;
18
19/// Registry for storing and retrieving provider plugins.
20///
21/// Instance-scoped (not a global static) for testability. Stores plugins
22/// as `Arc<dyn ProviderPlugin>` keyed by plugin ID.
23pub struct PluginRegistry {
24    plugins: HashMap<String, Arc<dyn ProviderPlugin>>,
25}
26
27impl PluginRegistry {
28    /// Create a new empty plugin registry.
29    pub fn new() -> Self {
30        Self {
31            plugins: HashMap::new(),
32        }
33    }
34
35    /// Register a plugin in the registry.
36    ///
37    /// Returns `Err(AcgError::PluginAlreadyRegistered)` if a plugin with
38    /// the same ID is already registered.
39    pub fn register(&mut self, plugin: Arc<dyn ProviderPlugin>) -> Result<()> {
40        let id = plugin.plugin_id().to_string();
41        if self.plugins.contains_key(&id) {
42            return Err(AcgError::PluginAlreadyRegistered(id));
43        }
44        self.plugins.insert(id, plugin);
45        Ok(())
46    }
47
48    /// Retrieve a plugin by ID, returning an `Arc` clone.
49    pub fn get(&self, plugin_id: &str) -> Option<Arc<dyn ProviderPlugin>> {
50        self.plugins.get(plugin_id).cloned()
51    }
52
53    /// Return a sorted list of all registered plugin IDs.
54    pub fn list_plugin_ids(&self) -> Vec<String> {
55        let mut ids: Vec<String> = self.plugins.keys().cloned().collect();
56        ids.sort();
57        ids
58    }
59
60    /// Remove a plugin from the registry, returning `true` if it was present.
61    pub fn deregister(&mut self, plugin_id: &str) -> bool {
62        self.plugins.remove(plugin_id).is_some()
63    }
64
65    /// Return the number of registered plugins.
66    pub fn len(&self) -> usize {
67        self.plugins.len()
68    }
69
70    /// Return `true` if the registry contains no plugins.
71    pub fn is_empty(&self) -> bool {
72        self.plugins.is_empty()
73    }
74}
75
76impl Default for PluginRegistry {
77    fn default() -> Self {
78        Self::new()
79    }
80}
81
82impl std::fmt::Debug for PluginRegistry {
83    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
84        f.debug_struct("PluginRegistry")
85            .field("plugin_ids", &self.list_plugin_ids())
86            .finish()
87    }
88}
89
90#[cfg(test)]
91#[path = "../../tests/unit/acg/plugin_registry_tests.rs"]
92mod tests;