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#[cfg(feature = "with_minicbor_1")]
261impl_minicbor_write_for_windowedinfinity!(minicbor_1);
262
263#[cfg(feature = "with_ciborium")]
264impl ciborium_io::Write for WindowedInfinity<'_> {
265 type Error = core::convert::Infallible;
266
267 fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
268 self.write(buf);
269 Ok(())
270 }
271
272 fn flush(&mut self) -> Result<(), Self::Error> {
273 Ok(())
274 }
275}
276
277#[cfg(feature = "with_embedded_io_0_4")]
278impl embedded_io::Io for WindowedInfinity<'_> {
279 type Error = core::convert::Infallible;
280}
281
282#[cfg(feature = "with_embedded_io_0_4")]
283impl embedded_io::blocking::Write for WindowedInfinity<'_> {
284 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
285 self.write(buf);
286
287 Ok(buf.len())
288 }
289
290 fn flush(&mut self) -> Result<(), Self::Error> {
291 Ok(())
292 }
293}
294
295#[cfg(feature = "embedded_io_0_6")]
297impl embedded_io_0_6::ErrorType for WindowedInfinity<'_> {
298 type Error = core::convert::Infallible;
299}
300
301#[cfg(feature = "with_embedded_io_0_6")]
302impl embedded_io_0_6::Write for WindowedInfinity<'_> {
303 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
304 self.write(buf);
305
306 Ok(buf.len())
307 }
308
309 fn flush(&mut self) -> Result<(), Self::Error> {
310 Ok(())
311 }
312}
313
314#[cfg(feature = "with_embedded_io_async_0_6")]
315impl embedded_io_async_0_6::Write for WindowedInfinity<'_> {
316 async fn write(&mut self, buf: &[u8]) -> Result<usize, core::convert::Infallible> {
317 self.write(buf);
318
319 Ok(buf.len())
320 }
321}
322
323#[cfg(test)]
324mod tests {
325 use super::WindowedInfinity;
326
327 #[test]
328 fn zero_length() {
329 let mut data: [u8; 0] = [];
330 let mut writer = WindowedInfinity::new(&mut data, -10);
331 writer.write(&[42; 20]);
332 assert_eq!(writer.cursor(), 10);
333 assert_eq!(writer.written(), &[]);
334 }
335
336 #[test]
337 fn single_write() {
338 let mut data: [u8; 5] = [0; 5];
339 let mut writer = WindowedInfinity::new(&mut data, -10);
340 writer.write(&[42; 20]);
341 assert_eq!(writer.cursor(), 10);
342 assert_eq!(writer.written(), &[42; 5]);
343 assert_eq!(data, [42; 5]);
344 }
345
346 #[test]
347 fn small_chunks() {
348 let mut data: [u8; 5] = [0; 5];
349 let mut writer = WindowedInfinity::new(&mut data, -10);
350 for i in 0..10 {
351 writer.write(&[i as u8; 2]);
352 assert_eq!(writer.cursor(), -10 + (i + 1) * 2);
353 if i == 5 {
354 assert_eq!(writer.written(), &[5; 2]);
355 }
356 }
357 assert_eq!(writer.written(), [5, 5, 6, 6, 7]);
358 assert_eq!(data, [5, 5, 6, 6, 7]);
359 }
360
361 #[cfg(feature = "std")]
362 #[test]
363 fn single_write_std() {
364 let mut data: [u8; 5] = [0; 5];
365 let mut writer = WindowedInfinity::new(&mut data, -10);
366 std::io::Write::write(&mut writer, &[42; 20]).unwrap();
367 assert_eq!(writer.cursor(), 10);
368 }
369
370 #[cfg(feature = "with_serde_cbor")]
371 #[test]
372 fn single_write_cbor() {
373 use serde::ser::Serialize;
374
375 let mut data: [u8; 5] = [0; 5];
376 let mut writer = WindowedInfinity::new(&mut data, -10);
377 let cbordata = ["Hello World"];
378 cbordata
379 .serialize(&mut serde_cbor::ser::Serializer::new(&mut writer))
380 .unwrap();
381 assert_eq!(writer.cursor(), 3);
382 }
383
384 #[allow(unused_macros)] macro_rules! single_write_minicbor {
386 ($f:ident, $c:ident) => {
387 #[test]
388 fn $f() {
389 let mut data: [u8; 5] = [0; 5];
390 let mut writer = WindowedInfinity::new(&mut data, -10);
391 $c::encode(["Hello World"], &mut writer).unwrap();
392 assert_eq!(writer.cursor(), 3);
393 }
394 };
395 }
396
397 #[cfg(feature = "with_minicbor")]
398 single_write_minicbor!(single_write_minicbor, minicbor);
399 #[cfg(feature = "with_minicbor_0_19")]
400 single_write_minicbor!(single_write_minicbor_0_19, minicbor_0_19);
401 #[cfg(feature = "with_minicbor_0_24")]
402 single_write_minicbor!(single_write_minicbor_0_24, minicbor_0_24);
403 #[cfg(feature = "with_minicbor_0_25")]
404 single_write_minicbor!(single_write_minicbor_0_25, minicbor_0_25);
405 #[cfg(feature = "with_minicbor_0_26")]
406 single_write_minicbor!(single_write_minicbor_0_26, minicbor_0_26);
407 #[cfg(feature = "with_minicbor_1")]
408 single_write_minicbor!(single_write_minicbor_1, minicbor_1);
409
410 #[cfg(feature = "with_ciborium")]
411 #[test]
412 fn single_write_cborium() {
413 use ciborium_ll;
414
415 let mut data: [u8; 5] = [0; 5];
416 let mut writer = WindowedInfinity::new(&mut data, -10);
417 let mut encoder = ciborium_ll::Encoder::from(&mut writer);
418 encoder.push(ciborium_ll::Header::Array(Some(1))).unwrap();
419 encoder.text("Hello World", None).unwrap();
420 assert_eq!(writer.cursor(), 3);
421 }
422
423 #[cfg(feature = "with_embedded_io_0_4")]
424 #[test]
425 fn write_embedded_io_blocking() {
426 use embedded_io::blocking::Write;
427
428 let mut data: [u8; 5] = [0; 5];
429 let mut writer = WindowedInfinity::new(&mut data, -10);
430 writer.write_all(b"Hello ").unwrap();
431 writer.flush().unwrap();
432
433 writer.write_fmt(format_args!("Worl{}", "d")).unwrap();
434 assert_eq!(writer.cursor(), 1);
437 }
438
439 #[cfg(feature = "with_embedded_io_0_6")]
440 #[test]
441 fn write_embedded_io_0_6() {
442 use embedded_io_0_6::Write;
443
444 let mut data: [u8; 5] = [0; 5];
445 let mut writer = WindowedInfinity::new(&mut data, -10);
446 writer.write_all(b"Hello ").unwrap();
447 writer.flush().unwrap();
448
449 writer.write_fmt(format_args!("Worl{}", "d")).unwrap();
450 assert_eq!(writer.cursor(), 1);
453 }
454
455 #[cfg(feature = "with_embedded_io_async_0_6")]
456 #[tokio::test]
457 async fn write_embedded_io_async_0_6() {
458 use embedded_io_async_0_6::Write;
459
460 let mut data: [u8; 5] = [0; 5];
461 let mut writer = WindowedInfinity::new(&mut data, -10);
462 writer.write_all(b"Hello World").await.unwrap();
463 writer.flush().await.unwrap();
464
465 assert_eq!(writer.cursor(), 1);
468 }
469}