use crate::pattern::config::PatternParams;
use crate::pattern::params::PatternParam;
use crate::pattern::patterns::*;
use std::collections::HashMap;
use std::sync::Arc;
pub struct PatternMetadata {
pub id: &'static str,
pub name: &'static str,
pub description: &'static str,
default_params: Arc<Box<dyn PatternParam + Send + Sync>>,
}
impl Clone for PatternMetadata {
fn clone(&self) -> Self {
Self {
id: self.id,
name: self.name,
description: self.description,
default_params: Arc::clone(&self.default_params),
}
}
}
impl PatternMetadata {
pub fn params(&self) -> &dyn PatternParam {
&**self.default_params
}
}
macro_rules! define_pattern_registry {
($(
$id:expr => {
variant: $variant:ident,
params: $params:ident
}
),* $(,)?) => {
impl PatternRegistry {
fn create_default() -> HashMap<String, PatternMetadata> {
let mut patterns = HashMap::new();
$(
let default_params = Box::new($params::default());
patterns.insert($id.to_string(), PatternMetadata {
id: $id,
name: default_params.name(),
description: default_params.description(),
default_params: Arc::new(default_params),
});
)*
patterns
}
fn pattern_to_params(&self, id: &str, params: Box<dyn PatternParam>) -> Result<PatternParams, String> {
match id {
$(
$id => Ok(PatternParams::$variant(
params.as_any()
.downcast_ref::<$params>()
.ok_or_else(|| format!("Invalid parameter type for {}", $id))?
.clone()
)),
)*
_ => Err(format!("Unknown pattern: {}", id))
}
}
pub fn get_pattern_id(&self, params: &PatternParams) -> Option<&str> {
match params {
$(PatternParams::$variant(_) => Some($id),)*
}
}
}
};
}
define_pattern_registry! {
"horizontal" => {
variant: Horizontal,
params: HorizontalParams
},
"diagonal" => {
variant: Diagonal,
params: DiagonalParams
},
"plasma" => {
variant: Plasma,
params: PlasmaParams
},
"ripple" => {
variant: Ripple,
params: RippleParams
},
"wave" => {
variant: Wave,
params: WaveParams
},
"spiral" => {
variant: Spiral,
params: SpiralParams
},
"checkerboard" => {
variant: Checkerboard,
params: CheckerboardParams
},
"diamond" => {
variant: Diamond,
params: DiamondParams
},
"perlin" => {
variant: Perlin,
params: PerlinParams
},
"rain" => {
variant: PixelRain,
params: PixelRainParams
},
"fire" => {
variant: Fire,
params: FireParams
},
"aurora" => {
variant: Aurora,
params: AuroraParams
},
"kaleidoscope" => {
variant: Kaleidoscope,
params: KaleidoscopeParams
},
}
pub struct PatternRegistry {
patterns: HashMap<String, PatternMetadata>,
}
impl Default for PatternRegistry {
fn default() -> Self {
Self::new()
}
}
impl PatternRegistry {
pub fn new() -> Self {
Self {
patterns: Self::create_default(),
}
}
pub fn get_pattern(&self, id: &str) -> Option<&PatternMetadata> {
self.patterns.get(id)
}
pub fn list_patterns(&self) -> Vec<&str> {
self.patterns.keys().map(|s| s.as_str()).collect()
}
pub fn create_pattern_params(&self, id: &str) -> Option<PatternParams> {
self.get_pattern(id).map(|metadata| {
self.pattern_to_params(id, metadata.default_params.as_ref().clone_param())
.unwrap_or_else(|_| PatternParams::Horizontal(Default::default()))
})
}
pub fn validate_params(&self, id: &str, params: &str) -> Result<(), String> {
if let Some(metadata) = self.get_pattern(id) {
metadata.default_params.validate(params)
} else {
Err(format!("Unknown pattern: {}", id))
}
}
pub fn parse_params(&self, id: &str, params: &str) -> Result<PatternParams, String> {
if let Some(metadata) = self.get_pattern(id) {
let parsed = metadata.default_params.parse(params)?;
self.pattern_to_params(id, parsed)
} else {
Err(format!("Unknown pattern: {}", id))
}
}
}
lazy_static::lazy_static! {
pub static ref REGISTRY: PatternRegistry = PatternRegistry::new();
}