lla
- plugin interface
This crate provides a plugin interface for the lla
command line tool.
Plugin Architecture
The plugin system in lla
is designed to be robust and version-independent, using a message-passing architecture that ensures ABI compatibility across different Rust versions. Here's how it works:
Core Components
-
Protocol Buffer Interface
- All communication between the main application and plugins uses Protocol Buffers
- Messages are defined in
plugin.proto
, providing a language-agnostic contract - Supports various operations like decoration, field formatting, and custom actions
-
FFI Boundary
- Plugins are loaded dynamically using
libloading
- Communication crosses the FFI boundary using only C-compatible types
- Raw bytes are used for data transfer, avoiding Rust-specific ABI details
- Plugins are loaded dynamically using
ABI Compatibility
The plugin system solves the ABI compatibility problem through several mechanisms:
-
Message-Based Communication
- Instead of direct function calls, all interaction happens through serialized Protocol Buffer messages
- This eliminates dependency on Rust's internal ABI, which can change between versions
- Plugins and the main application can be compiled with different Rust versions
-
Version Control
- Each plugin declares its API version
- The system performs version checking during plugin loading
- Incompatible plugins are rejected with clear error messages
-
Stable Interface
- The FFI layer uses only C-compatible types, ensuring ABI stability
- Complex Rust types are serialized before crossing plugin boundaries
- The Protocol Buffer schema acts as a stable contract between components
Plugin Development
To create a plugin:
- Implement the plugin interface defined in the Protocol Buffer schema
- Use the provided macros and traits for proper FFI setup
- Compile as a dynamic library (
.so
,.dll
, or.dylib
)
The main application will handle loading, version verification, and communication with your plugin automatically.
Example Plugin
Here's a simple example of a file type categorizer plugin that demonstrates the key concepts:
use ;
use Message as ProstMessage;
/// A simple plugin that categorizes files based on their extensions
// Register the plugin with the main application
declare_plugin!;
This example demonstrates:
- Using Protocol Buffers for communication
- Implementing the
Plugin
trait - Handling different message types
- Processing file metadata
- Adding custom fields to entries
- Proper error handling
- Using the plugin declaration macro
The plugin can be compiled as a dynamic library and loaded by the main application at runtime, with full ABI compatibility regardless of the Rust version used to compile either component.