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}