Files
smart-home-in-rust-with-hom…/protocol/src/light.rs
2026-07-12 19:34:25 -04:00

126 lines
3.1 KiB
Rust

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<bool> for State {
fn from(bool: bool) -> Self {
if bool {
State::On
} else {
State::Off
}
}
}
impl From<State> for bool {
fn from(state: State) -> Self {
state.is_on()
}
}
pub trait GetState {
type Error: Error;
fn get_state(&self) -> impl Future<Output = Result<State, Self::Error>> + Send;
}
#[ext_trait::extension(pub trait IsOff)]
impl<T: GetState> T {
fn is_off(&self) -> impl Future<Output = Result<bool, T::Error>> + Send {
self.get_state().map_ok(|state| state.is_off())
}
}
#[ext_trait::extension(pub trait IsOn)]
impl<T: GetState> T {
fn is_on(&self) -> impl Future<Output = Result<bool, T::Error>> + 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<Output = Result<(), Self::Error>> + Send;
}
#[ext_trait::extension(pub trait TurnOff)]
impl<T: SetState> T {
fn turn_off(&mut self) -> impl Future<Output = Result<(), T::Error>> + Send {
self.set_state(State::Off)
}
}
#[ext_trait::extension(pub trait TurnOn)]
impl<T: SetState> T {
fn turn_on(&mut self) -> impl Future<Output = Result<(), T::Error>> + Send {
self.set_state(State::On)
}
}
pub trait Toggle {
type Error: Error;
fn toggle(&mut self) -> impl Future<Output = Result<(), Self::Error>> + Send;
}
#[derive(Debug, Clone, Snafu)]
pub enum InvertToToggleError<GetStateError: Error + 'static, SetStateError: Error + 'static> {
GetStateError { source: GetStateError },
SetStateError { source: SetStateError },
}
impl<T: GetState + SetState + Send> Toggle for T
where
<T as GetState>::Error: 'static,
<T as SetState>::Error: 'static,
{
type Error = InvertToToggleError<<T as GetState>::Error, <T as SetState>::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<Output = Result<(), Self::Error>> + Send;
}
pub type Oklch = palette::Oklch<f64>;
pub trait TurnToColor {
type Error: Error;
fn turn_to_color(
&mut self,
color: Oklch,
) -> impl Future<Output = Result<(), Self::Error>> + Send;
}