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}