bevy_state_plugin_generator 1.4.4

A build-dependency that generates a Bevy State Plugin from a simple state definition.
Documentation
use std::borrow::Cow;

#[cfg(test)]
use bevy_reflect::Reflect;

/// How state-names are determined
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[cfg_attr(test, derive(Reflect))]
pub enum NamingScheme {
    /// Name includes the names of all ancestors
    Full,
    /// Name includes only the name of the immediate parent
    Short,
    /// None (all names must be unique)
    None,
}

impl NamingScheme {
    /// Get the name of the naming scheme
    /// ```rust
    /// # use bevy_state_plugin_generator::prelude::NamingScheme;
    /// assert_eq!(NamingScheme::Full.name(), "Full");
    /// assert_eq!(NamingScheme::Short.name(), "Short");
    /// assert_eq!(NamingScheme::None.name(), "None");
    /// ```
    pub fn name(&self) -> &str {
        match self {
            NamingScheme::Full => "Full",
            NamingScheme::Short => "Short",
            NamingScheme::None => "None",
        }
    }
    /// Get the identifying tag for this scheme
    /// ```rust
    /// # use bevy_state_plugin_generator::prelude::NamingScheme;
    /// assert_eq!(NamingScheme::Full.tag(), "full");
    /// assert_eq!(NamingScheme::Short.tag(), "short");
    /// assert_eq!(NamingScheme::None.tag(), "none");
    /// ```
    pub fn tag(&self) -> String {
        self.name().to_lowercase()
    }
    /// Convert a string into a NamingScheme, if it's the name or tag
    pub fn try_parse(input: &str) -> Option<Self> {
        match input {
            "full" | "Full" => Some(NamingScheme::Full),
            "short" | "Short" => Some(NamingScheme::Short),
            "none" | "None" => Some(NamingScheme::None),
            _ => None,
        }
    }
}

impl Default for NamingScheme {
    fn default() -> Self {
        Self::Full
    }
}

impl std::fmt::Display for NamingScheme {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.name())
    }
}

/// How the plugin is rendered.
#[derive(Clone, Debug, Eq, PartialEq)]
#[cfg_attr(test, derive(Reflect))]
pub enum PluginName<'s> {
    /// ```rust
    /// use bevy_state_plugin_generator::prelude::PluginName;
    /// PluginName::new_struct("MyPlugin");
    /// ```
    Struct(Cow<'s, str>),
    /// ```rust
    /// use bevy_state_plugin_generator::prelude::PluginName;
    /// PluginName::new_function("my_plugin");
    /// ```
    Function(Cow<'s, str>),
}

impl<'s> PluginName<'s> {
    /// Create the Struct variant
    pub fn new_struct<S: Into<Cow<'s, str>>>(name: S) -> Self {
        Self::Struct(name.into())
    }
    /// Create the Function variant
    pub fn new_function<S: Into<Cow<'s, str>>>(name: S) -> Self {
        Self::Function(name.into())
    }
}

/// Configuration for the generated plugin
#[derive(Clone, Debug)]
#[cfg_attr(test, derive(Reflect))]
pub struct PluginConfig {
    /// Name of the struct that implements [`bevy::plugin::Plugin`]
    /// Defaults to `GeneratedStatesPlugin`
    pub plugin_name: PluginName<'static>,
    /// Name of the root enum/struct. `None` means NO root node.
    pub root_state_name: Option<Cow<'static, str>>,
    /// Name for the inner module containing the generated states
    pub states_module_name: Cow<'static, str>,
    /// How generated states are named
    pub naming_scheme: NamingScheme,
    /// These additional traits will be added to the derive list
    pub additional_derives: Vec<Cow<'static, str>>,
}

impl PluginConfig {
    const fn const_default() -> Self {
        Self {
            plugin_name: PluginName::Struct(Cow::Borrowed("GeneratedStatesPlugin")),
            root_state_name: Some(Cow::Borrowed("GameState")),
            states_module_name: Cow::Borrowed("states"),
            naming_scheme: NamingScheme::Full,
            additional_derives: vec![],
        }
    }
}

/// Default configuration for the generated plugin
/// ```rust
/// # use bevy_state_plugin_generator::prelude::*;
/// let config = PluginConfig::default();
/// assert_eq!(config.plugin_name, PluginName::new_struct("GeneratedStatesPlugin"));
/// assert_eq!(config.root_state_name, Some(Cow::from("GameState")));
/// assert_eq!(config.states_module_name, Cow::from("states"));
/// assert_eq!(config.naming_scheme, NamingScheme::Full);
/// ```
impl Default for PluginConfig {
    fn default() -> Self {
        Self::const_default()
    }
}

impl From<NamingScheme> for PluginConfig {
    fn from(naming_scheme: NamingScheme) -> Self {
        Self {
            naming_scheme,
            ..Default::default()
        }
    }
}

#[cfg(test)]
#[rstest::rstest]
#[case(NamingScheme::None)]
#[case(NamingScheme::Short)]
#[case(NamingScheme::Full)]
fn test_plugin_config_from_naming_scheme(#[case] naming_scheme: NamingScheme) {
    let config = PluginConfig::from(naming_scheme);
    assert_eq!(config.naming_scheme, naming_scheme);
}