//! Code in this module is largely generic enough to be developed into a general-purpose Tee for
//! embedded-io.
//!
//! Going there will take two steps:
//! * Replace the internal write with embedded-io's. This is currently not done as to avoid
//! implementing the current 0.4 version's embedded-io trait (which would be a public property).
//! * Implement a constructor and an into_inner() -> (W1, W2). These are currently not done because
//! also here, this would bring a version compatiblity issue.
//!
//! Instead, there are custom constructors and destructors for very specific supported cases.
//!
//! Once there is a stable embedded-io to use, the Tee can migrate (possibly into a dedicated
//! crate). The old constructors will then provide shims (which may deref into the Tee) that
//! provide the old (now deprecated) finalizers.
use super::MyWrite;
/// A "T" shaped dispatcher for blocking writes. This contains two writers, one of which is
/// infallible to simplify error handling, both of which writes to the Tee are sent to.
pub struct Tee<W1, W2>
// These are preconditions for every actual implemnetation, but we're not listing them as the
// MyWrite trait is private.
// where
// W1: MyWrite,
// W2: MyWrite<Error = core::convert::Infallible>,
{
pub(crate) w1: W1,
pub(crate) w2: W2,
}
impl<W1, W2> MyWrite for Tee<W1, W2>
where
W1: MyWrite,
W2: MyWrite<Error = core::convert::Infallible>,
{
type Error = W1::Error;
fn write(&mut self, buf: &[u8]) -> Result<(), <W1 as MyWrite>::Error> {
// unwrap: The W2 error type is uninhabited, but `let Ok(()) = ...;` doesn't work yet
self.w2.write(buf).unwrap();
self.w1.write(buf)
}
fn flush(&mut self) -> Result<(), Self::Error> {
// unwrap: The W2 error type is uninhabited, but `let Ok(()) = ...;` doesn't work yet
self.w2.flush().unwrap();
self.w1.flush()
}
}
#[cfg(feature = "std")]
impl<W1, W2> std::io::Write for Tee<W1, W2>
where
// It might be possible to relax this into W1 errors that are Into<std::io::Error>
W1: MyWrite<Error = core::convert::Infallible>,
W2: MyWrite<Error = core::convert::Infallible>,
{
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
// unwrap: W1::Error is infallbile
MyWrite::write(self, buf).unwrap();
Ok(buf.len())
}
fn flush(&mut self) -> std::io::Result<()> {
self.w2.flush().unwrap();
self.w1.flush().unwrap();
Ok(())
}
}
impl<W1, W2> core::fmt::Write for Tee<W1, W2>
where
// It might be possible to relax this into W1 errors that are Into<core::fmt::Error>
W1: MyWrite<Error = core::convert::Infallible>,
W2: MyWrite<Error = core::convert::Infallible>,
{
fn write_str(&mut self, s: &str) -> core::fmt::Result {
// unwrap: W1::Error is infallbile
self.write(s.as_bytes()).unwrap();
Ok(())
}
}
#[cfg(feature = "serde_cbor")]
impl<W1, W2> serde_cbor::ser::Write for Tee<W1, W2>
where
W1: MyWrite<Error = core::convert::Infallible>,
W2: MyWrite<Error = core::convert::Infallible>,
{
// To be changed to ! once that's stable and implements Into-all
type Error = serde_cbor::error::Error;
fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
// unwrap: W1::Error is infallbile
self.write(buf).unwrap();
Ok(())
}
}
#[cfg(feature = "with_minicbor")]
impl<W1, W2> minicbor::encode::Write for Tee<W1, W2>
where
// Could be any, once MyWrite is replaced with embedded-io (then, Error will become W1::Error).
W1: MyWrite<Error = core::convert::Infallible>,
W2: MyWrite<Error = core::convert::Infallible>,
{
type Error = core::convert::Infallible;
fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
self.write(buf)
}
}
#[cfg(feature = "with_minicbor_0_19")]
impl<W1, W2> minicbor_0_19::encode::Write for Tee<W1, W2>
where
// Could be any, once MyWrite is replaced with embedded-io (then, Error will become W1::Error).
W1: MyWrite<Error = core::convert::Infallible>,
W2: MyWrite<Error = core::convert::Infallible>,
{
type Error = core::convert::Infallible;
fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
self.write(buf)
}
}
#[cfg(feature = "with_minicbor_0_24")]
impl<W1, W2> minicbor_0_24::encode::Write for Tee<W1, W2>
where
// Could be any, once MyWrite is replaced with embedded-io (then, Error will become W1::Error).
W1: MyWrite<Error = core::convert::Infallible>,
W2: MyWrite<Error = core::convert::Infallible>,
{
type Error = core::convert::Infallible;
fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
self.write(buf)
}
}
#[cfg(feature = "with_minicbor_0_25")]
impl<W1, W2> minicbor_0_25::encode::Write for Tee<W1, W2>
where
// Could be any, once MyWrite is replaced with embedded-io (then, Error will become W1::Error).
W1: MyWrite<Error = core::convert::Infallible>,
W2: MyWrite<Error = core::convert::Infallible>,
{
type Error = core::convert::Infallible;
fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
self.write(buf)
}
}
#[cfg(feature = "with_ciborium")]
impl<W1, W2> ciborium_io::Write for Tee<W1, W2>
where
// Could be any, once MyWrite is replaced with embedded-io (then, Error will become W1::Error).
W1: MyWrite<Error = core::convert::Infallible>,
W2: MyWrite<Error = core::convert::Infallible>,
{
type Error = core::convert::Infallible;
fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
self.write(buf)
}
fn flush(&mut self) -> Result<(), Self::Error> {
Ok(())
}
}
#[cfg(feature = "with_embedded_io_0_4")]
impl<W1, W2> embedded_io::Io for Tee<W1, W2>
where
// Could be any, once MyWrite is replaced with embedded-io (then, Error will become W1::Error).
W1: MyWrite<Error = core::convert::Infallible>,
W2: MyWrite<Error = core::convert::Infallible>,
{
type Error = core::convert::Infallible;
}
#[cfg(feature = "with_embedded_io_0_4")]
impl<W1, W2> embedded_io::blocking::Write for Tee<W1, W2>
where
W1: MyWrite<Error = core::convert::Infallible>,
W2: MyWrite<Error = core::convert::Infallible>,
{
fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
MyWrite::write(self, buf).map(|()| buf.len())
}
fn flush(&mut self) -> Result<(), Self::Error> {
MyWrite::flush(self)
}
}