use crate::resource::Resources;
use std::any::type_name;
pub trait PluginSet {
fn names() -> Vec<&'static str>;
}
impl PluginSet for () {
fn names() -> Vec<&'static str> {
vec![]
}
}
impl<P: Plugin> PluginSet for P {
fn names() -> Vec<&'static str> {
vec![type_name::<P>()]
}
}
impl<P1: Plugin, P2: Plugin> PluginSet for (P1, P2) {
fn names() -> Vec<&'static str> {
vec![type_name::<P1>(), type_name::<P2>()]
}
}
impl<P1: Plugin, P2: Plugin, P3: Plugin> PluginSet for (P1, P2, P3) {
fn names() -> Vec<&'static str> {
vec![type_name::<P1>(), type_name::<P2>(), type_name::<P3>()]
}
}
impl<P1: Plugin, P2: Plugin, P3: Plugin, P4: Plugin> PluginSet for (P1, P2, P3, P4) {
fn names() -> Vec<&'static str> {
vec![
type_name::<P1>(),
type_name::<P2>(),
type_name::<P3>(),
type_name::<P4>(),
]
}
}
impl<P1: Plugin, P2: Plugin, P3: Plugin, P4: Plugin, P5: Plugin> PluginSet
for (P1, P2, P3, P4, P5)
{
fn names() -> Vec<&'static str> {
vec![
type_name::<P1>(),
type_name::<P2>(),
type_name::<P3>(),
type_name::<P4>(),
type_name::<P5>(),
]
}
}
impl<P1: Plugin, P2: Plugin, P3: Plugin, P4: Plugin, P5: Plugin, P6: Plugin> PluginSet
for (P1, P2, P3, P4, P5, P6)
{
fn names() -> Vec<&'static str> {
vec![
type_name::<P1>(),
type_name::<P2>(),
type_name::<P3>(),
type_name::<P4>(),
type_name::<P5>(),
type_name::<P6>(),
]
}
}
pub trait PluginDyn: Send + Sync {
fn name(&self) -> &'static str;
fn dependencies(&self) -> Vec<&'static str>;
fn build(&self, resources: &mut Resources);
fn finish(&self, resources: &mut Resources);
fn cleanup(&self, resources: &mut Resources);
}
pub trait Plugin: Send + Sync + 'static {
type Dependencies: PluginSet;
fn name(&self) -> &'static str {
type_name::<Self>()
}
fn build(&self, resources: &mut Resources);
#[allow(unused_variables)]
fn finish(&self, resources: &mut Resources) {}
#[allow(unused_variables)]
fn cleanup(&self, resources: &mut Resources) {}
}
impl<P: Plugin> PluginDyn for P {
fn name(&self) -> &'static str {
<Self as Plugin>::name(self)
}
fn dependencies(&self) -> Vec<&'static str> {
P::Dependencies::names()
}
fn build(&self, resources: &mut Resources) {
<Self as Plugin>::build(self, resources)
}
fn finish(&self, resources: &mut Resources) {
<Self as Plugin>::finish(self, resources)
}
fn cleanup(&self, resources: &mut Resources) {
<Self as Plugin>::cleanup(self, resources)
}
}
pub trait PluginGroup {
fn plugins(&self) -> Vec<Box<dyn PluginDyn>>;
fn name(&self) -> &'static str {
std::any::type_name::<Self>()
}
}
pub(crate) struct PluginGroupAdapter {
#[allow(dead_code)]
name: &'static str,
plugins: Vec<Box<dyn PluginDyn>>,
}
impl PluginGroupAdapter {
pub fn new(group: impl PluginGroup) -> Self {
Self {
name: group.name(),
plugins: group.plugins(),
}
}
pub fn into_plugins(self) -> Vec<Box<dyn PluginDyn>> {
self.plugins
}
}
pub struct FnPlugin<F>
where
F: Fn(&mut Resources) + Send + Sync + 'static,
{
name: &'static str,
build_fn: F,
}
impl<F> FnPlugin<F>
where
F: Fn(&mut Resources) + Send + Sync + 'static,
{
pub fn new(name: &'static str, build_fn: F) -> Self {
Self { name, build_fn }
}
}
impl<F> Plugin for FnPlugin<F>
where
F: Fn(&mut Resources) + Send + Sync + 'static,
{
type Dependencies = ();
fn name(&self) -> &'static str {
self.name
}
fn build(&self, resources: &mut Resources) {
(self.build_fn)(resources);
}
}
#[cfg(test)]
mod tests {
use super::*;
struct TestPlugin {
value: i32,
}
impl Plugin for TestPlugin {
type Dependencies = ();
fn name(&self) -> &'static str {
"TestPlugin"
}
fn build(&self, resources: &mut Resources) {
resources.insert(self.value);
}
}
#[test]
fn test_plugin_build() {
let plugin = TestPlugin { value: 42 };
let mut resources = Resources::new();
PluginDyn::build(&plugin, &mut resources);
assert_eq!(*resources.get::<i32>().unwrap(), 42);
}
#[test]
fn test_fn_plugin() {
let plugin = FnPlugin::new("test", |resources| {
resources.insert("hello".to_string());
});
let mut resources = Resources::new();
PluginDyn::build(&plugin, &mut resources);
assert_eq!(resources.get::<String>().unwrap(), "hello");
}
struct DependentPlugin;
impl Plugin for DependentPlugin {
type Dependencies = TestPlugin;
fn name(&self) -> &'static str {
"DependentPlugin"
}
fn build(&self, resources: &mut Resources) {
if let Some(val) = resources.get_mut::<i32>() {
*val *= 2;
}
}
}
#[test]
fn test_plugin_dependencies() {
let plugin = DependentPlugin;
let deps = PluginDyn::dependencies(&plugin);
assert_eq!(deps, vec![type_name::<TestPlugin>()]);
}
}