use std::iter::{Chain, FlatMap};
use le_stream::{FromLeStream, ToLeStream};
use num_traits::FromPrimitive;
use crate::Error;
use crate::ezsp::Status;
use crate::frame::Parameter;
use crate::frame::responds_with::RespondsWith;
use crate::types::ByteSizedVec;
const ID: u16 = 0x0002;
#[derive(Clone, Debug, Eq, PartialEq, ToLeStream)]
pub(crate) struct Command {
endpoint: u8,
profile_id: u16,
device_id: u16,
app_flags: u8,
clusters: Clusters,
}
impl Command {
#[must_use]
pub fn new(
endpoint: u8,
profile_id: u16,
device_id: u16,
app_flags: u8,
input_cluster_list: ByteSizedVec<u16>,
output_cluster_list: ByteSizedVec<u16>,
) -> Self {
Self {
endpoint,
profile_id,
device_id,
app_flags,
clusters: Clusters::new(input_cluster_list, output_cluster_list),
}
}
}
#[derive(Clone, Debug, Eq, PartialEq)]
pub(crate) struct Clusters {
input_cluster_counts: u8,
output_cluster_counts: u8,
#[expect(clippy::struct_field_names)]
input_clusters: ByteSizedVec<u16>,
#[expect(clippy::struct_field_names)]
output_clusters: ByteSizedVec<u16>,
}
impl Clusters {
#[must_use]
pub fn new(input_clusters: ByteSizedVec<u16>, output_clusters: ByteSizedVec<u16>) -> Self {
Self {
#[expect(clippy::cast_possible_truncation)]
input_cluster_counts: input_clusters.len() as u8,
#[expect(clippy::cast_possible_truncation)]
output_cluster_counts: output_clusters.len() as u8,
input_clusters,
output_clusters,
}
}
}
impl ToLeStream for Clusters {
type Iter = Chain<
Chain<
Chain<<u8 as ToLeStream>::Iter, <u8 as ToLeStream>::Iter>,
FlatMap<
<ByteSizedVec<u16> as IntoIterator>::IntoIter,
<u16 as ToLeStream>::Iter,
fn(u16) -> <u16 as ToLeStream>::Iter,
>,
>,
FlatMap<
<ByteSizedVec<u16> as IntoIterator>::IntoIter,
<u16 as ToLeStream>::Iter,
fn(u16) -> <u16 as ToLeStream>::Iter,
>,
>;
fn to_le_stream(self) -> Self::Iter {
#[expect(trivial_casts)]
self.input_cluster_counts
.to_le_stream()
.chain(self.output_cluster_counts.to_le_stream())
.chain(
self.input_clusters
.into_iter()
.flat_map(ToLeStream::to_le_stream as _),
)
.chain(
self.output_clusters
.into_iter()
.flat_map(ToLeStream::to_le_stream as _),
)
}
}
impl Parameter for Command {
const ID: u16 = ID;
}
impl RespondsWith for Command {
type Response = Response;
}
#[derive(Clone, Debug, Eq, PartialEq, FromLeStream)]
pub struct Response {
status: u8,
}
impl Parameter for Response {
const ID: u16 = ID;
}
impl TryFrom<Response> for () {
type Error = Error;
fn try_from(response: Response) -> Result<Self, Self::Error> {
match Status::from_u8(response.status).ok_or(response.status) {
Ok(Status::Success) => Ok(()),
other => Err(other.into()),
}
}
}