extra_embedded_io_adapters/
lib.rs

1//! Types that encapsulate foreign types into embedded-io writers.
2//!
3//! Exceeding what the [embedded-io-adapters](https://crates.io/crates/embedded-io-adapters) (which
4//! gets co-developed with [`embedded-io`]) does,
5//!
6//! * it goes both ways: It implements [`embedded_io::Write`] for foreign types ([`WritableCrc`]
7//!   etc.), but also foreign traits for any implementation of [`embedded_io::Write`]
8//!   ([`ForeignWritable`]).
9//! * it is not too picky in what it implements:
10//!   * it interfaces with crates that are not stable (e.g. [`digest::Digest`])
11//!   * it interfaces with crates that are more bespoke but which would still not implement
12//!     `embedded-io` traits (e.g. [`ciborium_io::Write`])
13//!
14//! This library is not intended to be part of any other crate's public dependencies, and will do
15//! breaking releases whenever its own public dependencies change. Users who want to support
16//! different versions of other crates may need to resort to using multiple versions of this crate.
17#![no_std]
18
19#[cfg(test)]
20mod tests;
21
22use embedded_io::{ErrorType, Write};
23
24/// Wrapper around any [`embedded_io::Write`] that implements additional Write-ish traits.
25///
26/// This implements various CBOR encoders' custom write traits (currently only [`ciborium_io::Write`]).
27pub struct ForeignWritable<T: Write>(pub T);
28
29#[cfg(feature = "ciborium_0_2")]
30impl<T: Write> ciborium_io::Write for ForeignWritable<T> {
31    type Error = T::Error;
32
33    fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
34        Write::write_all(&mut self.0, buf)
35    }
36
37    fn flush(&mut self) -> Result<(), Self::Error> {
38        Ok(())
39    }
40}
41
42/// Wrapper around any [`digest::Digest`] (typically hashes) that implements [`embedded_io::Write`]
43/// to send data into a digest.
44pub struct WritableDigest<D: digest::Digest>(pub D);
45
46impl<D: digest::Digest> ErrorType for WritableDigest<D> {
47    type Error = core::convert::Infallible;
48}
49
50impl<D: digest::Digest> Write for WritableDigest<D> {
51    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
52        self.0.update(buf);
53        Ok(buf.len())
54    }
55
56    fn flush(&mut self) -> Result<(), Self::Error> {
57        Ok(())
58    }
59}
60
61/// Wrapper around any [`crc::Digest`] (typically hashes) that implements [`embedded_io::Write`]
62/// to send data into a digest.
63pub struct WritableCrc<'c, W: crc::Width>(pub crc::Digest<'c, W>);
64
65impl<W: crc::Width> ErrorType for WritableCrc<'_, W> {
66    type Error = core::convert::Infallible;
67}
68
69impl Write for WritableCrc<'_, u64> {
70    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
71        self.0.update(buf);
72        Ok(buf.len())
73    }
74
75    fn flush(&mut self) -> Result<(), Self::Error> {
76        Ok(())
77    }
78}
79
80impl Write for WritableCrc<'_, u32> {
81    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
82        self.0.update(buf);
83        Ok(buf.len())
84    }
85
86    fn flush(&mut self) -> Result<(), Self::Error> {
87        Ok(())
88    }
89}
90
91//
92// FIXME: These were convenient constructors on the WindowedInfinity; should we have them as an
93// extension trait on every embedded_ioWrite?
94//
95
96/*
97    /// Create a Tee (a T-shaped writer) that writes both to this WindowedInfinity and some
98    /// [digest::Digest].
99    ///
100    /// The resulting type implements all the same writers as the WindowedInfinity, and offers an
101    /// `into_windowed_and_digest(self) -> (WindowedInfinity, Digest)` to get both back after
102    /// writing as completed.
103    pub fn tee_digest<D: digest::Digest>(self) -> TeeForDigest<'a, D> {
104        tee::Tee {
105            w1: self,
106            w2: wrappers::WritableDigest(D::new()),
107        }
108    }
109
110    /// Create a Tee (a T-shaped writer) that writes both to this WindowedInfinity and some
111    /// [crc::Digest].
112    ///
113    /// This is limited to u64 CRCs due to <https://github.com/mrhooray/crc-rs/issues/79>, and
114    /// indirectly the availability of const traits.
115    pub fn tee_crc64<'c>(self, crc: &'c crc::Crc<u64>) -> TeeForCrc<'a, 'c, u64> {
116        tee::Tee {
117            w1: self,
118            w2: wrappers::WritableCrc(crc.digest()),
119        }
120    }
121
122    /// Create a Tee (a T-shaped writer) that writes both to this WindowedInfinity and some
123    /// [crc::Digest].
124    ///
125    /// This is limited to u32 CRCs due to <https://github.com/mrhooray/crc-rs/issues/79>, and
126    /// indirectly the availability of const traits.
127    pub fn tee_crc32<'c>(self, crc: &'c crc::Crc<u32>) -> TeeForCrc<'a, 'c, u32> {
128        tee::Tee {
129            w1: self,
130            w2: wrappers::WritableCrc(crc.digest()),
131        }
132    }
133
134impl<'a, 'c> crate::tee::Tee<crate::WindowedInfinity<'a>, WritableCrc<'c, u64>> {
135    pub fn into_windowed_and_crc(self) -> (crate::WindowedInfinity<'a>, crc::Digest<'c, u64>) {
136        (self.w1, self.w2.0)
137    }
138}
139
140impl<'a, 'c> crate::tee::Tee<crate::WindowedInfinity<'a>, WritableCrc<'c, u32>> {
141    pub fn into_windowed_and_crc(self) -> (crate::WindowedInfinity<'a>, crc::Digest<'c, u32>) {
142        (self.w1, self.w2.0)
143    }
144}
145*/