use std::{error::Error, future::Future}; use deranged::RangedU16; use futures::TryFutureExt as _; use snafu::{ResultExt as _, Snafu}; #[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, } impl State { pub const fn inverted(self) -> Self { match self { State::Off => State::On, State::On => State::Off, } } } impl From for State { fn from(bool: bool) -> Self { if bool { State::On } else { State::Off } } } impl From for bool { fn from(state: State) -> Self { state.is_on() } } pub trait GetState { type Error: Error; fn get_state(&self) -> impl Future> + Send; } #[ext_trait::extension(pub trait IsOff)] impl T { fn is_off(&self) -> impl Future> + Send { self.get_state().map_ok(|state| state.is_off()) } } #[ext_trait::extension(pub trait IsOn)] impl T { fn is_on(&self) -> impl Future> + Send { self.get_state().map_ok(|state| state.is_on()) } } pub trait SetState { type Error: Error; fn set_state(&mut self, state: State) -> impl Future> + Send; } #[ext_trait::extension(pub trait TurnOff)] impl T { fn turn_off(&mut self) -> impl Future> + Send { self.set_state(State::Off) } } #[ext_trait::extension(pub trait TurnOn)] impl T { fn turn_on(&mut self) -> impl Future> + Send { self.set_state(State::On) } } pub trait Toggle { type Error: Error; fn toggle(&mut self) -> impl Future> + Send; } #[derive(Debug, Clone, Snafu)] pub enum InvertToToggleError { GetStateError { source: GetStateError }, SetStateError { source: SetStateError }, } impl Toggle for T where ::Error: 'static, ::Error: 'static, { type Error = InvertToToggleError<::Error, ::Error>; /// Toggle the light by setting it to the inverse of its current state async fn toggle(&mut self) -> Result<(), Self::Error> { let state = self.get_state().await.context(GetStateSnafu)?; self.set_state(state.inverted()) .await .context(SetStateSnafu)?; Ok(()) } } pub type Kelvin = RangedU16<2000, 10000>; pub trait TurnToTemperature { type Error: Error; fn turn_to_temperature( &mut self, temperature: Kelvin, ) -> impl Future> + Send; } pub type Oklch = palette::Oklch; pub trait TurnToColor { type Error: Error; fn turn_to_color( &mut self, color: Oklch, ) -> impl Future> + Send; }