smart_led_effects 0.1.8

A collection of effects for LED strips
Documentation
use crate::strip::EffectIterator;
use std::vec;

use palette::{FromColor, Hsv, Srgb};

#[derive(Debug, PartialEq)]
enum Direction {
    Forward,
    Backward,
}

impl Direction {
    fn next(&mut self) {
        match self {
            Direction::Forward => *self = Direction::Backward,
            _ => *self = Direction::Forward,
        }
    }
}

pub struct Cylon {
    colour: Hsv,
    direction: Direction,
    brightness: Vec<f32>,
    start: usize,
    size: usize,
    fade: f32,
}

impl Cylon {
    const DEFAULT_SIZE: usize = 4;
    const DEFAULT_FADE: f32 = 0.2;

    pub fn new(count: usize, colour: Srgb<u8>, size: Option<usize>, fade: Option<f32>) -> Self {
        let mut brightness = vec![0.0; count];
        let size = size.unwrap_or(Cylon::DEFAULT_SIZE);

        for pixel in brightness.iter_mut().take(size) {
            *pixel = 1.0;
        }

        Cylon {
            colour: Hsv::from_color(colour.into_format()),
            brightness,
            start: size - 1,
            direction: Direction::Forward,
            size,
            fade: fade.unwrap_or(Cylon::DEFAULT_FADE),
        }
    }
}

impl EffectIterator for Cylon {
    fn name(&self) -> &'static str {
        "Cylon"
    }

    fn next(&mut self) -> Option<Vec<Srgb<u8>>> {
        let len = self.brightness.len();

        let mut trail: Vec<f32> = vec![0.0; len];

        match self.direction {
            Direction::Forward => {
                self.brightness.rotate_right(1);
                self.start += 1;

                if self.start == len - 1 {
                    self.direction.next();
                }

                let mut val: f32 = 0.8;
                if self.start + 1 > self.size {
                    for i in (0..self.start + 1 - self.size).rev() {
                        trail[i] = val;
                        val = (val - self.fade).max(0.0);
                    }
                }
            }
            _ => {
                self.brightness.rotate_left(1);
                self.start -= 1;
                if self.start == self.size - 1 {
                    self.direction.next();
                }

                if self.start < len - 1 {
                    let mut val: f32 = 0.8;
                    for pixel in trail.iter_mut().take(len).skip(self.start) {
                        *pixel = val;
                        val = (val - self.fade).max(0.0);
                    }
                }
            }
        };

        let out: Vec<Srgb<u8>> = self
            .brightness
            .iter()
            .zip(trail.iter())
            .map(|(&x, &y)| {
                let mut pixel = self.colour;
                pixel.value = (x + y).min(1.0);
                Srgb::from_color(pixel).into_format::<u8>()
            })
            .collect();

        Some(out)
    }
}