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*/