rs_matter/tlv/traits/
skippable.rs1use pinned_init::init_from_closure;
19
20use crate::error::Error;
21use crate::tlv::{FromTLV, TLVElement, TLVTag, TLVWrite, ToTLV, TLV};
22use crate::utils::init::{try_init, Init, InitDefault, IntoFallibleInit};
23
24#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)]
29#[cfg_attr(feature = "defmt", derive(defmt::Format))]
30pub struct Skippable<T> {
31 value: T,
32}
33
34impl<T> Skippable<T> {
35 pub const fn new(value: T) -> Self {
37 Self { value }
38 }
39
40 pub fn init<I: Init<T, E>, E>(value: I) -> impl Init<Self, E> {
42 try_init!(Self {
43 value <- value,
44 }? E)
45 }
46
47 pub const fn value(&self) -> &T {
48 &self.value
49 }
50
51 pub const fn value_mut(&mut self) -> &mut T {
52 &mut self.value
53 }
54}
55
56impl<T> Skippable<T>
57where
58 T: Default + InitDefault,
59{
60 pub fn new_default() -> Self {
62 Self::new(T::default())
63 }
64
65 pub fn init_default() -> impl Init<Self> {
67 Self::init(T::init_default().into_fallible())
68 }
69}
70
71impl<T> Default for Skippable<T>
72where
73 T: Default,
74{
75 fn default() -> Self {
76 Self::new(T::default())
77 }
78}
79
80impl<T> InitDefault for Skippable<T>
81where
82 T: InitDefault,
83{
84 fn init_default() -> impl Init<Self> {
85 Self::init(T::init_default().into_fallible())
89 }
90}
91
92impl<T> core::ops::Deref for Skippable<T> {
93 type Target = T;
94
95 fn deref(&self) -> &Self::Target {
96 &self.value
97 }
98}
99
100impl<T> core::ops::DerefMut for Skippable<T> {
101 fn deref_mut(&mut self) -> &mut Self::Target {
102 &mut self.value
103 }
104}
105
106impl<'a, T> FromTLV<'a> for Skippable<T>
107where
108 T: FromTLV<'a> + Default + InitDefault,
109{
110 fn from_tlv(element: &TLVElement<'a>) -> Result<Self, Error> {
111 if element.is_empty() {
112 Ok(Self::new_default())
113 } else {
114 Ok(Self::new(T::from_tlv(element)?))
115 }
116 }
117
118 fn init_from_tlv(element: TLVElement<'a>) -> impl Init<Self, Error> {
119 unsafe {
120 init_from_closure(move |slot| {
121 if element.is_empty() {
122 Self::init(T::init_default().into_fallible()).__init(slot)
123 } else {
124 Self::init(T::init_from_tlv(element)).__init(slot)
125 }
126 })
127 }
128 }
129}
130
131impl<T> ToTLV for Skippable<T>
132where
133 T: ToTLV,
134{
135 fn to_tlv<W: TLVWrite>(&self, tag: &TLVTag, tw: W) -> Result<(), Error> {
136 self.value.to_tlv(tag, tw)
137 }
138
139 fn tlv_iter(&self, tag: TLVTag) -> impl Iterator<Item = Result<TLV<'_>, Error>> {
140 self.value.tlv_iter(tag)
141 }
142}
143
144#[cfg(test)]
145mod tests {
146 use crate::tlv::{FromTLV, TLVElement, TLVTag, ToTLV};
147 use crate::utils::init::InitMaybeUninit;
148 use crate::utils::storage::{Vec, WriteBuf};
149
150 use super::Skippable;
151
152 fn to_bytes<T: ToTLV>(t: &T, buf: &mut [u8]) -> usize {
154 let mut wb = WriteBuf::new(buf);
155 t.to_tlv(&TLVTag::Anonymous, &mut wb).unwrap();
156 wb.get_tail()
157 }
158
159 type Inner = Vec<u16, 4>;
162
163 fn inner(items: &[u16]) -> Inner {
164 let mut v = Inner::new();
165 for &i in items {
166 v.push(i).unwrap();
167 }
168 v
169 }
170
171 #[test]
173 fn present_value_roundtrips() {
174 let mut buf = [0u8; 32];
175 let len = to_bytes(&Skippable::new(inner(&[42, 43])), &mut buf);
176
177 let back = Skippable::<Inner>::from_tlv(&TLVElement::new(&buf[..len])).unwrap();
178 assert_eq!(back.value().as_slice(), &[42, 43]);
179 }
180
181 #[test]
184 fn missing_value_from_tlv_is_default() {
185 let empty = TLVElement::new(&[]);
186 assert!(empty.is_empty());
187
188 let s = Skippable::<Inner>::from_tlv(&empty).unwrap();
189 assert!(s.value().is_empty());
190 }
191
192 #[test]
194 fn init_from_tlv_defaults_on_empty_and_parses_otherwise() {
195 let mut slot = core::mem::MaybeUninit::<Skippable<Inner>>::uninit();
197 let s = slot
198 .try_init_with(Skippable::<Inner>::init_from_tlv(TLVElement::new(&[])))
199 .unwrap();
200 assert!(s.value().is_empty());
201
202 let mut buf = [0u8; 32];
204 let len = to_bytes(&Skippable::new(inner(&[7])), &mut buf);
205 let mut slot = core::mem::MaybeUninit::<Skippable<Inner>>::uninit();
206 let s = slot
207 .try_init_with(Skippable::<Inner>::init_from_tlv(TLVElement::new(
208 &buf[..len],
209 )))
210 .unwrap();
211 assert_eq!(s.value().as_slice(), &[7]);
212 }
213
214 #[test]
218 fn missing_trailing_skippable_field_deserializes_to_default() {
219 #[derive(Debug, ToTLV)]
221 struct Old {
222 a: u16,
223 b: u16,
224 }
225
226 #[derive(Debug, FromTLV)]
228 struct New {
229 a: u16,
230 b: u16,
231 trailing: Skippable<Vec<u16, 4>>,
232 }
233
234 let mut buf = [0u8; 64];
235 let len = to_bytes(&Old { a: 7, b: 9 }, &mut buf);
236
237 let new = New::from_tlv(&TLVElement::new(&buf[..len])).unwrap();
238 assert_eq!((new.a, new.b), (7, 9));
239 assert!(new.trailing.value().is_empty());
240 }
241
242 #[test]
245 fn trailing_skippable_field_roundtrips_when_present() {
246 #[derive(Debug, FromTLV, ToTLV)]
247 struct S {
248 a: u16,
249 trailing: Skippable<Vec<u16, 4>>,
250 }
251
252 let mut inner = Vec::new();
253 inner.push(1).unwrap();
254 inner.push(2).unwrap();
255
256 let mut buf = [0u8; 64];
257 let len = to_bytes(
258 &S {
259 a: 5,
260 trailing: Skippable::new(inner),
261 },
262 &mut buf,
263 );
264
265 let back = S::from_tlv(&TLVElement::new(&buf[..len])).unwrap();
266 assert_eq!(back.a, 5);
267 assert_eq!(back.trailing.value().as_slice(), &[1, 2]);
268 }
269}