bevy_fnplugins 0.1.1

A plugin for bevy that allows you to use functions as plugins
Documentation
/* Heavily based on the plugin.rs in bevy_app */
#![allow(private_bounds)]

use bevy::prelude::*;

pub trait FnPluginsExt {
    /// Extended App method that adds functions as plugins to the main bevy app. Useful for creating plugin hierarchies (```struct``` Plugins as base plugins and `fn` plugins as sub-plugins). This method is heavily inspired by bevy's ```App::add_plugins``` method.
    /// ```
    /// use bevy::prelude::*;
    ///
    /// fn main() {
    ///     App::new().fn_plugins(example_plugin).run();
    /// }
    ///
    /// fn example_plugin(app: &mut App) {
    ///     println!("Hello from example_plugin!");
    /// }
    /// ```
    fn fn_plugins<T>(&mut self, f: impl FnPlugins<T>) -> &mut Self;
}

impl FnPluginsExt for App {
    fn fn_plugins<T>(&mut self, f: impl FnPlugins<T>) -> &mut Self {
        f.add_to_app(self);
        self
    }
}

trait FnPlugins<Marker>: sealed::FnPlugins<Marker> {}

impl<Marker, T> FnPlugins<Marker> for T where T: sealed::FnPlugins<Marker> {}

mod sealed {
    use bevy::ecs::all_tuples;
    use bevy::prelude::*;

    pub struct SingleFnMarker;
    pub struct TupleFnMarker;

    pub trait FnPlugins<Marker> {
        fn add_to_app(self, app: &mut App);
    }

    impl<P: FnOnce(&mut App)> FnPlugins<SingleFnMarker> for P {
        fn add_to_app(self, app: &mut App) {
            self(app);
        }
    }

    macro_rules! impl_fn_plugins {
        ($(($param: ident, $plugins: ident)),*) => {
            impl<$($param, $plugins),*> FnPlugins<(TupleFnMarker, $($param,)*)> for ($($plugins,)*)
            where
                $($plugins: FnPlugins<$param>),*
            {
                #[allow(non_snake_case, unused_variables)]
                fn add_to_app(self, app: &mut App) {
                    let ($($plugins,)*) = self;
                    $($plugins.add_to_app(app);)*
                }
            }
        }
    }

    all_tuples!(impl_fn_plugins, 0, 15, P, S);
}