tee_embedded_io/
lib.rs

1//! Adapter for embedded-io to feed writes into two instances
2//!
3//! It provides a "T" shaped dispatcher for writes (performed on both sides with the
4//! [`embedded_io::Write`] trait), similar to the UNIX
5//! [`tee`](https://manpages.debian.org/bookworm/coreutils/tee.1.en.html) command.
6#![no_std]
7
8use core::marker::PhantomData;
9use embedded_io::{Error, ErrorType, Write};
10
11/// A "T" shaped dispatcher for blocking writes. This contains two writers, both of which writes to
12/// the Tee are sent to.
13///
14/// On errors, the writers may have received different amounts of data. Errors are propagated from
15/// either writer. Both writers' error types need to be convertible into a common error.
16pub struct Tee<W1: ErrorType, W2, E>
17// These are preconditions for every actual implemnetation, but we're not listing them as a matter
18// of best practice (keeping the requirements minimal)
19//     W1: Write,
20//     W2: Write,
21//     E: Error + From<W1::Error> + From<W2::Error>
22{
23    w1: W1,
24    w2: W2,
25    _phantom: PhantomData<E>,
26}
27
28impl<W1, W2> Tee<W1, W2, W1::Error>
29where
30    // More to make trouble visible early; otherwise, the trait bounds would only cause errors on
31    // use.
32    W1: Write,
33    W2: Write,
34    W1::Error: From<W2::Error>,
35{
36    /// Constructs a [`Tee`] from the two writers it will sends the its written data to.
37    ///
38    /// This constructor uses `W1`'s error type as the common error.
39    pub fn new(w1: W1, w2: W2) -> Self {
40        Self::new_with_error_type(w1, w2)
41    }
42}
43
44impl<W1, W2, E> Tee<W1, W2, E>
45where
46    // More to make trouble visible early; otherwise, the trait bounds would only cause errors on
47    // use.
48    W1: Write,
49    W2: Write,
50    E: Error + From<W1::Error> + From<W2::Error>,
51{
52    /// Constructs a [`Tee`] from the two writers it will sends the its written data to.
53    ///
54    /// This constructor uses an error type that needs to be indicated explicitly on the output
55    /// type.
56    pub fn new_with_error_type(w1: W1, w2: W2) -> Self {
57        Self {
58            w1,
59            w2,
60            _phantom: PhantomData,
61        }
62    }
63}
64
65impl<W1: ErrorType, W2, E> Tee<W1, W2, E> {
66    pub fn into_parts(self) -> (W1, W2) {
67        (self.w1, self.w2)
68    }
69}
70
71impl<W1, W2, E> ErrorType for Tee<W1, W2, E>
72where
73    W1: ErrorType,
74    E: Error,
75{
76    type Error = E;
77}
78
79impl<W1, W2, E> Write for Tee<W1, W2, E>
80where
81    W1: Write,
82    W2: Write,
83    E: Error + From<W1::Error> + From<W2::Error>,
84{
85    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
86        self.w2.write_all(buf)?;
87        self.w1.write_all(buf)?;
88        Ok(buf.len())
89    }
90
91    fn flush(&mut self) -> Result<(), Self::Error> {
92        self.w2.flush()?;
93        self.w1.flush()?;
94        Ok(())
95    }
96}