#![warn(
future_incompatible,
nonstandard_style,
rust_2018_idioms,
trivial_casts,
trivial_numeric_casts,
missing_debug_implementations,
missing_docs,
unreachable_pub,
unsafe_code,
unused_extern_crates,
unused_import_braces,
unused_qualifications,
unused_results,
)]
#[macro_use]
extern crate error_chain;
#[allow(unused_imports)]
#[macro_use]
extern crate log;
use std::fmt::{Display, Formatter};
use std::str::FromStr;
#[derive(Clone, Debug)]
pub enum SolidColor {
Red,
Green,
Yellow,
Blue,
White,
Cyan,
Magenta,
Custom {
red: u8,
green: u8,
blue: u8,
},
}
#[derive(Clone, Debug)]
pub enum Wave {
Short,
Long,
OverlappingShort,
OverlappingLong,
}
#[derive(Clone, Debug)]
pub enum Pattern {
Police,
TrafficLights,
Random(u8),
#[cfg(target_os = "windows")]
Rainbow,
#[cfg(target_os = "windows")]
Sea,
#[cfg(target_os = "windows")]
WhiteWave,
#[cfg(target_os = "windows")]
Synthetic,
}
pub trait Device {
fn id(&self) -> String;
fn turn_off(&self) -> error::Result<()>;
fn set_solid_color(&self, color: SolidColor) -> error::Result<()>;
fn set_fade_to_color(&self, color: SolidColor, fade_duration: u8) -> error::Result<()>;
fn set_color_strobe(
&self,
color: SolidColor,
strobe_speed: u8,
repeat_count: u8,
) -> error::Result<()>;
fn set_color_wave(
&self,
color: SolidColor,
wave_pattern: Wave,
wave_speed: u8,
repeat_count: u8,
) -> error::Result<()>;
fn set_pattern(&self, pattern: Pattern, repeat_count: u8) -> error::Result<()>;
}
#[derive(Clone, Debug)]
pub enum SpecificLED {
All,
AllFront,
AllBack,
Number(u8),
}
pub trait TargetedDevice: Device {
fn set_specific_led(&mut self, led: SpecificLED) -> error::Result<()>;
}
impl Display for SolidColor {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
fn to_hex(v: &u8) -> String {
format!("{:#04x}", v)[2..].to_string()
}
write!(
f,
"{}",
match self {
SolidColor::Red => "red".to_string(),
SolidColor::Green => "green".to_string(),
SolidColor::Yellow => "yellow".to_string(),
SolidColor::Blue => "blue".to_string(),
SolidColor::White => "white".to_string(),
SolidColor::Cyan => "cyan".to_string(),
SolidColor::Magenta => "magenta".to_string(),
SolidColor::Custom { red, green, blue } =>
format!("{}{}{}", to_hex(red), to_hex(green), to_hex(blue)),
}
)
}
}
impl FromStr for SolidColor {
type Err = error::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase();
match s.as_str() {
"red" => Ok(SolidColor::Red),
"green" => Ok(SolidColor::Green),
"yellow" => Ok(SolidColor::Yellow),
"blue" => Ok(SolidColor::Blue),
"white" => Ok(SolidColor::White),
"cyan" => Ok(SolidColor::Cyan),
"magenta" => Ok(SolidColor::Magenta),
_ => {
if s.len() == 6 && s.chars().all(|c| c.is_ascii_hexdigit()) {
Ok(SolidColor::Custom {
red: u8::from_str_radix(&s[0..1], 16)?,
green: u8::from_str_radix(&s[2..3], 16)?,
blue: u8::from_str_radix(&s[4..5], 16)?,
})
} else {
Err(error::ErrorKind::InvalidColor.into())
}
}
}
}
}
impl Display for Wave {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Wave::Short => "short",
Wave::Long => "long",
Wave::OverlappingShort => "overlapping short",
Wave::OverlappingLong => "overlapping long",
}
)
}
}
impl FromStr for Wave {
type Err = error::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase();
match s.as_str() {
"short" => Ok(Wave::Short),
"long" => Ok(Wave::Long),
"overlapping short" => Ok(Wave::OverlappingShort),
"overlapping long" => Ok(Wave::OverlappingLong),
_ => Err(error::ErrorKind::InvalidPattern.into()),
}
}
}
impl Display for Pattern {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
Pattern::Police => "police".to_string(),
Pattern::TrafficLights => "traffic lights".to_string(),
Pattern::Random(n) => format!("random {}", n),
#[cfg(target_os = "windows")]
Pattern::Rainbow => "rainbow".to_string(),
#[cfg(target_os = "windows")]
Pattern::Sea => "sea".to_string(),
#[cfg(target_os = "windows")]
Pattern::WhiteWave => "white wave".to_string(),
#[cfg(target_os = "windows")]
Pattern::Synthetic => "synthetic".to_string(),
}
)
}
}
impl FromStr for Pattern {
type Err = error::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase();
match s.as_str() {
"police" => Ok(Pattern::Police),
"traffic lights" => Ok(Pattern::TrafficLights),
"random 1" => Ok(Pattern::Random(1)),
"random 2" => Ok(Pattern::Random(2)),
"random 3" => Ok(Pattern::Random(3)),
"random 4" => Ok(Pattern::Random(4)),
"random 5" => Ok(Pattern::Random(5)),
#[cfg(target_os = "windows")]
"rainbow" => Ok(Pattern::Rainbow),
#[cfg(target_os = "windows")]
"sea" => Ok(Pattern::Sea),
#[cfg(target_os = "windows")]
"white wave" => Ok(Pattern::WhiteWave),
#[cfg(target_os = "windows")]
"synthetic" => Ok(Pattern::Synthetic),
_ => Err(error::ErrorKind::InvalidPattern.into()),
}
}
}
impl Display for SpecificLED {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
write!(
f,
"{}",
match self {
SpecificLED::All => "all".to_string(),
SpecificLED::AllFront => "front".to_string(),
SpecificLED::AllBack => "back".to_string(),
SpecificLED::Number(n) => n.to_string(),
}
)
}
}
impl FromStr for SpecificLED {
type Err = error::Error;
fn from_str(s: &str) -> Result<Self, Self::Err> {
let s = s.to_lowercase();
match s.as_str() {
"all" => Ok(SpecificLED::All),
"front" => Ok(SpecificLED::AllFront),
"back" => Ok(SpecificLED::AllBack),
"1" => Ok(SpecificLED::Number(1)),
"2" => Ok(SpecificLED::Number(2)),
"3" => Ok(SpecificLED::Number(3)),
"4" => Ok(SpecificLED::Number(4)),
"5" => Ok(SpecificLED::Number(5)),
"6" => Ok(SpecificLED::Number(6)),
_ => Err(error::ErrorKind::InvalidLED.into()),
}
}
}
#[allow(missing_docs)]
pub mod error {
error_chain! {
errors {
#[doc("The color value supplied was not recognized")]
InvalidColor {
description("The color value supplied was not recognized")
display("The color value supplied was not recognized")
}
#[doc("The pattern value supplied was not recognized")]
InvalidPattern {
description("The pattern value supplied was not recognized")
display("The pattern value supplied was not recognized")
}
#[doc("The LED number is either invalid or not supported by the connected device")]
InvalidLED {
description("The LED number is either invalid or not supported by the connected device")
display("The LED number is either invalid or not supported by the connected device")
}
#[doc("The provided device ID was incorrectly formatted")]
InvalidDeviceID {
description("The provided device ID was incorrectly formatted")
display("The provided device ID was incorrectly formatted")
}
#[doc("No device was discovered, or the ID did not resolve to a device")]
DeviceNotFound {
description("No device was discovered, or the ID did not resolve to a device")
display("No device was discovered, or the ID did not resolve to a device")
}
#[doc("The server indicated an invalid request")]
InvalidRequest {
description("The server indicated an invalid request")
display("The server indicated an invalid request")
}
#[doc("An unexpected HTTP error was returned")]
UnexpectedError(sc: u16) {
description("An unexpected HTTP error was returned")
display("An unexpected HTTP error was returned: {}", sc)
}
#[doc("The command is not supported by the current device, or connection to the device")]
UnsupportedCommand {
description("The command is not supported by the current device, or connection to the device")
display("The command is not supported by the current device, or connection to the device")
}
}
foreign_links {
CustomFmt(::std::num::ParseIntError);
Request(::reqwest::Error);
Fmt(::std::fmt::Error);
}
}
}
#[cfg(feature = "usb")]
pub mod usb_hid;
#[cfg(feature = "webhook")]
pub mod webhook;