Struct HookRegistry

Source
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

Source

pub fn new() -> Self

Creates a new empty hook registry.

§Examples
use steckrs::hook::HookRegistry;

let registry = HookRegistry::new();
Source

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 hook
  • hook: 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();
Source

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 removed
  • None if 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));
Source

pub fn exists(&self, id: &HookID) -> bool

Checks if a hook with the given HookID exists.

§Parameters
  • id: The ID to check
§Returns
  • true if a hook with the given ID exists
  • false otherwise
§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));
Source

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 found
  • None if 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);
Source

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 found
  • None if 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);
Source

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 found
  • None if 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());
Source

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 found
  • None if 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());
Source

pub fn get_by_plugin(&self, plugin_id: PluginID) -> Vec<(&HookID, &BoxedHook)>

Gets all hooks registered by a specific Plugin.

§Parameters
§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);
Source

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
§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);
Source

pub fn get_by_filter<F>(&self, f: F) -> Vec<(&HookID, &BoxedHook)>
where F: FnMut(&(&HookID, &BoxedHook)) -> bool,

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);
Source

pub fn get_by_filter_mut<F>(&mut self, f: F) -> Vec<(&HookID, &mut BoxedHook)>
where F: FnMut(&(&HookID, &mut BoxedHook)) -> bool,

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);
Source

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!(&registry);
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"));
Source

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!(&registry);
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"));
Source

pub fn deregister_hooks_for_plugin(&mut self, plugin_id: PluginID)

Deregisters all hooks for a specific Plugin.

§Parameters
§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);

Trait Implementations§

Source§

impl Debug for HookRegistry

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for HookRegistry

Source§

fn default() -> HookRegistry

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more