pub struct HookRegistry { /* private fields */ }Expand description
Registry for storing and retrieving hooks.
The HookRegistry provides a central place to register, deregister, and
query hooks from different Plugins, Extension Points and
other qualities.
§Examples
use steckrs::{extension_point, hook::{HookRegistry, Hook, HookID, ExtensionPoint}};
// Define extension points
extension_point!(
Validator: ValidatorTrait;
fn validate(&self, input: &str) -> bool;
);
// Implement extension points
struct MinLengthValidator;
impl ValidatorTrait for MinLengthValidator {
fn validate(&self, input: &str) -> bool {
input.len() >= 3
}
}
struct MaxLengthValidator;
impl ValidatorTrait for MaxLengthValidator {
fn validate(&self, input: &str) -> bool {
input.len() <= 10
}
}
// Create and register hooks
let mut registry = HookRegistry::new();
let min_hook = Hook::<Validator>::new(Box::new(MinLengthValidator), "minhook");
let min_id = HookID::new("plugin1", Validator::id(), Some("min_length"));
let max_hook = Hook::<Validator>::new(Box::new(MaxLengthValidator), "maxhook");
let max_id = HookID::new("plugin1", Validator::id(), Some("max_length"));
registry.register(&min_id, min_hook).unwrap();
registry.register(&max_id, max_hook).unwrap();
// Use the hooks
let hooks = registry.get_by_extension_point::<Validator>();
assert_eq!(hooks.len(), 2);
// Test both validators
let short = "ab";
let good = "jigglypuff";
let long = "this string is too long for the max validator";
dbg!(hooks[0].1.name()); // maxhook
dbg!(hooks[1].1.name()); // minhook
// Only the max len passes for the very short one
assert!(hooks[0].1.inner().validate(short));
assert!(!hooks[1].1.inner().validate(short));
// Both validators pass for good
assert!(hooks[0].1.inner().validate(good));
assert!(hooks[1].1.inner().validate(good));
// Min passes but max fails for long
assert!(!hooks[0].1.inner().validate(long));
assert!(hooks[1].1.inner().validate(long));Implementations§
Source§impl HookRegistry
impl HookRegistry
Sourcepub fn new() -> Self
pub fn new() -> Self
Creates a new empty hook registry.
§Examples
use steckrs::hook::HookRegistry;
let registry = HookRegistry::new();Sourcepub fn register<E: ExtensionPoint>(
&mut self,
id: &HookID,
hook: Hook<E>,
) -> HookResult<()>
pub fn register<E: ExtensionPoint>( &mut self, id: &HookID, hook: Hook<E>, ) -> HookResult<()>
Registers a hook with the given HookID.
§Type Parameters
E: The extension point type
§Parameters
id: The unique identifier for this hookhook: The hook implementation to register
§Errors
Returns a HookError::AlreadyRegistered if a hook with the same ID is already registered.
§Examples
use steckrs::{extension_point, hook::{HookRegistry, Hook, HookID, ExtensionPoint}};
extension_point!(
Serializer: SerializerTrait;
fn serialize(&self, data: &str) -> Vec<u8>;
);
struct ByteSerializer;
impl SerializerTrait for ByteSerializer {
fn serialize(&self, data: &str) -> Vec<u8> {
data.as_bytes().to_vec()
}
}
let mut registry = HookRegistry::new();
let hook = Hook::<Serializer>::new(Box::new(ByteSerializer), "myhook");
let id = HookID::new("byte_plugin", Serializer::id(), None);
registry.register(&id, hook).unwrap();Sourcepub fn deregister(&mut self, id: &HookID) -> Option<BoxedHook>
pub fn deregister(&mut self, id: &HookID) -> Option<BoxedHook>
Deregisters a hook by HookID.
§Parameters
id: The ID of the hook to deregister
§Returns
Some(BoxedHook)if the hook was found and removedNoneif no hook with the given ID was found
§Examples
use steckrs::{extension_point, hook::{HookRegistry, Hook, HookID, ExtensionPoint}};
extension_point!(
Parser: ParserTrait;
fn parse(&self, input: &str) -> bool;
);
struct SimpleParser;
impl ParserTrait for SimpleParser {
fn parse(&self, _: &str) -> bool {
true
}
}
let mut registry = HookRegistry::new();
let hook = Hook::<Parser>::new(Box::new(SimpleParser), "myhook");
let id = HookID::new("parser_plugin", Parser::id(), None);
registry.register(&id, hook).unwrap();
assert!(registry.exists(&id));
let removed = registry.deregister(&id);
assert!(removed.is_some());
assert!(!registry.exists(&id));Sourcepub fn exists(&self, id: &HookID) -> bool
pub fn exists(&self, id: &HookID) -> bool
Checks if a hook with the given HookID exists.
§Parameters
id: The ID to check
§Returns
trueif a hook with the given ID existsfalseotherwise
§Examples
use steckrs::{extension_point, hook::{HookRegistry, Hook, HookID, ExtensionPoint}};
extension_point!(
Handler: HandlerTrait;
fn handle(&self, input: &str) -> String;
);
struct EchoHandler;
impl HandlerTrait for EchoHandler {
fn handle(&self, input: &str) -> String {
input.to_string()
}
}
let mut registry = HookRegistry::new();
let hook = Hook::<Handler>::new(Box::new(EchoHandler), "myhook");
let id = HookID::new("echo_plugin", Handler::id(), None);
assert!(!registry.exists(&id));
registry.register(&id, hook).unwrap();
assert!(registry.exists(&id));Sourcepub fn get<E: ExtensionPoint>(&self, id: &HookID) -> Option<&Hook<E>>
pub fn get<E: ExtensionPoint>(&self, id: &HookID) -> Option<&Hook<E>>
Gets a hook by HookID and extension point type.
§Type Parameters
E: The extension point type
§Parameters
id: The ID of the hook to get
§Returns
Some(&Hook<E>)if the hook was foundNoneif no hook with the given ID was found for the extension point
§Examples
use steckrs::{extension_point, hook::{HookRegistry, Hook, HookID, ExtensionPoint}};
extension_point!(
Encoder: EncoderTrait;
fn encode(&self, input: &str) -> Vec<u8>;
);
struct Base64Encoder;
impl EncoderTrait for Base64Encoder {
fn encode(&self, input: &str) -> Vec<u8> {
input.as_bytes().to_vec() // Simplified for example
}
}
let mut registry = HookRegistry::new();
let hook = Hook::<Encoder>::new(Box::new(Base64Encoder), "myhook");
let id = HookID::new("encoder_plugin", Encoder::id(), None);
registry.register(&id, hook).unwrap();
let retrieved = registry.get::<Encoder>(&id);
assert!(retrieved.is_some());
assert_eq!(retrieved.unwrap().inner().encode("test").len(), 4);Sourcepub fn get_mut<E: ExtensionPoint>(
&mut self,
id: &HookID,
) -> Option<&mut Hook<E>>
pub fn get_mut<E: ExtensionPoint>( &mut self, id: &HookID, ) -> Option<&mut Hook<E>>
Gets a mutable hook by HookID and extension point type.
§Type Parameters
E: The extension point type
§Parameters
id: The ID of the hook to get
§Returns
Some(&mut Hook<E>)if the hook was foundNoneif no hook with the given ID was found for the extension point
§Examples
use steckrs::{extension_point, hook::{HookRegistry, Hook, HookID, ExtensionPoint}};
extension_point!(
Encoder: EncoderTrait;
fn encode(&mut self, input: &str) -> Vec<u8>;
);
struct Base64Encoder;
impl EncoderTrait for Base64Encoder {
fn encode(&mut self, input: &str) -> Vec<u8> {
input.as_bytes().to_vec() // Simplified for example
}
}
let mut registry = HookRegistry::new();
let mut hook = Hook::<Encoder>::new(Box::new(Base64Encoder), "myhook");
let id = HookID::new("encoder_plugin", Encoder::id(), None);
registry.register(&id, hook).unwrap();
let mut retrieved = registry.get_mut::<Encoder>(&id);
assert!(retrieved.is_some());
assert_eq!(retrieved.unwrap().inner_mut().encode("test").len(), 4);Sourcepub fn get_by_id(&self, id: &HookID) -> Option<(&HookID, &BoxedHook)>
pub fn get_by_id(&self, id: &HookID) -> Option<(&HookID, &BoxedHook)>
Gets a hook by HookID.
§Parameters
id: The ID of the hook to get
§Returns
Some(&BoxedHook)if the hook was foundNoneif no hook with the given ID was found
§Examples
use steckrs::{extension_point, hook::{HookRegistry, Hook, HookID, ExtensionPoint}};
extension_point!(
Hasher: HasherTrait;
fn hash(&self, input: &str) -> u64;
);
struct SimpleHasher;
impl HasherTrait for SimpleHasher {
fn hash(&self, input: &str) -> u64 {
input.len() as u64 // Simplified hash function
}
}
let mut registry = HookRegistry::new();
let hook = Hook::<Hasher>::new(Box::new(SimpleHasher), "myhook");
let id = HookID::new("hasher_plugin", Hasher::id(), None);
registry.register(&id, hook).unwrap();
let retrieved = registry.get_by_id(&id);
assert!(retrieved.is_some());Sourcepub fn get_by_id_mut(
&mut self,
id: &HookID,
) -> Option<(&HookID, &mut BoxedHook)>
pub fn get_by_id_mut( &mut self, id: &HookID, ) -> Option<(&HookID, &mut BoxedHook)>
Gets a mutable hook by HookID.
§Parameters
id: The ID of the hook to get
§Returns
Some(&mut BoxedHook)if the hook was foundNoneif no hook with the given ID was found
§Examples
use steckrs::{extension_point, hook::{HookRegistry, Hook, HookID, ExtensionPoint}};
extension_point!(
Hasher: HasherTrait;
fn hash(&mut self, input: &str) -> u64;
);
struct SimpleHasher;
impl HasherTrait for SimpleHasher {
fn hash(&mut self, input: &str) -> u64 {
input.len() as u64 // Simplified hash function
}
}
let mut registry = HookRegistry::new();
let mut hook = Hook::<Hasher>::new(Box::new(SimpleHasher), "myhook");
let id = HookID::new("hasher_plugin", Hasher::id(), None);
registry.register(&id, hook).unwrap();
let mut retrieved = registry.get_by_id_mut(&id);
assert!(retrieved.is_some());Sourcepub fn get_by_plugin(&self, plugin_id: PluginID) -> Vec<(&HookID, &BoxedHook)>
pub fn get_by_plugin(&self, plugin_id: PluginID) -> Vec<(&HookID, &BoxedHook)>
Gets all hooks registered by a specific Plugin.
§Parameters
plugin_id: ThePluginIDof the plugin
§Returns
A vector of references to all hooks registered by the plugin
§Examples
use steckrs::{extension_point, hook::{HookRegistry, Hook, HookID, ExtensionPoint}};
extension_point!(
Formatter: FormatterTrait;
fn format(&self, input: &str) -> String;
);
extension_point!(
Parser: ParserTrait;
fn parse(&self, input: &str) -> bool;
);
struct JsonFormatter;
impl FormatterTrait for JsonFormatter {
fn format(&self, input: &str) -> String {
format!("{{\"data\":\"{}\"}}", input)
}
}
struct JsonParser;
impl ParserTrait for JsonParser {
fn parse(&self, _: &str) -> bool {
true
}
}
let mut registry = HookRegistry::new();
let plugin_id = "json_plugin";
let formatter_hook = Hook::<Formatter>::new(Box::new(JsonFormatter), "formathook");
let formatter_id = HookID::new(plugin_id, Formatter::id(), None);
let parser_hook = Hook::<Parser>::new(Box::new(JsonParser), "parsehook");
let parser_id = HookID::new(plugin_id, Parser::id(), None);
registry.register(&formatter_id, formatter_hook).unwrap();
registry.register(&parser_id, parser_hook).unwrap();
let plugin_hooks = registry.get_by_plugin(plugin_id);
assert_eq!(plugin_hooks.len(), 2);Sourcepub fn get_by_plugin_mut(
&mut self,
plugin_id: PluginID,
) -> Vec<(&HookID, &mut BoxedHook)>
pub fn get_by_plugin_mut( &mut self, plugin_id: PluginID, ) -> Vec<(&HookID, &mut BoxedHook)>
Gets all hooks registered by a specific Plugin, mutable.
§Parameters
plugin_id: ThePluginIDof the plugin
§Returns
A vector of mutable references to all hooks registered by the plugin
§Examples
use steckrs::{extension_point, hook::{HookRegistry, Hook, HookID, ExtensionPoint}};
extension_point!(
Formatter: FormatterTrait;
fn format(&mut self, input: &str) -> String;
);
extension_point!(
Parser: ParserTrait;
fn parse(&mut self, input: &str) -> bool;
);
struct JsonFormatter;
impl FormatterTrait for JsonFormatter {
fn format(&mut self, input: &str) -> String {
format!("{{\"data\":\"{}\"}}", input)
}
}
struct JsonParser;
impl ParserTrait for JsonParser {
fn parse(&mut self, _: &str) -> bool {
true
}
}
let mut registry = HookRegistry::new();
let plugin_id = "json_plugin";
let formatter_hook = Hook::<Formatter>::new(Box::new(JsonFormatter), "formathook");
let formatter_id = HookID::new(plugin_id, Formatter::id(), None);
let parser_hook = Hook::<Parser>::new(Box::new(JsonParser), "parsehook");
let parser_id = HookID::new(plugin_id, Parser::id(), None);
registry.register(&formatter_id, formatter_hook).unwrap();
registry.register(&parser_id, parser_hook).unwrap();
let mut plugin_hooks = registry.get_by_plugin_mut(plugin_id);
assert_eq!(plugin_hooks.len(), 2);Sourcepub fn get_by_filter<F>(&self, f: F) -> Vec<(&HookID, &BoxedHook)>
pub fn get_by_filter<F>(&self, f: F) -> Vec<(&HookID, &BoxedHook)>
Gets hooks that match a filter function.
§Parameters
f: A function that takes a reference to a hook ID and hook, and returns a boolean
§Returns
A vector of references to hooks that match the filter
§Examples
use steckrs::{extension_point, hook::{HookRegistry, Hook, HookID, ExtensionPoint}};
extension_point!(
Logger: LoggerTrait;
fn log(&self, level: &str, message: &str);
);
struct ConsoleLogger;
impl LoggerTrait for ConsoleLogger {
fn log(&self, level: &str, message: &str) {
// In a real implementation, this would print to console
}
}
struct FileLogger;
impl LoggerTrait for FileLogger {
fn log(&self, level: &str, message: &str) {
// In a real implementation, this would write to a file
}
}
let mut registry = HookRegistry::new();
let console_hook = Hook::<Logger>::new(Box::new(ConsoleLogger), "consoleh");
let console_id = HookID::new("logger_plugin", Logger::id(), Some("console"));
let file_hook = Hook::<Logger>::new(Box::new(FileLogger), "fileh");
let file_id = HookID::new("logger_plugin", Logger::id(), Some("file"));
registry.register(&console_id, console_hook).unwrap();
registry.register(&file_id, file_hook).unwrap();
// Get only the file logger
let file_loggers = registry.get_by_filter(|(id, _)| {
id.discriminator.as_deref() == Some("file")
});
assert_eq!(file_loggers.len(), 1);Sourcepub fn get_by_filter_mut<F>(&mut self, f: F) -> Vec<(&HookID, &mut BoxedHook)>
pub fn get_by_filter_mut<F>(&mut self, f: F) -> Vec<(&HookID, &mut BoxedHook)>
Gets mutable hooks that match a filter function.
§Parameters
f: A function that takes a reference to a hook ID and hook, and returns a boolean
§Returns
A vector of mutable references to hooks that match the filter
§Examples
use steckrs::{extension_point, hook::{HookRegistry, Hook, HookID, ExtensionPoint}};
extension_point!(
Logger: LoggerTrait;
fn log(&mut self, level: &str, message: &str);
);
struct ConsoleLogger;
impl LoggerTrait for ConsoleLogger {
fn log(&mut self, level: &str, message: &str) {
// In a real implementation, this would print to console
}
}
struct FileLogger;
impl LoggerTrait for FileLogger {
fn log(&mut self, level: &str, message: &str) {
// In a real implementation, this would write to a file
}
}
let mut registry = HookRegistry::new();
let console_hook = Hook::<Logger>::new(Box::new(ConsoleLogger), "consoleh");
let console_id = HookID::new("logger_plugin", Logger::id(), Some("console"));
let file_hook = Hook::<Logger>::new(Box::new(FileLogger), "fileh");
let file_id = HookID::new("logger_plugin", Logger::id(), Some("file"));
registry.register(&console_id, console_hook).unwrap();
registry.register(&file_id, file_hook).unwrap();
// Get only the file logger
let file_loggers = registry.get_by_filter_mut(|(id, _)| {
id.discriminator.as_deref() == Some("file")
});
assert_eq!(file_loggers.len(), 1);Sourcepub fn get_by_extension_point<E: ExtensionPoint>(
&self,
) -> Vec<(&HookID, &Hook<E>)>
pub fn get_by_extension_point<E: ExtensionPoint>( &self, ) -> Vec<(&HookID, &Hook<E>)>
Gets all hooks for a specific ExtensionPoint type.
§Type Parameters
E: The extension point type
§Returns
A vector of references to all hooks registered for the ExtensionPoint
§Examples
use steckrs::{extension_point, hook::{HookRegistry, Hook, HookID, ExtensionPoint}};
extension_point!(
Validator: ValidatorTrait;
fn validate(&self, input: &str) -> bool;
);
struct LengthValidator;
impl ValidatorTrait for LengthValidator {
fn validate(&self, input: &str) -> bool {
input.len() > 0
}
}
struct NumberValidator;
impl ValidatorTrait for NumberValidator {
fn validate(&self, input: &str) -> bool {
input.parse::<i32>().is_ok()
}
}
let mut registry = HookRegistry::new();
let length_hook = Hook::<Validator>::new(Box::new(LengthValidator), "lenh");
let length_id = HookID::new("validator_plugin", Validator::id(), Some("length"));
let number_hook = Hook::<Validator>::new(Box::new(NumberValidator), "numh");
let number_id = HookID::new("validator_plugin", Validator::id(), Some("number"));
registry.register(&length_id, length_hook).unwrap();
registry.register(&number_id, number_hook).unwrap();
dbg!(®istry);
let validators: Vec<(&HookID, &Hook<_>)> = registry.get_by_extension_point::<Validator>();
assert_eq!(validators.len(), 2);
// if we want to actually know which is
//which, we can use the name method of the hook to get metadata
validators.iter().for_each(|(_id,v)|{dbg!(v.name());});
// Test the validators
// 0 is len, 2 is num
assert!(validators[0].1.inner().validate("123"));
assert!(validators[1].1.inner().validate("123"));
assert!(validators[0].1.inner().validate("abc"));
assert!(!validators[1].1.inner().validate("abc"));Sourcepub fn get_by_extension_point_mut<E: ExtensionPoint>(
&mut self,
) -> Vec<(&HookID, &mut Hook<E>)>
pub fn get_by_extension_point_mut<E: ExtensionPoint>( &mut self, ) -> Vec<(&HookID, &mut Hook<E>)>
Gets all mutable hooks for a specific ExtensionPoint type.
§Type Parameters
E: The extension point type
§Returns
A vector of mutable references to all hooks registered for the ExtensionPoint
§Examples
use steckrs::{extension_point, hook::{HookRegistry, Hook, HookID, ExtensionPoint}};
extension_point!(
Validator: ValidatorTrait;
fn validate(&mut self, input: &str) -> bool;
);
struct LengthValidator;
impl ValidatorTrait for LengthValidator {
fn validate(&mut self, input: &str) -> bool {
input.len() > 0
}
}
struct NumberValidator;
impl ValidatorTrait for NumberValidator {
fn validate(&mut self, input: &str) -> bool {
input.parse::<i32>().is_ok()
}
}
let mut registry = HookRegistry::new();
let length_hook = Hook::<Validator>::new(Box::new(LengthValidator), "lenh");
let length_id = HookID::new("validator_plugin", Validator::id(), Some("length"));
let number_hook = Hook::<Validator>::new(Box::new(NumberValidator), "numh");
let number_id = HookID::new("validator_plugin", Validator::id(), Some("number"));
registry.register(&length_id, length_hook).unwrap();
registry.register(&number_id, number_hook).unwrap();
dbg!(®istry);
let mut validators: Vec<(&HookID, &mut Hook<_>)> = registry.get_by_extension_point_mut::<Validator>();
assert_eq!(validators.len(), 2);
// if we want to actually know which is
//which, we can use the name method of the hook to get metadata
validators.iter().for_each(|(_id,v)|{dbg!(v.name());});
// Test the validators
// 0 is len, 2 is num
assert!(validators[0].1.inner_mut().validate("123"));
assert!(validators[1].1.inner_mut().validate("123"));
assert!(validators[0].1.inner_mut().validate("abc"));
assert!(!validators[1].1.inner_mut().validate("abc"));Sourcepub fn deregister_hooks_for_plugin(&mut self, plugin_id: PluginID)
pub fn deregister_hooks_for_plugin(&mut self, plugin_id: PluginID)
Deregisters all hooks for a specific Plugin.
§Parameters
plugin_id: ThePluginIDof the plugin
§Panics
If deregistering fails.
§Examples
use steckrs::{extension_point, hook::{HookRegistry, Hook, HookID, ExtensionPoint}};
extension_point!(
Formatter: FormatterTrait;
fn format(&self, input: &str) -> String;
);
struct HtmlFormatter;
impl FormatterTrait for HtmlFormatter {
fn format(&self, input: &str) -> String {
format!("<p>{}</p>", input)
}
}
struct XmlFormatter;
impl FormatterTrait for XmlFormatter {
fn format(&self, input: &str) -> String {
format!("<text>{}</text>", input)
}
}
let mut registry = HookRegistry::new();
let plugin_id = "formatter_plugin";
let html_hook = Hook::<Formatter>::new(Box::new(HtmlFormatter), "htmlhook");
let html_id = HookID::new(plugin_id, Formatter::id(), Some("html"));
let xml_hook = Hook::<Formatter>::new(Box::new(XmlFormatter), "xmlhook");
let xml_id = HookID::new(plugin_id, Formatter::id(), Some("xml"));
registry.register(&html_id, html_hook).unwrap();
registry.register(&xml_id, xml_hook).unwrap();
// Before deregistration
assert_eq!(registry.get_by_extension_point::<Formatter>().len(), 2);
// Deregister all hooks for the plugin
registry.deregister_hooks_for_plugin(plugin_id);
// After deregistration
assert_eq!(registry.get_by_extension_point::<Formatter>().len(), 0);