Hi all.
I want to develop a plugin system within my program, and I have a trait that functions defined by plugins should implement.
Currently, my code gets all the functions in a HashMap and then calls them by their name. Problem is, I have to create that hashmap myself by inserting every function myself.
I would really appreciate it if there was a way to say, suppose, all pub members of mod functions::
that implement this trait PluginFunction
call register(hashmap)
function. So as I add more functions as mod
in functions
it'll be automatically added on compile.
Pseudocode:
Files:
src/
├── attrs.rs
├── functions
│ ├── attrs.rs
│ ├── export.rs
│ └── render.rs
├── functions.rs
├── lib.rs
Basically, in mod functions
I want:
impl AllFunctions{
pub fn new() -> Self {
let mut functions_map = HashMap::new();[[
register_all!(crate::functions::* implementing PluginFunction, &mut functions_map);
Self { function_map }
}
}
Right now I'm doing:
impl AllFunctions{
pub fn new() -> Self {
let mut functions_map = HashMap::new();[[
crate::functions::attrs::PrintAttr{}.register(&mut functions_map);
crate::functions::export::ExportCSV{}.register(&mut functions_map);
crate::functions::render::RenderText{}.register(&mut functions_map);
// More as I add more functions
Self { function_map }
}
}
No, macros can see only the tokens you give them. They have no notion of the fact that
crate::functions
is a module, thatPluginFunction
is a trait and thatfunctions_map
is a variable. Not even the compiler may know those informations when the macro is expanded.If you really really want to do this, you can use something like
inventory
. Note thatinventory
uses a special linker section to do this, which some consider a hack. This is also not supported on WASM if you want to target it.Thank you. I just put the call with
!
, I don't necessarily want a macro solution. Any solution is acceptable, my requirement is that I can just keep adding more mods with functions insrc/functions/
and not have to register each function.Inventory seems like the solution I am looking for. Although in my case, instead of collecting different values of the same type, I want to collect different types that all have same trait. But maybe I can make a temporary struct with
Box<dyn _>
member to collect it if trying to collect it directly doesn't work. I do not plan to support WASM. I am planning to make C/C++ and Python API for the libraries though, so if it has problems with them, then I might have a problem.Maybe keep maintaining the HashMap you have now and use one of these less portable mechanisms in a test to alert you when you forgot to register one?
That seems like a good compromise if I don't find something better. Thank you.
I'm hoping to make it easy for people to add more functions, that's why I want minimal code change required to add more functions.