steeloxide 0.1.0

A rust library for interacting with SteelSeries devices.
Documentation
// (c) ato
//
// `keyboard/packet/colour.rs`
//
// What this does is just changing the colour of zones.
// For Apex 3 TKL (of which this whole mouse part is based off of), it colours primarily 8 zones.
//
// The header was obtained straight from Wireshark w USBPcap and I tried to make sense of what else was there

use crate::{
    Result,
    colour::Rgb,
    error::MouseError,
    keyboard::{KeyboardDevice, packet::KeyboardPacket},
};
pub const COLOUR_PACKET_HEADER: [u8; 3] = [0x00, 0x21, 0xff];

#[derive(Debug, Clone)]
pub struct ColourPacket {
    colours: Vec<Rgb>,
    zones: usize,
}

impl KeyboardPacket for ColourPacket {
    fn serialize(&self) -> Result<Vec<u8>> {
        let mut buffer = Vec::with_capacity(4 + (self.zones * 3));
        buffer.extend_from_slice(&COLOUR_PACKET_HEADER);

        for zone in self.colours.iter().take(self.zones) {
            buffer.push(zone.r);
            buffer.push(zone.g);
            buffer.push(zone.b);
        }

        Ok(buffer)
    }
}

impl ColourPacket {
    pub fn new(device_type: KeyboardDevice) -> Self {
        Self {
            zones: device_type.get_zones(),
            colours: vec![Rgb::new(255, 255, 255); device_type.get_zones()],
        }
    }

    pub fn with_colours(device_type: KeyboardDevice, colours: Vec<Rgb>) -> Self {
        let zones = match device_type {
            KeyboardDevice::None => 0,
            KeyboardDevice::Apex3TKL => 8,
        };

        let mut colours_safe = colours;
        colours_safe.resize(zones, Rgb::new(255, 255, 255));

        Self {
            zones,
            colours: colours_safe,
        }
    }

    pub fn get_colours(&self) -> Vec<Rgb> {
        self.colours.clone()
    }

    pub fn get_zone(&self, index: usize) -> Result<Rgb> {
        if index >= self.zones {
            return Err(MouseError::ZoneOutOfRange.into());
        }

        self.colours
            .get(index)
            .cloned()
            .ok_or_else(|| MouseError::ZoneOutOfRange.into())
    }

    pub fn change_zone(&mut self, index: usize, colour: Rgb) -> Result<()> {
        if index >= self.zones {
            return Err(MouseError::ZoneOutOfRange.into());
        }

        if let Some(value) = self.colours.get_mut(index) {
            *value = colour;
            Ok(())
        } else {
            Err(MouseError::ZoneOutOfRange.into())
        }
    }
}