use flagset::{FlagSet, flags};
use crate::data::ProtocolOption;
use crate::protocol::{DeserFromBuf, SerToBuf, WriteMessage};
use crate::{OpenRgbResult, protocol::data::Color};
use crate::{ReceivedMessage, impl_enum_discriminant};
flags! {
pub enum ModeFlag: u32 {
HasSpeed = 1 << 0,
HasDirectionLR = 1 << 1,
HasDirectionUD = 1 << 2,
HasDirectionHV = 1 << 3,
HasDirection = (ModeFlag::HasDirectionLR | ModeFlag::HasDirectionUD | ModeFlag::HasDirectionHV).bits(),
HasBrightness = 1 << 4,
HasPerLEDColor = 1 << 5,
HasModeSpecificColor = 1 << 6,
HasRandomColor = 1 << 7,
ManualSave = 1 << 8,
AutomaticSave = 1 << 9,
}
}
#[derive(Eq, PartialEq, Debug, Copy, Clone, Default)]
pub enum Direction {
#[default]
Left = 0,
Right = 1,
Up = 2,
Down = 3,
Horizontal = 4,
Vertical = 5,
}
impl_enum_discriminant!(
Direction,
Left: 0,
Right: 1,
Up: 2,
Down: 3,
Horizontal: 4,
Vertical: 5
);
#[derive(Eq, PartialEq, Debug, Copy, Clone, Default)]
pub enum ColorMode {
#[default]
None = 0,
PerLED = 1,
ModeSpecific = 2,
Random = 3,
}
impl_enum_discriminant!(ColorMode, None: 0, PerLED: 1, ModeSpecific: 2, Random: 3);
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct ModeData {
name: String,
value: i32,
flags: FlagSet<ModeFlag>,
speed_min: u32,
speed_max: u32,
speed: u32,
brightness_min: ProtocolOption<3, u32>,
brightness_max: ProtocolOption<3, u32>,
brightness: ProtocolOption<3, u32>,
color_mode: ColorMode,
colors: Vec<Color>,
colors_min: u32,
colors_max: u32,
direction: Direction,
id: u32,
}
impl ModeData {
pub fn name(&self) -> &str {
&self.name
}
pub fn id(&self) -> usize {
self.id as usize
}
pub(crate) fn set_id(&mut self, id: usize) {
self.id = id as u32;
}
pub fn flags(&self) -> FlagSet<ModeFlag> {
self.flags
}
pub fn brightness(&self) -> Option<u32> {
match self.flags.contains(ModeFlag::HasBrightness) {
true => self.brightness.value().copied(),
false => None,
}
}
pub fn set_brightness(&mut self, b: u32) {
if self.flags.contains(ModeFlag::HasBrightness) {
self.brightness.replace(b);
}
}
pub fn brightness_min(&self) -> Option<u32> {
match self.flags.contains(ModeFlag::HasBrightness) {
true => self.brightness_min.value().copied(),
false => None,
}
}
pub fn brightness_max(&self) -> Option<u32> {
match self.flags.contains(ModeFlag::HasBrightness) {
true => self.brightness_max.value().copied(),
false => None,
}
}
pub fn speed(&self) -> Option<u32> {
self.flags
.contains(ModeFlag::HasSpeed)
.then_some(self.speed)
}
pub fn set_speed(&mut self, sp: u32) {
if self.flags.contains(ModeFlag::HasSpeed) {
self.speed = sp;
}
}
pub fn speed_min(&self) -> Option<u32> {
self.flags
.contains(ModeFlag::HasSpeed)
.then_some(self.speed_min)
}
pub fn speed_max(&self) -> Option<u32> {
self.flags
.contains(ModeFlag::HasSpeed)
.then_some(self.speed_max)
}
pub fn direction(&self) -> Option<Direction> {
self.flags
.contains(ModeFlag::HasDirection)
.then_some(self.direction)
}
pub fn set_direction(&mut self, dir: Direction) {
if self.flags.contains(ModeFlag::HasDirection) {
self.direction = dir;
}
}
pub fn color_mode(&self) -> ColorMode {
self.color_mode
}
pub fn colors(&self) -> &[Color] {
&self.colors
}
pub fn colors_min(&self) -> Option<u32> {
(!self.colors.is_empty()).then_some(self.colors_min)
}
pub fn colors_max(&self) -> Option<u32> {
(!self.colors.is_empty()).then_some(self.colors_max)
}
}
impl DeserFromBuf for ModeData {
fn deserialize(buf: &mut ReceivedMessage<'_>) -> OpenRgbResult<Self> {
let name = buf.read_value()?;
let value = buf.read_value()?;
let flags = buf.read_value()?;
let speed_min = buf.read_value()?;
let speed_max = buf.read_value()?;
let brightness_min = buf.read_value()?;
let brightness_max = buf.read_value()?;
let brightness = buf.read_value()?;
let colors_min = buf.read_value()?;
let colors_max = buf.read_value()?;
let speed = buf.read_value()?;
let direction = buf.read_value::<Direction>()?;
let color_mode = buf.read_value()?;
let colors = buf.read_value::<Vec<Color>>()?;
Ok(ModeData {
id: u32::MAX,
name,
value,
flags,
speed_min,
speed_max,
speed,
brightness_min,
brightness_max,
brightness,
colors_min,
colors_max,
direction,
color_mode,
colors,
})
}
}
impl SerToBuf for ModeData {
fn serialize(&self, buf: &mut WriteMessage) -> OpenRgbResult<()> {
buf.push_value(&self.name)?
.push_value(&self.value)?
.push_value(&self.flags)?
.push_value(&self.speed_min)?
.push_value(&self.speed_max)?
.push_value(&self.brightness_min)?
.push_value(&self.brightness_max)?
.push_value(&self.brightness)?
.push_value(&self.colors_min)?
.push_value(&self.colors_max)?
.push_value(&self.speed)?
.push_value(&self.direction)?
.push_value(&self.color_mode)?
.push_value(&self.colors)?;
Ok(())
}
}
#[cfg(test)]
mod tests {
use std::error::Error;
use flagset::FlagSet;
use crate::{
Color, ModeData, ProtocolOption, WriteMessage,
data::{ColorMode, Direction},
protocol::data::ModeFlag,
};
use ModeFlag::*;
#[tokio::test]
async fn test_read_flag() -> Result<(), Box<dyn Error>> {
let mut buf = WriteMessage::new(crate::DEFAULT_PROTOCOL);
let mut msg = buf.push_value(&154_u32)?.to_received_msg();
assert_eq!(
msg.read_value::<FlagSet<ModeFlag>>()?,
HasDirectionLR | HasDirectionHV | HasBrightness | HasRandomColor
);
Ok(())
}
#[tokio::test]
async fn test_write_flag() -> Result<(), Box<dyn Error>> {
let mut buf = WriteMessage::new(crate::DEFAULT_PROTOCOL);
let mut msg = buf
.push_value(&(ModeFlag::HasBrightness | ModeFlag::HasSpeed))?
.to_received_msg();
assert_eq!(msg.read_value::<u32>()?, (1 << 4) | (1 << 0));
Ok(())
}
#[tokio::test]
async fn test_read_dir() -> Result<(), Box<dyn Error>> {
let mut buf = WriteMessage::new(crate::DEFAULT_PROTOCOL);
let mut msg = buf.push_value(&3_u32)?.to_received_msg();
assert_eq!(msg.read_value::<Direction>()?, Direction::Down);
Ok(())
}
#[tokio::test]
async fn test_write_dir() -> Result<(), Box<dyn Error>> {
let mut buf = WriteMessage::new(crate::DEFAULT_PROTOCOL);
let mut msg = buf.push_value(&Direction::Down)?.to_received_msg();
assert_eq!(msg.read_value::<u32>()?, 3);
Ok(())
}
#[tokio::test]
async fn test_read_color_mode() -> Result<(), Box<dyn Error>> {
let mut buf = WriteMessage::new(crate::DEFAULT_PROTOCOL);
let mut msg = buf.push_value(&3_u32)?.to_received_msg();
assert_eq!(msg.read_value::<ColorMode>()?, ColorMode::Random);
Ok(())
}
#[tokio::test]
async fn test_write_color_mode() -> Result<(), Box<dyn Error>> {
let mut buf = WriteMessage::new(crate::DEFAULT_PROTOCOL);
let mut msg = buf.push_value(&ColorMode::Random)?.to_received_msg();
assert_eq!(msg.read_value::<u32>()?, 3);
Ok(())
}
#[test]
fn test_read_001() -> Result<(), Box<dyn Error>> {
let mut buf = WriteMessage::new(3);
let mut msg = buf
.push_value(&"test")? .push_value(&46_i32)? .push_value(&31_u32)? .push_value(&10_u32)? .push_value(&1000_u32)? .push_value(&1_u32)? .push_value(&1024_u32)? .push_value(&512_u32)? .push_value(&0_u32)? .push_value(&256_u32)? .push_value(&51_u32)? .push_value(&4_u32)? .push_value(&1_u32)? .push_value(&[
Color {
r: 37,
g: 54,
b: 126,
},
Color {
r: 37,
g: 54,
b: 255,
},
])?
.to_received_msg();
let mode_data = msg.read_value::<ModeData>()?;
assert_eq!(mode_data.name(), "test");
assert_eq!(mode_data.speed_min(), Some(10));
assert_eq!(mode_data.speed_max(), Some(1000));
assert_eq!(mode_data.brightness_min(), Some(1));
assert_eq!(mode_data.brightness_max(), Some(1024));
assert_eq!(mode_data.colors_min(), Some(0));
assert_eq!(mode_data.colors_max(), Some(256));
assert_eq!(mode_data.speed(), Some(51));
assert_eq!(mode_data.brightness(), Some(512));
assert_eq!(mode_data.direction(), Some(Direction::Horizontal));
assert_eq!(mode_data.color_mode(), ColorMode::PerLED);
assert_eq!(
mode_data.colors(),
&[
Color {
r: 37,
g: 54,
b: 126
},
Color {
r: 37,
g: 54,
b: 255
}
]
);
Ok(())
}
#[test]
fn test_write_001() -> Result<(), Box<dyn Error>> {
let mode = ModeData {
id: u32::MAX,
name: "test".to_owned(),
value: 46,
flags: HasDirection | HasSpeed | HasBrightness,
speed_min: 10,
speed_max: 1000,
brightness_min: ProtocolOption::Some(1),
brightness_max: ProtocolOption::Some(231),
colors_min: 0,
colors_max: 256,
speed: 51,
brightness: ProtocolOption::Some(50),
direction: Direction::Horizontal,
color_mode: ColorMode::PerLED,
colors: vec![
Color {
r: 37,
g: 54,
b: 126,
},
Color {
r: 37,
g: 54,
b: 255,
},
],
};
let mut buf = WriteMessage::new(crate::DEFAULT_PROTOCOL);
buf.write_value(&mode)?;
let mut msg = buf.to_received_msg();
assert_eq!(mode, msg.read_value::<ModeData>()?);
Ok(())
}
}