use crate::http::{
client::{unity, AsRequest, Attempts, Client, Request, Selected},
state::{Color, Duration, Power, State, StateChange},
Select,
};
use reqwest::Method;
use std::num::NonZeroU8;
pub struct Toggle<'a, T: Select> {
parent: &'a Selected<'a, T>,
attempts: Option<NonZeroU8>,
}
impl<'a, T: Select> Toggle<'a, T> {
pub(crate) fn new(parent: &'a Selected<'a, T>) -> Self {
Self {
parent,
attempts: None,
}
}
pub fn transition<D: Into<Duration>>(&self, duration: D) -> Request<'_, Duration> {
Request {
client: self.parent.client,
path: format!("/lights/{}/toggle", self.parent.selector),
body: duration.into(),
method: Method::POST,
attempts: self.attempts.unwrap_or_else(unity),
}
}
}
impl<'a, T: Select> Attempts for Toggle<'a, T> {
fn set_attempts(&mut self, attempts: NonZeroU8) {
self.attempts = Some(attempts);
}
}
impl<'a, T: Select> AsRequest<()> for Toggle<'a, T> {
fn method() -> reqwest::Method {
Method::POST
}
fn client(&self) -> &'_ Client {
self.parent.client
}
fn path(&self) -> String {
format!("/lights/{}/toggle", self.parent.selector)
}
fn body(&self) -> &'_ () {
&()
}
fn attempts(&self) -> NonZeroU8 {
self.attempts.unwrap_or_else(unity)
}
}
#[doc(hidden)]
#[derive(Default, Serialize)]
pub struct SetStatePayload {
#[serde(flatten)]
state: State,
#[serde(skip_serializing_if = "Option::is_none")]
fast: Option<bool>,
}
pub struct SetState<'a, T: Select> {
parent: &'a Selected<'a, T>,
attempts: Option<NonZeroU8>,
payload: SetStatePayload,
}
impl<'a, T: Select> SetState<'a, T> {
pub(crate) fn new(parent: &'a Selected<'a, T>) -> Self {
Self {
parent,
payload: SetStatePayload::default(),
attempts: None,
}
}
pub fn power<P: Into<Power>>(&mut self, on: P) -> &'_ mut SetState<'a, T> {
self.payload.state.power = Some(on.into());
self
}
pub fn color(&mut self, color: Color) -> &'_ mut SetState<'a, T> {
self.payload.state.color = Some(color);
self
}
pub fn brightness(&mut self, brightness: f32) -> &'_ mut Self {
self.payload.state.brightness = Some(brightness);
self
}
pub fn transition<D: Into<Duration>>(&mut self, duration: D) -> &'_ mut Self {
self.payload.state.duration = Some(duration.into());
self
}
pub fn infrared(&mut self, ir: f32) -> &'_ mut Self {
self.payload.state.infrared = Some(ir);
self
}
pub fn fast(&mut self, quickly: bool) -> &'_ mut Self {
self.payload.fast = Some(quickly);
self
}
}
impl<'a, T: Select> Attempts for SetState<'a, T> {
fn set_attempts(&mut self, attempts: NonZeroU8) {
self.attempts = Some(attempts);
}
}
impl<'a, T: Select> AsRequest<SetStatePayload> for SetState<'a, T> {
fn method() -> reqwest::Method {
Method::PUT
}
fn client(&self) -> &'_ Client {
self.parent.client
}
fn path(&self) -> String {
format!("/lights/{}/state", self.parent.selector)
}
fn body(&self) -> &'_ SetStatePayload {
&self.payload
}
fn attempts(&self) -> NonZeroU8 {
self.attempts.unwrap_or_else(unity)
}
}
#[derive(Clone, Serialize)]
struct StateExt {
pub(crate) selector: String,
#[serde(flatten)]
pub(crate) state: State,
}
#[derive(Clone, Default, Serialize)]
#[doc(hidden)]
pub struct SetStatesPayload {
#[serde(rename = "states", skip_serializing_if = "Vec::is_empty")]
new: Vec<StateExt>,
#[serde(rename = "defaults", skip_serializing_if = "Option::is_none")]
default: Option<State>,
#[serde(skip_serializing_if = "Option::is_none")]
fast: Option<bool>,
}
#[derive(Clone)]
pub struct SetStates<'a> {
parent: &'a Client,
inner: SetStatesPayload,
attempts: Option<NonZeroU8>,
}
impl<'a> SetStates<'a> {
pub(crate) fn new(parent: &'a Client) -> Self {
Self {
parent,
inner: SetStatesPayload::default(),
attempts: None,
}
}
#[allow(clippy::needless_pass_by_value)]
pub fn add<T: Select>(&mut self, selector: T, state: State) -> &'_ mut Self {
self.inner.new.push(StateExt {
selector: format!("{}", selector),
state,
});
self
}
pub fn default(&mut self, state: State) -> &'_ mut Self {
self.inner.default = Some(state);
self
}
pub fn fast(&mut self, fast: bool) -> &'_ mut Self {
self.inner.fast = Some(fast);
self
}
}
impl<'a> Attempts for SetStates<'a> {
fn set_attempts(&mut self, attempts: NonZeroU8) {
self.attempts = Some(attempts);
}
}
impl<'a> AsRequest<SetStatesPayload> for SetStates<'a> {
fn method() -> reqwest::Method {
Method::PUT
}
fn client(&self) -> &'_ Client {
self.parent
}
fn path(&self) -> String {
"/lights/states".to_string()
}
fn body(&self) -> &'_ SetStatesPayload {
&self.inner
}
fn attempts(&self) -> NonZeroU8 {
self.attempts.unwrap_or_else(unity)
}
}
pub struct ChangeState<'a, T: Select> {
parent: &'a Selected<'a, T>,
change: StateChange,
attempts: Option<NonZeroU8>,
}
impl<'a, T: Select> ChangeState<'a, T> {
pub(crate) fn new(parent: &'a Selected<'a, T>) -> Self {
Self {
parent,
change: StateChange::default(),
attempts: None,
}
}
pub fn power<P: Into<Power>>(&mut self, on: P) -> &'_ mut Self {
self.change.power = Some(on.into());
self
}
pub fn transition<D: Into<Duration>>(&mut self, duration: D) -> &'_ mut Self {
self.change.duration = Some(duration.into());
self
}
pub fn hue(&mut self, hue: i16) -> &'_ mut Self {
self.change.hue = Some(hue);
self
}
pub fn saturation(&mut self, saturation: f32) -> &'_ mut Self {
self.change.saturation = Some(saturation);
self
}
pub fn brightness(&mut self, brightness: f32) -> &'_ mut Self {
self.change.brightness = Some(brightness);
self
}
pub fn kelvin(&mut self, temp: i16) -> &'_ mut Self {
self.change.kelvin = Some(temp);
self
}
pub fn infrared(&mut self, ir: f32) -> &'_ mut Self {
self.change.infrared = Some(ir);
self
}
}
impl<'a, T: Select> Attempts for ChangeState<'a, T> {
fn set_attempts(&mut self, attempts: NonZeroU8) {
self.attempts = Some(attempts);
}
}
impl<'a, T: Select> AsRequest<StateChange> for ChangeState<'a, T> {
fn method() -> reqwest::Method {
Method::POST
}
fn client(&self) -> &'_ Client {
self.parent.client
}
fn path(&self) -> String {
format!("/lights/{}/state/delta", self.parent.selector)
}
fn body(&self) -> &'_ StateChange {
&self.change
}
fn attempts(&self) -> NonZeroU8 {
self.attempts.unwrap_or_else(unity)
}
}
pub struct Cycle<'a, T: Select> {
parent: &'a Selected<'a, T>,
inner: CyclePayload<'a, T>,
attempts: Option<NonZeroU8>,
}
impl<'a, T: Select> Cycle<'a, T> {
pub(crate) fn new(parent: &'a Selected<'a, T>) -> Self {
Self {
parent,
inner: CyclePayload::new(&parent.selector),
attempts: None,
}
}
pub fn add(&mut self, next: State) -> &'_ mut Self {
self.inner.states.push(next);
self
}
pub fn default(&mut self, state: State) -> &'_ mut Self {
self.inner.default = Some(state);
self
}
pub fn rev(&mut self) -> &'_ mut Self {
self.inner.direction = if self.inner.direction == "forward" {
"backward"
} else {
"forward"
};
self
}
}
#[derive(Clone, Serialize)]
#[doc(hidden)]
pub struct CyclePayload<'a, T: Select> {
pub(crate) selector: &'a T,
pub(crate) direction: &'static str,
pub(crate) states: Vec<State>,
#[serde(rename = "defaults", skip_serializing_if = "Option::is_none")]
pub(crate) default: Option<State>,
}
impl<'a, T: Select> CyclePayload<'a, T> {
fn new(selector: &'a T) -> Self {
Self {
selector,
direction: "forward",
states: Vec::new(),
default: None,
}
}
}
impl<'a, T: Select> Attempts for Cycle<'a, T> {
fn set_attempts(&mut self, attempts: NonZeroU8) {
self.attempts = Some(attempts);
}
}
impl<'a, T: Select> AsRequest<CyclePayload<'a, T>> for Cycle<'a, T> {
fn method() -> reqwest::Method {
Method::POST
}
fn client(&self) -> &'_ Client {
self.parent.client
}
fn path(&self) -> String {
format!("/lights/{}/cycle", self.parent.selector)
}
fn body(&self) -> &'_ CyclePayload<'a, T> {
&self.inner
}
fn attempts(&self) -> NonZeroU8 {
self.attempts.unwrap_or_else(unity)
}
}