Skip to main content

hadris_io/
sync_api.rs

1//! Synchronous portable I/O traits and interoperability adapters.
2
3use crate::{Error, ErrorKind, Result, SeekFrom};
4
5/// Read bytes from a source.
6pub trait Read {
7    /// Error returned by the underlying source.
8    type Error: embedded_io::Error;
9
10    /// Read some bytes, returning zero at end of input.
11    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error>;
12
13    /// Fill `buf`, retrying interrupted operations.
14    fn read_exact(&mut self, buf: &mut [u8]) -> Result<()> {
15        let mut read = 0;
16        while read < buf.len() {
17            match self.read(&mut buf[read..]) {
18                Ok(0) => return Err(Error::from_kind(ErrorKind::UnexpectedEof)),
19                Ok(n) => read += n,
20                Err(error) if error.kind() == ErrorKind::Interrupted => continue,
21                Err(error) => return Err(error.erase()),
22            }
23        }
24        Ok(())
25    }
26}
27
28/// Write bytes to a destination.
29pub trait Write {
30    /// Error returned by the underlying destination.
31    type Error: embedded_io::Error;
32
33    /// Write some bytes.
34    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error>;
35
36    /// Flush buffered output.
37    fn flush(&mut self) -> Result<(), Self::Error>;
38
39    /// Write all bytes, retrying interrupted operations.
40    fn write_all(&mut self, buf: &[u8]) -> Result<()> {
41        let mut written = 0;
42        while written < buf.len() {
43            match self.write(&buf[written..]) {
44                Ok(0) => return Err(Error::from_kind(ErrorKind::WriteZero)),
45                Ok(n) => written += n,
46                Err(error) if error.kind() == ErrorKind::Interrupted => continue,
47                Err(error) => return Err(error.erase()),
48            }
49        }
50        Ok(())
51    }
52}
53
54/// Move within a stream.
55pub trait Seek {
56    /// Error returned by the underlying stream.
57    type Error: embedded_io::Error;
58
59    /// Seek to a new byte position.
60    fn seek(&mut self, pos: SeekFrom) -> Result<u64, Self::Error>;
61
62    /// Return the current byte position.
63    fn stream_position(&mut self) -> Result<u64, Self::Error> {
64        self.seek(SeekFrom::Current(0))
65    }
66
67    /// Seek relative to the current byte position.
68    fn seek_relative(&mut self, offset: i64) -> Result<(), Self::Error> {
69        self.seek(SeekFrom::Current(offset))?;
70        Ok(())
71    }
72}
73
74/// Reader and seeker that use one common source error.
75pub trait ReadSeek: Read + Seek<Error = <Self as Read>::Error> {}
76impl<T: Read + Seek<Error = <T as Read>::Error> + ?Sized> ReadSeek for T {}
77
78/// Reader and writer that use one common source error.
79pub trait ReadWrite: Read + Write<Error = <Self as Read>::Error> {}
80impl<T: Read + Write<Error = <T as Read>::Error> + ?Sized> ReadWrite for T {}
81
82/// Reader, writer, and seeker that use one common source error.
83pub trait ReadWriteSeek:
84    Read + Write<Error = <Self as Read>::Error> + Seek<Error = <Self as Read>::Error>
85{
86}
87impl<T> ReadWriteSeek for T where
88    T: Read + Write<Error = <T as Read>::Error> + Seek<Error = <T as Read>::Error> + ?Sized
89{
90}
91
92#[cfg(feature = "std")]
93impl<T: std::io::Read + ?Sized> Read for T {
94    type Error = std::io::Error;
95
96    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
97        std::io::Read::read(self, buf).map_err(Error::from_source)
98    }
99}
100
101#[cfg(feature = "std")]
102impl<T: std::io::Write + ?Sized> Write for T {
103    type Error = std::io::Error;
104
105    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
106        std::io::Write::write(self, buf).map_err(Error::from_source)
107    }
108
109    fn flush(&mut self) -> Result<(), Self::Error> {
110        std::io::Write::flush(self).map_err(Error::from_source)
111    }
112}
113
114#[cfg(feature = "std")]
115impl<T: std::io::Seek + ?Sized> Seek for T {
116    type Error = std::io::Error;
117
118    fn seek(&mut self, pos: SeekFrom) -> Result<u64, Self::Error> {
119        std::io::Seek::seek(self, pos.into()).map_err(Error::from_source)
120    }
121}
122
123#[cfg(not(feature = "std"))]
124impl<T: embedded_io::Read + ?Sized> Read for T {
125    type Error = T::Error;
126
127    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
128        embedded_io::Read::read(self, buf).map_err(Error::from_source)
129    }
130}
131
132#[cfg(not(feature = "std"))]
133impl<T: embedded_io::Write + ?Sized> Write for T {
134    type Error = T::Error;
135
136    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
137        embedded_io::Write::write(self, buf).map_err(Error::from_source)
138    }
139
140    fn flush(&mut self) -> Result<(), Self::Error> {
141        embedded_io::Write::flush(self).map_err(Error::from_source)
142    }
143}
144
145#[cfg(not(feature = "std"))]
146impl<T: embedded_io::Seek + ?Sized> Seek for T {
147    type Error = T::Error;
148
149    fn seek(&mut self, pos: SeekFrom) -> Result<u64, Self::Error> {
150        embedded_io::Seek::seek(self, pos).map_err(Error::from_source)
151    }
152}
153
154/// Explicitly expose an `embedded-io` value through Hadris traits.
155#[derive(Debug, Clone, Copy, Default)]
156pub struct FromEmbedded<T>(pub T);
157
158impl<T> FromEmbedded<T> {
159    /// Wrap an embedded I/O value.
160    pub const fn new(inner: T) -> Self {
161        Self(inner)
162    }
163    /// Recover the wrapped value.
164    pub fn into_inner(self) -> T {
165        self.0
166    }
167    /// Borrow the wrapped value.
168    pub const fn get_ref(&self) -> &T {
169        &self.0
170    }
171    /// Mutably borrow the wrapped value.
172    pub fn get_mut(&mut self) -> &mut T {
173        &mut self.0
174    }
175}
176
177/// Reborrow a Hadris I/O value without requiring a blanket implementation for `&mut T`.
178#[derive(Debug)]
179pub struct Borrowed<'a, T: ?Sized>(pub &'a mut T);
180
181impl<'a, T: ?Sized> Borrowed<'a, T> {
182    /// Borrow an I/O value.
183    pub fn new(inner: &'a mut T) -> Self {
184        Self(inner)
185    }
186}
187
188impl<T: Read + ?Sized> Read for Borrowed<'_, T> {
189    type Error = T::Error;
190    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
191        self.0.read(buf)
192    }
193}
194impl<T: Write + ?Sized> Write for Borrowed<'_, T> {
195    type Error = T::Error;
196    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
197        self.0.write(buf)
198    }
199    fn flush(&mut self) -> Result<(), Self::Error> {
200        self.0.flush()
201    }
202}
203impl<T: Seek + ?Sized> Seek for Borrowed<'_, T> {
204    type Error = T::Error;
205    fn seek(&mut self, pos: SeekFrom) -> Result<u64, Self::Error> {
206        self.0.seek(pos)
207    }
208}
209
210impl<T: embedded_io::Read> Read for FromEmbedded<T> {
211    type Error = T::Error;
212    fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
213        embedded_io::Read::read(&mut self.0, buf).map_err(Error::from_source)
214    }
215}
216
217impl<T: embedded_io::Write> Write for FromEmbedded<T> {
218    type Error = T::Error;
219    fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
220        embedded_io::Write::write(&mut self.0, buf).map_err(Error::from_source)
221    }
222    fn flush(&mut self) -> Result<(), Self::Error> {
223        embedded_io::Write::flush(&mut self.0).map_err(Error::from_source)
224    }
225}
226
227impl<T: embedded_io::Seek> Seek for FromEmbedded<T> {
228    type Error = T::Error;
229    fn seek(&mut self, pos: SeekFrom) -> Result<u64, Self::Error> {
230        embedded_io::Seek::seek(&mut self.0, pos).map_err(Error::from_source)
231    }
232}
233
234/// Explicitly expose a Hadris value through `embedded-io` traits.
235#[derive(Debug, Clone, Copy, Default)]
236pub struct ToEmbedded<T>(pub T);
237
238impl<T> ToEmbedded<T> {
239    /// Wrap a Hadris I/O value.
240    pub const fn new(inner: T) -> Self {
241        Self(inner)
242    }
243    /// Recover the wrapped value.
244    pub fn into_inner(self) -> T {
245        self.0
246    }
247}
248
249impl<T: Read> embedded_io::ErrorType for ToEmbedded<T> {
250    type Error = Error<T::Error>;
251}
252impl<T: Read> embedded_io::Read for ToEmbedded<T> {
253    fn read(&mut self, buf: &mut [u8]) -> core::result::Result<usize, Self::Error> {
254        Read::read(&mut self.0, buf)
255    }
256}
257impl<T> embedded_io::Write for ToEmbedded<T>
258where
259    T: Read + Write<Error = <T as Read>::Error>,
260{
261    fn write(&mut self, buf: &[u8]) -> core::result::Result<usize, Self::Error> {
262        Write::write(&mut self.0, buf)
263    }
264    fn flush(&mut self) -> core::result::Result<(), Self::Error> {
265        Write::flush(&mut self.0)
266    }
267}
268impl<T> embedded_io::Seek for ToEmbedded<T>
269where
270    T: Read + Seek<Error = <T as Read>::Error>,
271{
272    fn seek(&mut self, pos: SeekFrom) -> core::result::Result<u64, Self::Error> {
273        Seek::seek(&mut self.0, pos)
274    }
275}
276
277/// Structured-reading helpers.
278pub trait ReadExt: Read {
279    /// Read an arbitrary-bit-pattern value.
280    fn read_struct<T: bytemuck::Zeroable + bytemuck::NoUninit + bytemuck::AnyBitPattern>(
281        &mut self,
282    ) -> Result<T> {
283        let mut temp = T::zeroed();
284        self.read_exact(bytemuck::bytes_of_mut(&mut temp))?;
285        Ok(temp)
286    }
287
288    /// Parse a value with its custom parser.
289    fn parse<T: Parsable>(&mut self) -> Result<T>
290    where
291        Self: Sized,
292    {
293        T::parse(self)
294    }
295}
296impl<T: Read + ?Sized> ReadExt for T {}
297
298/// Parse a value from a reader.
299pub trait Parsable: Sized {
300    /// Parse `Self` while preserving the reader's source error.
301    fn parse<R: Read>(reader: &mut R) -> Result<Self>;
302}
303
304/// Write a value to a writer.
305pub trait Writable: Sized {
306    /// Write `Self` while preserving the writer's source error.
307    fn write<W: Write>(&self, writer: &mut W) -> Result<()>;
308}