steckrs 0.1.0

A lightweight, trait-based plugin system for Rust applications and libraries
Documentation
steckrs-0.1.0 has been yanked.

steckrs

A lightweight, trait-based plugin system for Rust applications. The name "steckrs" is a wordplay combining the German word "Stecker" (meaning "plug" or "connector") and the Rust file extension (.rs).

Features

  • Type-Safe Extension Points: Define clear interfaces where plugins can add functionality
  • Dynamic Plugin Lifecycle: Load, enable, disable, and unload plugins at runtime (currently only statically compiled)
  • Hook Registration: Register implementations for extension points with proper type safety
  • Low Boilerplate: Convenient macros make plugin implementation concise and readable
  • Minimal Dependencies: Built with a focus on being lightweight and efficient

Installation

From crates.io

# in your rust/cargo project
cargo add steckrs

From source

git clone https://github.com/PlexSheep/steckrs.git
cd steckrs
cargo build --release
ls ./target/release/libsteckrs.rlib # here is the rlib if you want that

Quick Start

Here's a simple example of how to use steckrs to create a plugin-enabled application:

use steckrs::{extension_point, simple_plugin, PluginManager};

// Define an extension point
extension_point!(
    GreeterExtension: GreeterTrait,
    fn greet(&self, name: &str) -> String,
);

// Implement a hook
struct EnglishGreeter;
impl GreeterTrait for EnglishGreeter {
    fn greet(&self, name: &str) -> String {
        format!("Hello, {}!", name)
    }
}

// Create a plugin
simple_plugin!(
    HelloPlugin,
    "hello_plugin",
    "A simple greeting plugin",
    hooks: [(GreeterExtension, EnglishGreeter)]
);

fn main() {
    // Create plugin manager
    let mut plugin_manager = PluginManager::new();

    // Load and enable the plugin
    plugin_manager.load_plugin(Box::new(HelloPlugin::new())).unwrap();
    plugin_manager.enable_plugin(HelloPlugin::ID).unwrap();

    // Use the plugin
    let registry = plugin_manager.hook_registry();
    let hooks = registry.get_by_extension_point::<GreeterExtension>();

    // Execute all hooks relevant for this extension point
    for hook in hooks {
        println!("{}", hook.inner().greet("World"));
    }
}

Core Concepts

Extension Points

Extension points define interfaces where plugins can add functionality. Each extension point:

  • Is defined as a trait that plugins implement
  • Specifies the contract that plugins must fulfill
  • Provides type-safe interaction between the core application and plugins

Plugins

Plugins are self-contained datastructures that implement functionality for extension points. Each plugin:

  • Has a unique identifier
  • Can be enabled or disabled at runtime
  • Can register multiple hooks to different extension points
  • Has lifecycle methods (on_load, on_unload)

Hooks

Hooks are implementations of extension points that plugins register. They:

  • Implement the trait defined by an extension point
  • Are invoked when the application calls that extension point
  • Can be uniquely identified by their plugin ID, extension point, and optional discriminator

Macros

steckrs provides several convenience macros to reduce boilerplate:

  • extension_point! - Defines an extension point and its associated trait
  • simple_plugin! - Creates a simple plugin with minimal boilerplate
  • register_hook! - Registers a hook with the hook registry

Advanced Usage

For more complex scenarios, you can implement the Plugin trait directly, allowing for more customized plugin behavior and state management. A good starting point would be defining a plugin with simple_plugin! and then expanding the macro.

Use Cases

  • Modular Applications: Break monolithic applications into pluggable components
  • Extensible Libraries: Allow users to extend your library with custom functionality
  • Framework Development: Build frameworks that can be customized without modifying core code
  • Runtime Customization: Add or modify functionality without having to hardcode small things

Planned features

  • Dynamic Loading: It would be cool if plugins could be loaded from dynamic libraries in the future.

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

  1. Fork the repository
  2. Create your feature branch (git checkout -b feature/amazing-feature)
  3. Commit your changes (git commit -m 'Add some amazing feature')
  4. Push to the branch (git push origin feature/amazing-feature)
  5. Open a Pull Request

License

Distributed under the MIT License. See LICENSE for more information.