/* * * Copyright (c) 2020-2022 Project CHIP Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ use crate::{ error::{Error, ErrorCode}, interaction_model::core::Transaction, tlv::TLVElement, }; use super::{AttrData, AttrDataEncoder, AttrDetails, CmdDataEncoder, CmdDetails}; pub trait ChangeNotifier<T> { fn consume_change(&mut self) -> Option<T>; } pub trait Handler { fn read(&self, attr: &AttrDetails, encoder: AttrDataEncoder) -> Result<(), Error>; fn write(&mut self, _attr: &AttrDetails, _data: AttrData) -> Result<(), Error> { Err(ErrorCode::AttributeNotFound.into()) } fn invoke( &mut self, _transaction: &mut Transaction, _cmd: &CmdDetails, _data: &TLVElement, _encoder: CmdDataEncoder, ) -> Result<(), Error> { Err(ErrorCode::CommandNotFound.into()) } } impl<T> Handler for &mut T where T: Handler, { fn read<'a>(&self, attr: &AttrDetails, encoder: AttrDataEncoder) -> Result<(), Error> { (**self).read(attr, encoder) } fn write(&mut self, attr: &AttrDetails, data: AttrData) -> Result<(), Error> { (**self).write(attr, data) } fn invoke( &mut self, transaction: &mut Transaction, cmd: &CmdDetails, data: &TLVElement, encoder: CmdDataEncoder, ) -> Result<(), Error> { (**self).invoke(transaction, cmd, data, encoder) } } pub trait NonBlockingHandler: Handler {} impl<T> NonBlockingHandler for &mut T where T: NonBlockingHandler {} pub struct EmptyHandler; impl EmptyHandler { pub const fn chain<H>( self, handler_endpoint: u16, handler_cluster: u32, handler: H, ) -> ChainedHandler<H, Self> { ChainedHandler { handler_endpoint, handler_cluster, handler, next: self, } } } impl Handler for EmptyHandler { fn read(&self, _attr: &AttrDetails, _encoder: AttrDataEncoder) -> Result<(), Error> { Err(ErrorCode::AttributeNotFound.into()) } } impl NonBlockingHandler for EmptyHandler {} impl ChangeNotifier<(u16, u32)> for EmptyHandler { fn consume_change(&mut self) -> Option<(u16, u32)> { None } } pub struct ChainedHandler<H, T> { pub handler_endpoint: u16, pub handler_cluster: u32, pub handler: H, pub next: T, } impl<H, T> ChainedHandler<H, T> { pub const fn chain<H2>( self, handler_endpoint: u16, handler_cluster: u32, handler: H2, ) -> ChainedHandler<H2, Self> { ChainedHandler { handler_endpoint, handler_cluster, handler, next: self, } } } impl<H, T> Handler for ChainedHandler<H, T> where H: Handler, T: Handler, { fn read(&self, attr: &AttrDetails, encoder: AttrDataEncoder) -> Result<(), Error> { if self.handler_endpoint == attr.endpoint_id && self.handler_cluster == attr.cluster_id { self.handler.read(attr, encoder) } else { self.next.read(attr, encoder) } } fn write(&mut self, attr: &AttrDetails, data: AttrData) -> Result<(), Error> { if self.handler_endpoint == attr.endpoint_id && self.handler_cluster == attr.cluster_id { self.handler.write(attr, data) } else { self.next.write(attr, data) } } fn invoke( &mut self, transaction: &mut Transaction, cmd: &CmdDetails, data: &TLVElement, encoder: CmdDataEncoder, ) -> Result<(), Error> { if self.handler_endpoint == cmd.endpoint_id && self.handler_cluster == cmd.cluster_id { self.handler.invoke(transaction, cmd, data, encoder) } else { self.next.invoke(transaction, cmd, data, encoder) } } } impl<H, T> NonBlockingHandler for ChainedHandler<H, T> where H: NonBlockingHandler, T: NonBlockingHandler, { } impl<H, T> ChangeNotifier<(u16, u32)> for ChainedHandler<H, T> where H: ChangeNotifier<()>, T: ChangeNotifier<(u16, u32)>, { fn consume_change(&mut self) -> Option<(u16, u32)> { if self.handler.consume_change().is_some() { Some((self.handler_endpoint, self.handler_cluster)) } else { self.next.consume_change() } } } #[allow(unused_macros)] #[macro_export] macro_rules! handler_chain_type { ($h:ty) => { $crate::data_model::objects::ChainedHandler<$h, $crate::data_model::objects::EmptyHandler> }; ($h1:ty $(, $rest:ty)+) => { $crate::data_model::objects::ChainedHandler<$h1, handler_chain_type!($($rest),+)> }; ($h:ty | $f:ty) => { $crate::data_model::objects::ChainedHandler<$h, $f> }; ($h1:ty $(, $rest:ty)+ | $f:ty) => { $crate::data_model::objects::ChainedHandler<$h1, handler_chain_type!($($rest),+ | $f)> }; } #[cfg(feature = "nightly")] pub mod asynch { use crate::{ data_model::objects::{AttrData, AttrDataEncoder, AttrDetails, CmdDataEncoder, CmdDetails}, error::{Error, ErrorCode}, interaction_model::core::Transaction, tlv::TLVElement, }; use super::{ChainedHandler, EmptyHandler, Handler, NonBlockingHandler}; pub trait AsyncHandler { async fn read<'a>( &'a self, attr: &'a AttrDetails<'_>, encoder: AttrDataEncoder<'a, '_, '_>, ) -> Result<(), Error>; async fn write<'a>( &'a mut self, _attr: &'a AttrDetails<'_>, _data: AttrData<'a>, ) -> Result<(), Error> { Err(ErrorCode::AttributeNotFound.into()) } async fn invoke<'a>( &'a mut self, _transaction: &'a mut Transaction<'_, '_>, _cmd: &'a CmdDetails<'_>, _data: &'a TLVElement<'_>, _encoder: CmdDataEncoder<'a, '_, '_>, ) -> Result<(), Error> { Err(ErrorCode::CommandNotFound.into()) } } impl<T> AsyncHandler for &mut T where T: AsyncHandler, { async fn read<'a>( &'a self, attr: &'a AttrDetails<'_>, encoder: AttrDataEncoder<'a, '_, '_>, ) -> Result<(), Error> { (**self).read(attr, encoder).await } async fn write<'a>( &'a mut self, attr: &'a AttrDetails<'_>, data: AttrData<'a>, ) -> Result<(), Error> { (**self).write(attr, data).await } async fn invoke<'a>( &'a mut self, transaction: &'a mut Transaction<'_, '_>, cmd: &'a CmdDetails<'_>, data: &'a TLVElement<'_>, encoder: CmdDataEncoder<'a, '_, '_>, ) -> Result<(), Error> { (**self).invoke(transaction, cmd, data, encoder).await } } pub struct Asyncify<T>(pub T); impl<T> AsyncHandler for Asyncify<T> where T: NonBlockingHandler, { async fn read<'a>( &'a self, attr: &'a AttrDetails<'_>, encoder: AttrDataEncoder<'a, '_, '_>, ) -> Result<(), Error> { Handler::read(&self.0, attr, encoder) } async fn write<'a>( &'a mut self, attr: &'a AttrDetails<'_>, data: AttrData<'a>, ) -> Result<(), Error> { Handler::write(&mut self.0, attr, data) } async fn invoke<'a>( &'a mut self, transaction: &'a mut Transaction<'_, '_>, cmd: &'a CmdDetails<'_>, data: &'a TLVElement<'_>, encoder: CmdDataEncoder<'a, '_, '_>, ) -> Result<(), Error> { Handler::invoke(&mut self.0, transaction, cmd, data, encoder) } } impl AsyncHandler for EmptyHandler { async fn read<'a>( &'a self, _attr: &'a AttrDetails<'_>, _encoder: AttrDataEncoder<'a, '_, '_>, ) -> Result<(), Error> { Err(ErrorCode::AttributeNotFound.into()) } } impl<H, T> AsyncHandler for ChainedHandler<H, T> where H: AsyncHandler, T: AsyncHandler, { async fn read<'a>( &'a self, attr: &'a AttrDetails<'_>, encoder: AttrDataEncoder<'a, '_, '_>, ) -> Result<(), Error> { if self.handler_endpoint == attr.endpoint_id && self.handler_cluster == attr.cluster_id { self.handler.read(attr, encoder).await } else { self.next.read(attr, encoder).await } } async fn write<'a>( &'a mut self, attr: &'a AttrDetails<'_>, data: AttrData<'a>, ) -> Result<(), Error> { if self.handler_endpoint == attr.endpoint_id && self.handler_cluster == attr.cluster_id { self.handler.write(attr, data).await } else { self.next.write(attr, data).await } } async fn invoke<'a>( &'a mut self, transaction: &'a mut Transaction<'_, '_>, cmd: &'a CmdDetails<'_>, data: &'a TLVElement<'_>, encoder: CmdDataEncoder<'a, '_, '_>, ) -> Result<(), Error> { if self.handler_endpoint == cmd.endpoint_id && self.handler_cluster == cmd.cluster_id { self.handler.invoke(transaction, cmd, data, encoder).await } else { self.next.invoke(transaction, cmd, data, encoder).await } } } }