plux_rs/lib.rs
1//! # Plux - Extensible Plugin System for Rust
2//!
3//! Plux is a comprehensive plugin system for Rust applications, offering a robust and flexible
4//! architecture for extending application functionality through plugins. It enables seamless
5//! integration of third-party code while maintaining security and stability.
6//!
7//! ## Key Features
8//!
9//! - **Language Agnostic**: Write plugins in any programming language
10//! - **Hot Reloading**: Update plugins without restarting the host application
11//! - **Dynamic Loading**: Load and unload plugins at runtime
12//! - **Type Safety**: Rust's type system ensures safe plugin interactions
13//! - **Cross-Platform**: Works on all major platforms (Windows, macOS, Linux)
14//! - **Performance Optimized**: Efficient loading and caching of plugins
15//! - **Isolated Execution**: Secure sandboxing for plugin execution
16//!
17//! ## Core Components
18//!
19//! - **Loader**: Central component for managing plugin lifecycle and execution
20//! - **Manager**: Adapters providing standardized interfaces for plugin integration
21//! - **Plugin**: Self-contained modules that extend application functionality
22//!
23//! ## Quick Start
24//!
25//! ```rust,no_run
26//! use plux_rs::prelude::*;
27//! use plux_lua_manager::LuaManager;
28//!
29//! #[function]
30//! fn add(_: (), a: &i32, b: &i32) -> i32 {
31//! a + b
32//! }
33//!
34//! fn main() -> Result<(), Box<dyn std::error::Error>> {
35//! let mut loader = SimpleLoader::new();
36//!
37//! loader.context(move |mut ctx| {
38//! ctx.register_manager(LuaManager::new())?;
39//! ctx.register_function(add());
40//!
41//! // Load and manage plugins here
42//! Ok::<(), Box<dyn std::error::Error>>(())
43//! })?;
44//!
45//! Ok(())
46//! }
47//! ```
48
49#![warn(missing_docs)]
50// #![doc(html_logo_url = "https://example.com/logo.png")]
51// #![doc(html_favicon_url = "https://example.com/favicon.ico")]
52
53/// Context types used during plugin loading and registration.
54///
55/// This module provides the context types that are passed to plugin managers
56/// during various lifecycle events such as registration and loading.
57pub mod context;
58
59/// Function and request definitions for the plugin system.
60///
61/// This module defines the core function and request types that enable
62/// communication between plugins and the host application.
63pub mod function;
64
65/// Utility types and functions for the plugin system.
66///
67/// This module contains various utility types, error definitions, and helper
68/// functions used throughout the plugin system.
69pub mod utils;
70
71/// Variable types used for data exchange between plugins and host.
72///
73/// This module defines the Variable and VariableType enums that represent
74/// the data types that can be passed between plugins and the host application.
75pub mod variable;
76
77mod api;
78mod bundle;
79mod info;
80mod loader;
81mod manager;
82mod plugin;
83
84pub use api::*;
85pub use bundle::*;
86pub use context::*;
87pub use info::*;
88pub use loader::*;
89pub use manager::*;
90pub use plugin::*;
91
92use function::{Function, Request};
93use std::sync::Arc;
94
95/// Registry of functions that can be called by plugins.
96/// This type alias represents a collection of functions exposed by the host application
97/// that plugins can invoke during execution.
98pub type Registry<O> = Vec<Arc<dyn Function<Output = O>>>;
99
100/// Collection of function requests from plugins.
101/// This type alias represents a collection of requests that plugins can make to the host
102/// application, typically for accessing host-provided functionality.
103pub type Requests = Vec<Request>;
104
105/// A convenience type alias for a Loader with commonly used default type parameters.
106///
107/// This type alias simplifies the creation of a `Loader` with the following configuration:
108/// - `'static` lifetime for the loader itself
109/// - `FunctionOutput` as the output type, which is the standard return type for plugin functions
110/// - `StdInfo` as the info type, which provides standard plugin information
111///
112/// # Example
113///
114/// ```rust
115/// use plux_rs::SimpleLoader;
116///
117/// // Create a new loader with default configuration
118/// let loader = SimpleLoader::new();
119/// ```
120pub type SimpleLoader = Loader<'static, function::FunctionOutput, info::StdInfo>;
121
122/// Macro for convenient function calling with automatic argument conversion.
123///
124/// This macro simplifies calling functions by automatically converting arguments
125/// to Variables and handling the function call syntax.
126///
127/// # Examples
128///
129/// ```rust
130/// use plux_rs::{function_call, function::{Function, DynamicFunction, Arg, FunctionOutput}};
131/// use plux_rs::variable::VariableType;
132///
133/// let add = DynamicFunction::new(
134/// "add",
135/// vec![
136/// Arg::new("a", VariableType::I32),
137/// Arg::new("b", VariableType::I32),
138/// ],
139/// Some(Arg::new("result", VariableType::I32)),
140/// |args| -> FunctionOutput {
141/// let a = args[0].parse_ref::<i32>();
142/// let b = args[1].parse_ref::<i32>();
143/// Ok(Some((a + b).into()))
144/// }
145/// );
146///
147/// // Call with arguments
148/// let result = function_call!(add, 5, 3);
149/// assert_eq!(result.unwrap(), Some(8.into()));
150///
151/// // Call without arguments
152/// let no_args_func = DynamicFunction::new(
153/// "hello",
154/// vec![],
155/// Some(Arg::new("message", VariableType::String)),
156/// |_| -> FunctionOutput { Ok(Some("Hello!".into())) }
157/// );
158/// let message = function_call!(no_args_func);
159/// ```
160#[macro_export]
161macro_rules! function_call {
162 ($function: ident, $($args:expr), +) => {
163 // Call a function with multiple arguments
164 $function.call(&[$($args.into()), +])
165 };
166 ($function: ident) => {
167 // Call a function with no arguments
168 $function.call(&[])
169 };
170}
171
172/// Re-exports for procedural macros when the `derive` feature is enabled.
173///
174/// # Macros
175///
176/// ## `#[function]`
177///
178/// A procedural macro that transforms a Rust function into a plugin-compatible function.
179/// This macro enables the function to be called from plugins and handles serialization
180/// of arguments and return values.
181///
182/// ### Usage
183///
184/// ```rust,no_run
185/// use plux_rs::prelude::*;
186///
187/// // Basic usage with primitive types
188/// #[plux_rs::function]
189/// fn add(_: (), a: &i32, b: &i32) -> i32 {
190/// a + b
191/// }
192///
193/// // With references for better performance
194/// #[plux_rs::function]
195/// fn concat(_: (), a: &String, b: Vec<&String>) -> String {
196/// let v = b.into_iter().map(|s| s.clone()).collect::<Vec<String>>();
197/// format!("{} {}", a, v.join(" "))
198/// }
199///
200/// // With context parameter (first parameter is always the context)
201/// #[plux_rs::function]
202/// fn greet(message: &String, name: &Variable) -> String {
203/// format!("{} {}", message, name)
204/// }
205///
206/// let mut loader = Loader::<'_, FunctionOutput, StdInfo>::new();
207/// loader
208/// .context(move |mut ctx| {
209/// ctx.register_function(add());
210/// ctx.register_function(concat());
211/// ctx.register_function(greet("Hello world,".to_string()));
212///
213/// Ok::<(), Box<dyn std::error::Error>>(())
214/// })
215/// .unwrap();
216///
217/// let registry = loader.get_registry();
218///
219/// let add_function = registry.get(0).unwrap();
220/// let concat_function = registry.get(1).unwrap();
221/// let greet_function = registry.get(2).unwrap();
222///
223/// let result = add_function.call(&[1.into(), 2.into()]).unwrap().unwrap();
224/// assert_eq!(result, 3.into());
225///
226/// let result = concat_function
227/// .call(&["Hi".into(), vec!["guest", "!"].into()])
228/// .unwrap()
229/// .unwrap();
230/// assert_eq!(result, "Hi guest !".into());
231///
232/// let result = greet_function.call(&["guest".into()]).unwrap().unwrap();
233/// assert_eq!(result, "Hello world, guest".into());
234/// ```
235///
236/// ### Features
237///
238/// - **Type Safety**: Compile-time type checking of function signatures
239/// - **Zero-Copy**: Always uses references to avoid unnecessary cloning
240/// - **Context Support**: First parameter can be a context object
241///
242/// ### Notes
243///
244/// - The first parameter can be used for context (use `_` if not needed)
245/// - Supported parameter types: primitive types, `&T` and `Vec<&T>`
246/// - The function will be available to plugins under its Rust name by default
247#[cfg(feature = "derive")]
248pub use plux_codegen::function;
249
250/// Re-export of common types for plugin implementation.
251/// This module provides convenient access to the most commonly used types when
252/// implementing plugins.
253pub mod prelude {
254 pub use crate::LoaderContext;
255 pub use crate::api::*;
256 pub use crate::bundle::*;
257 pub use crate::function::*;
258 pub use crate::info::{Depend, Info, StdInfo};
259 pub use crate::loader::*;
260 pub use crate::plugin::*;
261 pub use crate::utils::*;
262 pub use crate::variable::*;
263 pub use crate::Registry;
264 pub use crate::Requests;
265 pub use crate::SimpleLoader;
266
267 #[cfg(feature = "derive")]
268 pub use plux_codegen::*;
269}
270
271#[test]
272fn test_function_call_macro() {
273 use crate::{
274 function::{Arg, DynamicFunction, Function, FunctionOutput},
275 variable::VariableType,
276 };
277
278 // Creating a function
279 let func = DynamicFunction::new(
280 "add",
281 vec![
282 Arg::new("a", VariableType::I32),
283 Arg::new("b", VariableType::I32),
284 ],
285 Some(Arg::new("c", VariableType::I32)),
286 |args| -> FunctionOutput {
287 let a = args[0].parse_ref::<i32>();
288 let b = args[1].parse_ref::<i32>();
289
290 let c = a + b;
291
292 println!("{} + {} = {}", a, b, c);
293
294 Ok(Some(c.into()))
295 },
296 );
297
298 // Running the function
299 let c = function_call!(func, 1, 2);
300
301 assert!(c.is_ok());
302 assert_eq!(c.unwrap(), Some(3.into()));
303}