coap_handler_implementations/
helpers.rs1use coap_message::{MessageOption, MutableWritableMessage, ReadableMessage};
2use coap_message_utils::option_value::Block2RequestData;
3use coap_numbers::option;
4
5use windowed_infinity::WindowedInfinity;
6
7pub(crate) fn optconvert<O: TryFrom<u16>>(option: u16) -> O {
10 option
11 .try_into()
12 .map_err(|_| "Response type can't express options required by handler")
13 .unwrap()
14}
15
16pub fn block2_write<F, R>(
32 block2: Block2RequestData,
33 response: &mut impl MutableWritableMessage,
34 f: F,
35) -> R
36where
37 F: FnOnce(&mut windowed_infinity::TeeForCrc<'_, '_, u64>) -> R,
38{
39 block2_write_with_cf(block2, response, f, None)
40}
41
42#[derive(PartialEq)]
43enum Characterization {
44 Underflow,
45 Inside,
46 Overflow,
47}
48
49use Characterization::*;
50
51impl Characterization {
52 fn new(cursor: isize, buffer: &[u8]) -> Self {
53 match usize::try_from(cursor) {
54 Err(_) => Underflow,
55 Ok(i) if i == buffer.len() => Inside,
56 _ => Overflow,
57 }
58 }
59}
60
61pub(crate) fn block2_write_with_cf<F, R>(
65 block2: Block2RequestData,
66 response: &mut impl MutableWritableMessage,
67 f: F,
68 cf: Option<u16>,
69) -> R
70where
71 F: FnOnce(&mut windowed_infinity::TeeForCrc<'_, '_, u64>) -> R,
72{
73 let estimated_option_size = 25; let payload_budget = response.available_space() - estimated_option_size;
75 let block2 = block2
76 .shrink(payload_budget as u16)
77 .expect("Tiny buffer allocated");
78
79 response
80 .add_option(optconvert(option::ETAG), &[0, 0, 0, 0, 0, 0, 0, 0])
81 .unwrap();
82 if let Some(cf) = cf {
83 if let Ok(cfopt) = option::CONTENT_FORMAT.try_into() {
84 response.add_option_uint(cfopt, cf).unwrap();
85 }
86 }
87 response
88 .add_option_uint(optconvert(option::BLOCK2), block2.to_option_value(false))
89 .unwrap();
90
91 let (characterization, written, etag, ret) = {
92 let full_payload = response.payload_mut_with_len(block2.size().into()).unwrap();
93 let writer = WindowedInfinity::new(
94 &mut full_payload[..block2.size() as usize],
95 -(block2.start() as isize),
96 );
97 let etag = crc::Crc::<u64>::new(&crc::CRC_64_ECMA_182);
98 let mut writer = writer.tee_crc64(&etag);
99
100 let ret = f(&mut writer);
101
102 let (writer, etag) = writer.into_windowed_and_crc();
103 let written = writer.written();
104
105 (
106 Characterization::new(writer.cursor(), written),
107 written.len(),
108 etag.finalize().to_le_bytes(),
109 ret,
110 )
111 };
112
113 response.truncate(written).unwrap();
114 if characterization == Underflow {
115 unimplemented!("Report out-of-band seek");
116 }
117
118 response.mutate_options(|optnum, value| {
119 match optnum.into() {
120 option::ETAG => {
121 value.copy_from_slice(&etag);
122 }
123 option::BLOCK2 if characterization == Overflow => {
124 value[value.len() - 1] |= 0x08;
126 }
127 _ => (),
128 };
129 });
130
131 ret
132}
133
134pub struct MaskingUriUpToPath<'m, M: ReadableMessage>(pub &'m M);
142
143impl<M: ReadableMessage> ReadableMessage for MaskingUriUpToPath<'_, M> {
144 type Code = M::Code;
145 type MessageOption<'a>
146 = M::MessageOption<'a>
147 where
148 Self: 'a;
149 type OptionsIter<'a>
150 = MaskingUriUpToPathIter<M::OptionsIter<'a>>
151 where
152 Self: 'a;
153
154 fn options(&self) -> Self::OptionsIter<'_> {
155 MaskingUriUpToPathIter(self.0.options())
156 }
157
158 fn code(&self) -> M::Code {
159 self.0.code()
160 }
161
162 fn payload(&self) -> &[u8] {
163 self.0.payload()
164 }
165}
166
167pub struct MaskingUriUpToPathIter<I>(I);
168
169impl<MO: MessageOption, I: Iterator<Item = MO>> Iterator for MaskingUriUpToPathIter<I> {
170 type Item = MO;
171
172 fn next(&mut self) -> Option<MO> {
173 loop {
174 let result = self.0.next()?;
175 match result.number() {
176 coap_numbers::option::URI_HOST => continue,
177 coap_numbers::option::URI_PATH => continue,
178 _ => return Some(result),
179 }
180 }
181 }
182}
183
184pub(crate) struct MaskingUriUpToPathN<'m, M: ReadableMessage> {
187 message: &'m M,
188 strip_paths: usize,
189}
190
191impl<'m, M: ReadableMessage> MaskingUriUpToPathN<'m, M> {
192 pub(crate) fn new(message: &'m M, strip_paths: usize) -> Self {
193 Self {
194 message,
195 strip_paths,
196 }
197 }
198}
199
200impl<M: ReadableMessage> ReadableMessage for MaskingUriUpToPathN<'_, M> {
201 type Code = M::Code;
202 type MessageOption<'a>
203 = M::MessageOption<'a>
204 where
205 Self: 'a;
206 type OptionsIter<'a>
207 = MaskingUriUpToPathNIter<M::OptionsIter<'a>>
208 where
209 Self: 'a;
210
211 fn options(&self) -> Self::OptionsIter<'_> {
212 MaskingUriUpToPathNIter {
213 inner: self.message.options(),
214 remaining_strip: self.strip_paths,
215 }
216 }
217
218 fn code(&self) -> M::Code {
219 self.message.code()
220 }
221
222 fn payload(&self) -> &[u8] {
223 self.message.payload()
224 }
225}
226
227pub struct MaskingUriUpToPathNIter<I> {
228 inner: I,
229 remaining_strip: usize,
230}
231
232impl<MO: MessageOption, I: Iterator<Item = MO>> Iterator for MaskingUriUpToPathNIter<I> {
233 type Item = MO;
234
235 fn next(&mut self) -> Option<MO> {
236 loop {
237 let result = self.inner.next()?;
238 match result.number() {
239 coap_numbers::option::URI_HOST => continue,
240 coap_numbers::option::URI_PATH if self.remaining_strip > 0 => {
241 self.remaining_strip -= 1;
242 continue;
243 }
244 _ => return Some(result),
245 }
246 }
247 }
248}