From 472ca50ec0c78ed6b4e1ea30166437124d9fec13 Mon Sep 17 00:00:00 2001 From: Jacob Date: Fri, 2 May 2025 17:33:21 -0400 Subject: [PATCH] feat!: overhaul the light protocol (i.e. collection of traits) --- protocol/Cargo.toml | 10 ++++ protocol/src/light.rs | 131 ++++++++++++++++++++++++++++++++++-------- 2 files changed, 117 insertions(+), 24 deletions(-) diff --git a/protocol/Cargo.toml b/protocol/Cargo.toml index bef3409..5b2ff86 100644 --- a/protocol/Cargo.toml +++ b/protocol/Cargo.toml @@ -4,6 +4,16 @@ version = "0.1.0" edition = "2021" license = { workspace = true } +[features] +default = [] +serde = ["dep:serde"] + [dependencies] deranged = { workspace = true } derive_more = { workspace = true } +ext-trait = { workspace = true } +palette = { workspace = true } +snafu = { workspace = true } +strum = { workspace = true, features = ["derive"] } + +serde = { optional = true, workspace = true, features = ["derive"] } diff --git a/protocol/src/light.rs b/protocol/src/light.rs index 6a1c1d9..0e795c8 100644 --- a/protocol/src/light.rs +++ b/protocol/src/light.rs @@ -1,43 +1,126 @@ use std::{error::Error, future::Future}; use deranged::RangedU16; +use palette::Oklch; +use snafu::{ResultExt, Snafu}; -pub trait Light { - type IsOnError: Error; - fn is_on(&self) -> impl Future> + Send; +#[derive( + Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, strum::Display, strum::EnumIs, +)] +#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))] +pub enum State { + Off, + On, +} - type IsOffError: Error; - fn is_off(&self) -> impl Future> + Send; +impl State { + pub const fn invert(self) -> Self { + match self { + State::Off => State::On, + State::On => State::Off, + } + } +} - type TurnOnError: Error; - fn turn_on(&mut self) -> impl Future> + Send; +impl From for State { + fn from(bool: bool) -> Self { + if bool { + State::On + } else { + State::Off + } + } +} - type TurnOffError: Error; - fn turn_off(&mut self) -> impl Future> + Send; +impl From for bool { + fn from(state: State) -> Self { + state.is_on() + } +} - type ToggleError: Error; - fn toggle(&mut self) -> impl Future> + Send; +pub trait GetState { + type Error: Error; + fn get_state(&self) -> impl Future> + Send; +} + +#[ext_trait::extension(trait IsOff)] +impl T { + async fn is_off(&self) -> Result { + Ok(self.get_state().await?.is_off()) + } +} + +#[ext_trait::extension(trait IsOn)] +impl T { + async fn is_on(&self) -> Result { + Ok(self.get_state().await?.is_on()) + } +} + +pub trait SetState { + type Error: Error; + fn set_state(&mut self, state: State) -> impl Future> + Send; +} + +#[ext_trait::extension(trait TurnOff)] +impl T { + async fn turn_off(&mut self) -> Result<(), T::Error> { + self.set_state(State::Off).await + } +} + +#[ext_trait::extension(trait TurnOn)] +impl T { + async fn turn_on(&mut self) -> Result<(), T::Error> { + self.set_state(State::On).await + } +} + +#[derive(Debug, Clone, Snafu)] +enum InvertToToggleError { + GetStateError { source: GetStateError }, + SetStateError { source: SetStateError }, +} + +#[ext_trait::extension(trait InvertToToggle)] +impl T +where + ::Error: 'static, + ::Error: 'static, +{ + /// Toggle the light by setting it to the inverse of its current state + async fn toggle( + &mut self, + ) -> Result<(), InvertToToggleError<::Error, ::Error>> { + let state = self.get_state().await.context(GetStateSnafu)?; + self.set_state(state.invert()) + .await + .context(SetStateSnafu)?; + + Ok(()) + } +} + +pub trait Toggle { + type Error: Error; + fn toggle(&mut self, state: State) -> impl Future> + Send; } #[derive(Debug, Clone, Copy, derive_more::From, derive_more::Into)] pub struct Kelvin(pub RangedU16<2000, 10000>); -pub trait KelvinLight: Light { - type TurnToKelvinError: Error; - fn turn_to_kelvin( +pub trait TurnToTemperature { + type TurnToTemperatureError: Error; + fn turn_to_temperature( &mut self, temperature: Kelvin, - ) -> impl Future> + Send; + ) -> impl Future> + Send; } -// TODO: replace with a type from a respected and useful library -#[derive(Debug, Clone, Copy, derive_more::From, derive_more::Into)] -pub struct Rgb(pub u8, pub u8, pub u8); - -pub trait RgbLight: Light { - type TurnToRgbError: Error; - fn turn_to_rgb( +pub trait TurnToColor { + type TurnToColorError: Error; + fn turn_to_color( &mut self, - color: Rgb, - ) -> impl Future> + Send; + color: Oklch, + ) -> impl Future> + Send; }