mod blink; mod color_wipe; mod fade; mod fade_random; mod fade_unstable; mod fill_random; mod fill_unstable; mod rain; mod rainbow; mod scanner; use crate::patterns::blink::Blink; use crate::patterns::color_wipe::ColorWipe; use crate::patterns::fade::Fade; use crate::patterns::fade_random::FadeRandom; use crate::patterns::fade_unstable::FadeUnstable; use crate::patterns::fill_random::FillRandom; use crate::patterns::fill_unstable::FillUnstable; use crate::patterns::rain::Rain; use crate::patterns::rainbow::Rainbow; use crate::patterns::scanner::Scanner; use rand::rngs::ThreadRng; use rand::Rng; use serde_derive::{Deserialize, Serialize}; use std::fmt; use std::ops::{AddAssign, Div, Index, IndexMut, SubAssign}; #[derive(Serialize, Deserialize, Debug, Eq, Hash, PartialEq, Copy, Clone)] #[serde(tag = "type")] pub(crate) enum Patterns { Rainbow(Rainbow), Fade(Fade), ColorWipe(ColorWipe), Scanner(Scanner), FillRandom(FillRandom), FillUnstable(FillUnstable), Blink(Blink), Rain(Rain), FadeRandom(FadeRandom), FadeUnstable(FadeUnstable), } pub trait Pattern: Iterator { type Strip; fn init(&mut self) -> Option; fn is_last_iteration(&self) -> bool; } impl Iterator for Patterns { type Item = Strip; fn next(&mut self) -> Option { match self { Patterns::Rainbow(p) => p.next(), Patterns::Fade(p) => p.next(), Patterns::ColorWipe(p) => p.next(), Patterns::Scanner(p) => p.next(), Patterns::FillRandom(p) => p.next(), Patterns::FillUnstable(p) => p.next(), Patterns::Blink(p) => p.next(), Patterns::Rain(p) => p.next(), Patterns::FadeRandom(p) => p.next(), Patterns::FadeUnstable(p) => p.next(), } } } impl Pattern for Patterns { type Strip = Strip; fn init(&mut self) -> Option { match self { Patterns::Rainbow(p) => p.init(), Patterns::Fade(p) => p.init(), Patterns::ColorWipe(p) => p.init(), Patterns::Scanner(p) => p.init(), Patterns::FillRandom(p) => p.init(), Patterns::FillUnstable(p) => p.init(), Patterns::Blink(p) => p.init(), Patterns::Rain(p) => p.init(), Patterns::FadeRandom(p) => p.init(), Patterns::FadeUnstable(p) => p.init(), } } fn is_last_iteration(&self) -> bool { match self { Patterns::Rainbow(p) => p.is_last_iteration(), Patterns::Fade(p) => p.is_last_iteration(), Patterns::ColorWipe(p) => p.is_last_iteration(), Patterns::Scanner(p) => p.is_last_iteration(), Patterns::FillRandom(p) => p.is_last_iteration(), Patterns::FillUnstable(p) => p.is_last_iteration(), Patterns::Blink(p) => p.is_last_iteration(), Patterns::Rain(p) => p.is_last_iteration(), Patterns::FadeRandom(p) => p.is_last_iteration(), Patterns::FadeUnstable(p) => p.is_last_iteration(), } } } /// /// a struct for an RGB color #[derive(Clone, Copy, Debug, Serialize, Deserialize, Default, Eq, Hash, PartialEq)] pub struct PixelColor { pub(crate) red: u8, pub(crate) green: u8, pub(crate) blue: u8, } impl fmt::Display for PixelColor { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "[{},{},{}]", self.red, self.green, self.blue) } } impl Div for PixelColor { type Output = PixelColor; fn div(self, rhs: u8) -> Self::Output { PixelColor { red: self.red / rhs, green: self.green / rhs, blue: self.blue / rhs, } } } impl SubAssign for PixelColor { fn sub_assign(&mut self, rhs: Self) { self.red = self.red.saturating_sub(rhs.red); self.green = self.red.saturating_sub(rhs.green); self.blue = self.red.saturating_sub(rhs.blue); } } impl AddAssign for PixelColor { fn add_assign(&mut self, rhs: Self) { self.red = self.red.saturating_add(rhs.red); self.green = self.red.saturating_add(rhs.green); self.blue = self.red.saturating_add(rhs.blue); } } impl PixelColor { /// apply random delta to pixel and return computed value /// /// # Arguments /// /// * `pixel`: pixel to apply delta /// * `stability`: amplitude of delta between 0 and `stability` /// /// returns: PixelColor /// pub fn random_delta(&self, stability: usize, rng: &mut ThreadRng) -> PixelColor { let red_delta = rng.gen_range(0..stability) as u8; let green_delta = rng.gen_range(0..stability) as u8; let blue_delta = rng.gen_range(0..stability) as u8; let operation = rng.gen_bool(0.5); let red; let green; let blue; if operation { red = self.red.saturating_add(red_delta); green = self.green.saturating_add(green_delta); blue = self.blue.saturating_add(blue_delta); } else { red = self.red.saturating_sub(red_delta); green = self.green.saturating_sub(green_delta); blue = self.blue.saturating_sub(blue_delta); } PixelColor { red, green, blue } } } /// /// a basic newtype based on a fix array size. /// #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq)] pub struct Strip([Option; N]); impl Default for Strip { fn default() -> Self { Strip([None; N]) } } impl Index for Strip { type Output = Option; fn index(&self, index: usize) -> &Self::Output { &self.0[index] } } impl IndexMut for Strip { fn index_mut(&mut self, index: usize) -> &mut Option { &mut self.0[index] } } impl Strip { pub fn to_array(self) -> Vec { let mut data: Vec = vec![]; for i in 0..N { let color = self[i].unwrap_or(PixelColor::default()); data.append(&mut vec![color.green, color.red, color.blue]); } data } pub fn new(color: PixelColor) -> Strip { Strip { 0: [Some(color); N], } } pub fn fill(&mut self, color: PixelColor) { self.0.fill(Some(color)); } }