Skip to main content

embedded_svc/utils/
io.rs

1use embedded_io::Error;
2
3use crate::io::{Read, Write};
4
5pub fn try_read_full<R: Read>(mut read: R, buf: &mut [u8]) -> Result<usize, (R::Error, usize)> {
6    let mut offset = 0;
7    let mut size = 0;
8
9    loop {
10        let size_read = read.read(&mut buf[offset..]).map_err(|e| (e, size))?;
11
12        offset += size_read;
13        size += size_read;
14
15        if size_read == 0 || size == buf.len() {
16            break;
17        }
18    }
19
20    Ok(size)
21}
22
23#[derive(Debug)]
24#[cfg_attr(feature = "defmt", derive(defmt::Format))]
25pub enum CopyError<R, W> {
26    Read(R),
27    Write(W),
28}
29
30impl<R: core::fmt::Debug, W: core::fmt::Debug> core::fmt::Display for CopyError<R, W> {
31    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
32        write!(f, "{self:?}")
33    }
34}
35
36impl<R: core::fmt::Debug, W: core::fmt::Debug> core::error::Error for CopyError<R, W> {}
37
38impl<R, W> Error for CopyError<R, W>
39where
40    R: Error,
41    W: Error,
42{
43    fn kind(&self) -> embedded_io::ErrorKind {
44        match self {
45            Self::Read(e) => e.kind(),
46            Self::Write(e) => e.kind(),
47        }
48    }
49}
50
51pub fn copy<R, W>(read: R, write: W, buf: &mut [u8]) -> Result<u64, CopyError<R::Error, W::Error>>
52where
53    R: Read,
54    W: Write,
55{
56    copy_len(read, write, buf, u64::MAX)
57}
58
59pub fn copy_len<R, W>(
60    read: R,
61    write: W,
62    buf: &mut [u8],
63    len: u64,
64) -> Result<u64, CopyError<R::Error, W::Error>>
65where
66    R: Read,
67    W: Write,
68{
69    copy_len_with_progress(read, write, buf, len, |_, _| {})
70}
71
72pub fn copy_len_with_progress<R, W, P>(
73    mut read: R,
74    mut write: W,
75    buf: &mut [u8],
76    mut len: u64,
77    progress: P,
78) -> Result<u64, CopyError<R::Error, W::Error>>
79where
80    R: Read,
81    W: Write,
82    P: Fn(u64, u64),
83{
84    let mut copied = 0;
85
86    while len > 0 {
87        progress(copied, len);
88
89        let size_read = read.read(buf).map_err(CopyError::Read)?;
90        if size_read == 0 {
91            break;
92        }
93
94        write
95            .write_all(&buf[0..size_read])
96            .map_err(CopyError::Write)?;
97
98        copied += size_read as u64;
99        len -= size_read as u64;
100    }
101
102    progress(copied, len);
103
104    Ok(copied)
105}
106
107pub mod asynch {
108    use crate::io::asynch::{Read, Write};
109
110    pub use super::CopyError;
111
112    pub async fn try_read_full<R: Read>(
113        mut read: R,
114        buf: &mut [u8],
115    ) -> Result<usize, (R::Error, usize)> {
116        let mut offset = 0;
117        let mut size = 0;
118
119        loop {
120            let size_read = read.read(&mut buf[offset..]).await.map_err(|e| (e, size))?;
121
122            offset += size_read;
123            size += size_read;
124
125            if size_read == 0 || size == buf.len() {
126                break;
127            }
128        }
129
130        Ok(size)
131    }
132
133    pub async fn copy<R, W>(
134        read: R,
135        write: W,
136        buf: &mut [u8],
137    ) -> Result<u64, CopyError<R::Error, W::Error>>
138    where
139        R: Read,
140        W: Write,
141    {
142        copy_len(read, write, buf, u64::MAX).await
143    }
144
145    pub async fn copy_len<R, W>(
146        read: R,
147        write: W,
148        buf: &mut [u8],
149        len: u64,
150    ) -> Result<u64, CopyError<R::Error, W::Error>>
151    where
152        R: Read,
153        W: Write,
154    {
155        copy_len_with_progress(read, write, buf, len, |_, _| {}).await
156    }
157
158    pub async fn copy_len_with_progress<R, W, P>(
159        mut read: R,
160        mut write: W,
161        buf: &mut [u8],
162        mut len: u64,
163        progress: P,
164    ) -> Result<u64, CopyError<R::Error, W::Error>>
165    where
166        R: Read,
167        W: Write,
168        P: Fn(u64, u64),
169    {
170        let mut copied = 0;
171
172        while len > 0 {
173            progress(copied, len);
174
175            let size_read = read.read(buf).await.map_err(CopyError::Read)?;
176            if size_read == 0 {
177                break;
178            }
179
180            write
181                .write_all(&buf[0..size_read])
182                .await
183                .map_err(CopyError::Write)?;
184
185            copied += size_read as u64;
186            len -= size_read as u64;
187        }
188
189        progress(copied, len);
190
191        Ok(copied)
192    }
193}