1#![cfg_attr(not(feature = "std"), no_std)]
2mod tee;
43mod wrappers;
44
45pub type TeeForDigest<'a, D> = tee::Tee<WindowedInfinity<'a>, wrappers::WritableDigest<D>>;
50pub type TeeForCrc<'a, 'c, W> = tee::Tee<WindowedInfinity<'a>, wrappers::WritableCrc<'c, W>>;
55
56trait MyWrite {
62 type Error;
63 fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error>;
64 #[allow(dead_code)]
66 fn flush(&mut self) -> Result<(), Self::Error>;
67}
68
69pub struct WindowedInfinity<'a> {
72 view: &'a mut [u8],
73 cursor: isize,
74}
75
76impl<'a> WindowedInfinity<'a> {
77 pub fn new(view: &'a mut [u8], cursor: isize) -> Self {
81 WindowedInfinity { view, cursor }
82 }
83
84 pub fn cursor(&self) -> isize {
90 self.cursor
91 }
92
93 #[deprecated(note = "Renamed to .cursor()")]
94 pub fn get_cursor(&self) -> isize {
95 self.cursor()
96 }
97
98 pub fn write(&mut self, data: &[u8]) {
102 let start = self.cursor;
103 self.cursor += data.len() as isize;
105 let end = self.cursor;
106
107 if end <= 0 {
108 return;
110 }
111
112 if start >= self.view.len() as isize {
113 return;
115 }
116
117 #[rustfmt::skip]
118 let (fronttrim, start) = if start < 0 {
119 (-start, 0)
120 } else {
121 (0, start)
122 };
123 let data = &data[fronttrim as usize..];
124
125 let overshoot = start + data.len() as isize - self.view.len() as isize;
126 let (tailtrim, end) = if overshoot > 0 {
127 (overshoot, end - overshoot)
128 } else {
129 (0, end)
130 };
131 let data = &data[..data.len() - tailtrim as usize];
132 self.view[start as usize..end as usize].copy_from_slice(data);
133 }
134
135 pub fn written(&self) -> &[u8] {
140 if self.cursor > 0 {
141 self.view.chunks(self.cursor as usize).next().unwrap_or(&[])
143 } else {
144 &[]
145 }
146 }
147
148 #[deprecated(note = "Renamed to .written()")]
149 pub fn get_written(&self) -> &[u8] {
150 self.written()
151 }
152
153 pub fn tee_digest<D: digest::Digest>(self) -> TeeForDigest<'a, D> {
160 tee::Tee {
161 w1: self,
162 w2: wrappers::WritableDigest(D::new()),
163 }
164 }
165
166 pub fn tee_crc64<'c>(self, crc: &'c crc::Crc<u64>) -> TeeForCrc<'a, 'c, u64> {
172 tee::Tee {
173 w1: self,
174 w2: wrappers::WritableCrc(crc.digest()),
175 }
176 }
177
178 pub fn tee_crc32<'c>(self, crc: &'c crc::Crc<u32>) -> TeeForCrc<'a, 'c, u32> {
184 tee::Tee {
185 w1: self,
186 w2: wrappers::WritableCrc(crc.digest()),
187 }
188 }
189}
190
191impl MyWrite for WindowedInfinity<'_> {
192 type Error = core::convert::Infallible;
193
194 fn write(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
195 self.write(buf);
196 Ok(())
197 }
198
199 fn flush(&mut self) -> Result<(), Self::Error> {
200 Ok(())
201 }
202}
203
204#[cfg(feature = "std")]
205impl std::io::Write for WindowedInfinity<'_> {
206 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
207 self.write(buf);
208 Ok(buf.len())
211 }
212
213 fn flush(&mut self) -> std::io::Result<()> {
214 Ok(())
215 }
216}
217
218impl core::fmt::Write for WindowedInfinity<'_> {
219 fn write_str(&mut self, s: &str) -> core::fmt::Result {
220 self.write(s.as_bytes());
221 Ok(())
222 }
223}
224
225#[cfg(feature = "serde_cbor")]
226impl serde_cbor::ser::Write for WindowedInfinity<'_> {
227 type Error = serde_cbor::error::Error;
229
230 fn write_all(&mut self, buf: &[u8]) -> Result<(), serde_cbor::error::Error> {
231 self.write(buf);
232 Ok(())
233 }
234}
235
236#[allow(unused_macros)] macro_rules! impl_minicbor_write_for_windowedinfinity {
238 ($c:ident) => {
239 impl<'a> $c::encode::Write for WindowedInfinity<'a> {
240 type Error = core::convert::Infallible;
241
242 fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
243 self.write(buf);
244 Ok(())
245 }
246 }
247 };
248}
249
250#[cfg(feature = "with_minicbor")]
251impl_minicbor_write_for_windowedinfinity!(minicbor);
252#[cfg(feature = "with_minicbor_0_19")]
253impl_minicbor_write_for_windowedinfinity!(minicbor_0_19);
254#[cfg(feature = "with_minicbor_0_24")]
255impl_minicbor_write_for_windowedinfinity!(minicbor_0_24);
256#[cfg(feature = "with_minicbor_0_25")]
257impl_minicbor_write_for_windowedinfinity!(minicbor_0_25);
258#[cfg(feature = "with_minicbor_0_26")]
259impl_minicbor_write_for_windowedinfinity!(minicbor_0_26);
260
261#[cfg(feature = "with_ciborium")]
262impl ciborium_io::Write for WindowedInfinity<'_> {
263 type Error = core::convert::Infallible;
264
265 fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
266 self.write(buf);
267 Ok(())
268 }
269
270 fn flush(&mut self) -> Result<(), Self::Error> {
271 Ok(())
272 }
273}
274
275#[cfg(feature = "with_embedded_io_0_4")]
276impl embedded_io::Io for WindowedInfinity<'_> {
277 type Error = core::convert::Infallible;
278}
279
280#[cfg(feature = "with_embedded_io_0_4")]
281impl embedded_io::blocking::Write for WindowedInfinity<'_> {
282 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
283 self.write(buf);
284
285 Ok(buf.len())
286 }
287
288 fn flush(&mut self) -> Result<(), Self::Error> {
289 Ok(())
290 }
291}
292
293#[cfg(feature = "embedded_io_0_6")]
295impl embedded_io_0_6::ErrorType for WindowedInfinity<'_> {
296 type Error = core::convert::Infallible;
297}
298
299#[cfg(feature = "with_embedded_io_0_6")]
300impl embedded_io_0_6::Write for WindowedInfinity<'_> {
301 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
302 self.write(buf);
303
304 Ok(buf.len())
305 }
306
307 fn flush(&mut self) -> Result<(), Self::Error> {
308 Ok(())
309 }
310}
311
312#[cfg(feature = "with_embedded_io_async_0_6")]
313impl embedded_io_async_0_6::Write for WindowedInfinity<'_> {
314 async fn write(&mut self, buf: &[u8]) -> Result<usize, core::convert::Infallible> {
315 self.write(buf);
316
317 Ok(buf.len())
318 }
319}
320
321#[cfg(test)]
322mod tests {
323 use super::WindowedInfinity;
324
325 #[test]
326 fn zero_length() {
327 let mut data: [u8; 0] = [];
328 let mut writer = WindowedInfinity::new(&mut data, -10);
329 writer.write(&[42; 20]);
330 assert_eq!(writer.cursor(), 10);
331 assert_eq!(writer.written(), &[]);
332 }
333
334 #[test]
335 fn single_write() {
336 let mut data: [u8; 5] = [0; 5];
337 let mut writer = WindowedInfinity::new(&mut data, -10);
338 writer.write(&[42; 20]);
339 assert_eq!(writer.cursor(), 10);
340 assert_eq!(writer.written(), &[42; 5]);
341 assert_eq!(data, [42; 5]);
342 }
343
344 #[test]
345 fn small_chunks() {
346 let mut data: [u8; 5] = [0; 5];
347 let mut writer = WindowedInfinity::new(&mut data, -10);
348 for i in 0..10 {
349 writer.write(&[i as u8; 2]);
350 assert_eq!(writer.cursor(), -10 + (i + 1) * 2);
351 if i == 5 {
352 assert_eq!(writer.written(), &[5; 2]);
353 }
354 }
355 assert_eq!(writer.written(), [5, 5, 6, 6, 7]);
356 assert_eq!(data, [5, 5, 6, 6, 7]);
357 }
358
359 #[cfg(feature = "std")]
360 #[test]
361 fn single_write_std() {
362 let mut data: [u8; 5] = [0; 5];
363 let mut writer = WindowedInfinity::new(&mut data, -10);
364 std::io::Write::write(&mut writer, &[42; 20]).unwrap();
365 assert_eq!(writer.cursor(), 10);
366 }
367
368 #[cfg(feature = "with_serde_cbor")]
369 #[test]
370 fn single_write_cbor() {
371 use serde::ser::Serialize;
372
373 let mut data: [u8; 5] = [0; 5];
374 let mut writer = WindowedInfinity::new(&mut data, -10);
375 let cbordata = ["Hello World"];
376 cbordata
377 .serialize(&mut serde_cbor::ser::Serializer::new(&mut writer))
378 .unwrap();
379 assert_eq!(writer.cursor(), 3);
380 }
381
382 #[allow(unused_macros)] macro_rules! single_write_minicbor {
384 ($f:ident, $c:ident) => {
385 #[test]
386 fn $f() {
387 let mut data: [u8; 5] = [0; 5];
388 let mut writer = WindowedInfinity::new(&mut data, -10);
389 $c::encode(["Hello World"], &mut writer).unwrap();
390 assert_eq!(writer.cursor(), 3);
391 }
392 };
393 }
394
395 #[cfg(feature = "with_minicbor")]
396 single_write_minicbor!(single_write_minicbor, minicbor);
397 #[cfg(feature = "with_minicbor_0_19")]
398 single_write_minicbor!(single_write_minicbor_0_19, minicbor_0_19);
399 #[cfg(feature = "with_minicbor_0_24")]
400 single_write_minicbor!(single_write_minicbor_0_24, minicbor_0_24);
401 #[cfg(feature = "with_minicbor_0_25")]
402 single_write_minicbor!(single_write_minicbor_0_25, minicbor_0_25);
403 #[cfg(feature = "with_minicbor_0_26")]
404 single_write_minicbor!(single_write_minicbor_0_26, minicbor_0_26);
405
406 #[cfg(feature = "with_ciborium")]
407 #[test]
408 fn single_write_cborium() {
409 use ciborium_ll;
410
411 let mut data: [u8; 5] = [0; 5];
412 let mut writer = WindowedInfinity::new(&mut data, -10);
413 let mut encoder = ciborium_ll::Encoder::from(&mut writer);
414 encoder.push(ciborium_ll::Header::Array(Some(1))).unwrap();
415 encoder.text("Hello World", None).unwrap();
416 assert_eq!(writer.cursor(), 3);
417 }
418
419 #[cfg(feature = "with_embedded_io_0_4")]
420 #[test]
421 fn write_embedded_io_blocking() {
422 use embedded_io::blocking::Write;
423
424 let mut data: [u8; 5] = [0; 5];
425 let mut writer = WindowedInfinity::new(&mut data, -10);
426 writer.write_all(b"Hello ").unwrap();
427 writer.flush().unwrap();
428
429 writer.write_fmt(format_args!("Worl{}", "d")).unwrap();
430 assert_eq!(writer.cursor(), 1);
433 }
434
435 #[cfg(feature = "with_embedded_io_0_6")]
436 #[test]
437 fn write_embedded_io_0_6() {
438 use embedded_io_0_6::Write;
439
440 let mut data: [u8; 5] = [0; 5];
441 let mut writer = WindowedInfinity::new(&mut data, -10);
442 writer.write_all(b"Hello ").unwrap();
443 writer.flush().unwrap();
444
445 writer.write_fmt(format_args!("Worl{}", "d")).unwrap();
446 assert_eq!(writer.cursor(), 1);
449 }
450
451 #[cfg(feature = "with_embedded_io_async_0_6")]
452 #[tokio::test]
453 async fn write_embedded_io_async_0_6() {
454 use embedded_io_async_0_6::Write;
455
456 let mut data: [u8; 5] = [0; 5];
457 let mut writer = WindowedInfinity::new(&mut data, -10);
458 writer.write_all(b"Hello World").await.unwrap();
459 writer.flush().await.unwrap();
460
461 assert_eq!(writer.cursor(), 1);
464 }
465}