rs_matter/dm/clusters/
desc.rs1use core::fmt::Debug;
21
22use crate::dm::{ArrayAttributeRead, Cluster, Dataver, Endpoint, EndptId, Metadata, ReadContext};
23use crate::error::{Error, ErrorCode};
24use crate::tlv::{TLVBuilderParent, ToTLVArrayBuilder, ToTLVBuilder};
25use crate::utils::sync::DynBase;
26use crate::with;
27
28pub use crate::dm::clusters::decl::descriptor::*;
29
30#[derive(Debug)]
32#[cfg_attr(feature = "defmt", derive(defmt::Format))]
33struct StandardPartsMatcher;
34
35impl DynBase for StandardPartsMatcher {}
36
37impl PartsMatcher for StandardPartsMatcher {
38 fn matches(&self, our_endpoint: EndptId, endpoint: EndptId) -> bool {
39 our_endpoint == 0 && endpoint != our_endpoint
40 }
41}
42
43#[derive(Debug)]
50#[cfg_attr(feature = "defmt", derive(defmt::Format))]
51struct AggregatorPartsMatcher;
52
53impl DynBase for AggregatorPartsMatcher {}
54
55impl PartsMatcher for AggregatorPartsMatcher {
56 fn matches(&self, our_endpoint: EndptId, endpoint: EndptId) -> bool {
57 endpoint != our_endpoint && endpoint != 0
58 }
59}
60
61pub trait PartsMatcher: DynBase + Debug {
68 fn matches(&self, our_endpoint: EndptId, endpoint: EndptId) -> bool;
74}
75
76impl<T> PartsMatcher for &T
77where
78 T: PartsMatcher,
79{
80 fn matches(&self, our_endpoint: EndptId, endpoint: EndptId) -> bool {
81 (**self).matches(our_endpoint, endpoint)
82 }
83}
84
85#[derive(Clone, Debug)]
87#[cfg_attr(feature = "defmt", derive(defmt::Format))]
88pub struct DescHandler<'a> {
89 dataver: Dataver,
90 matcher: &'a dyn PartsMatcher,
91}
92
93impl DescHandler<'static> {
94 pub const fn new(dataver: Dataver) -> Self {
97 Self::new_matching(dataver, &StandardPartsMatcher)
98 }
99
100 pub const fn new_aggregator(dataver: Dataver) -> Self {
103 Self::new_matching(dataver, &AggregatorPartsMatcher)
104 }
105}
106
107impl<'a> DescHandler<'a> {
108 pub const fn new_matching(dataver: Dataver, matcher: &'a dyn PartsMatcher) -> DescHandler<'a> {
111 Self { dataver, matcher }
112 }
113
114 pub const fn adapt(self) -> HandlerAdaptor<Self> {
116 HandlerAdaptor(self)
117 }
118
119 fn with_endpoint<F, R>(ctx: impl ReadContext, f: F) -> Result<R, Error>
120 where
121 F: FnOnce(&Endpoint) -> Result<R, Error>,
122 {
123 let metadata = ctx.metadata();
124
125 metadata.access(|node| {
126 let endpoint = node
127 .endpoint(ctx.attr().endpoint_id)
128 .ok_or_else(|| Error::new(ErrorCode::EndpointNotFound))?;
129
130 f(endpoint)
131 })
132 }
133}
134
135impl ClusterHandler for DescHandler<'_> {
136 const CLUSTER: Cluster<'static> = FULL_CLUSTER.with_attrs(with!(required)).with_cmds(with!());
137
138 fn dataver(&self) -> u32 {
139 self.dataver.get()
140 }
141
142 fn dataver_changed(&self) {
143 self.dataver.changed();
144 }
145
146 fn device_type_list<P: TLVBuilderParent>(
147 &self,
148 ctx: impl ReadContext,
149 builder: ArrayAttributeRead<DeviceTypeStructArrayBuilder<P>, DeviceTypeStructBuilder<P>>,
150 ) -> Result<P, Error> {
151 Self::with_endpoint(ctx, |endpoint| match builder {
152 ArrayAttributeRead::ReadAll(mut builder) => {
153 for dev_type in endpoint.device_types {
154 builder = builder
155 .push()?
156 .device_type(dev_type.dtype as _)?
157 .revision(dev_type.drev)?
158 .end()?;
159 }
160
161 builder.end()
162 }
163 ArrayAttributeRead::ReadOne(index, builder) => {
164 let Some(dev_type) = endpoint.device_types.get(index as usize) else {
165 return Err(ErrorCode::ConstraintError.into());
166 };
167
168 builder
169 .device_type(dev_type.dtype as _)?
170 .revision(dev_type.drev)?
171 .end()
172 }
173 ArrayAttributeRead::ReadNone(builder) => builder.end(),
174 })
175 }
176
177 fn server_list<P: TLVBuilderParent>(
178 &self,
179 ctx: impl ReadContext,
180 builder: ArrayAttributeRead<ToTLVArrayBuilder<P, u32>, ToTLVBuilder<P, u32>>,
181 ) -> Result<P, Error> {
182 Self::with_endpoint(ctx, |endpoint| match builder {
183 ArrayAttributeRead::ReadAll(mut builder) => {
184 for cluster in endpoint.clusters {
185 builder = builder.push(&cluster.id)?;
186 }
187
188 builder.end()
189 }
190 ArrayAttributeRead::ReadOne(index, builder) => {
191 let Some(cluster) = endpoint.clusters.get(index as usize) else {
192 return Err(ErrorCode::ConstraintError.into());
193 };
194
195 builder.set(&cluster.id)
196 }
197 ArrayAttributeRead::ReadNone(builder) => builder.end(),
198 })
199 }
200
201 fn client_list<P: TLVBuilderParent>(
202 &self,
203 ctx: impl ReadContext,
204 builder: ArrayAttributeRead<ToTLVArrayBuilder<P, u32>, ToTLVBuilder<P, u32>>,
205 ) -> Result<P, Error> {
206 Self::with_endpoint(ctx, |endpoint| match builder {
207 ArrayAttributeRead::ReadAll(mut builder) => {
208 for client_id in endpoint.client_clusters {
209 builder = builder.push(client_id)?;
210 }
211 builder.end()
212 }
213 ArrayAttributeRead::ReadOne(index, builder) => {
214 let Some(client_id) = endpoint.client_clusters.get(index as usize) else {
215 return Err(ErrorCode::ConstraintError.into());
216 };
217 builder.set(client_id)
218 }
219 ArrayAttributeRead::ReadNone(builder) => builder.end(),
220 })
221 }
222
223 fn parts_list<P: TLVBuilderParent>(
224 &self,
225 ctx: impl ReadContext,
226 builder: ArrayAttributeRead<ToTLVArrayBuilder<P, u16>, ToTLVBuilder<P, u16>>,
227 ) -> Result<P, Error> {
228 let metadata = ctx.metadata();
229
230 metadata.access(|node| {
231 let mut ep_ids = node
232 .endpoints
233 .iter()
234 .map(|e| e.id)
235 .filter(|e| self.matcher.matches(ctx.attr().endpoint_id, *e));
236
237 match builder {
238 ArrayAttributeRead::ReadAll(mut builder) => {
239 for id in ep_ids {
240 builder = builder.push(&id)?;
241 }
242
243 builder.end()
244 }
245 ArrayAttributeRead::ReadOne(index, builder) => {
246 let Some(ep_id) = ep_ids.nth(index as usize) else {
247 return Err(ErrorCode::ConstraintError.into());
248 };
249
250 builder.set(&ep_id)
251 }
252 ArrayAttributeRead::ReadNone(builder) => builder.end(),
253 }
254 })
255 }
256}