steeloxide 0.1.0

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

use crate::{MouseDevice, Result, colour::Rgb, error::MouseError, mouse::packet::MousePacket};

pub const COLOUR_PACKET_HEADER: [u8; 4] = [0x00, 0x0a, 0x00, 0x0f];

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

impl MousePacket 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: MouseDevice) -> Self {
        Self {
            zones: device_type.get_zones(),
            colours: vec![Rgb::new(255, 255, 255); device_type.get_zones()],
        }
    }

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

        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())
        }
    }
}