embedded_io_async/lib.rs
1#![cfg_attr(not(feature = "std"), no_std)]
2#![cfg_attr(docsrs, feature(doc_cfg))]
3#![warn(missing_docs)]
4#![doc = include_str!("../README.md")]
5#![allow(async_fn_in_trait)]
6
7#[cfg(feature = "alloc")]
8extern crate alloc;
9
10mod impls;
11
12pub use embedded_io::{
13 Error, ErrorKind, ErrorType, ReadExactError, ReadReady, SeekFrom, WriteReady,
14};
15
16/// Async reader.
17///
18/// This trait is the `embedded-io-async` equivalent of [`std::io::Read`].
19pub trait Read: ErrorType {
20 /// Read some bytes from this source into the specified buffer, returning how many bytes were read.
21 ///
22 /// If no bytes are currently available to read:
23 /// - The method waits until at least one byte becomes available;
24 /// - Once at least one (or more) bytes become available, a non-zero amount of those is copied to the
25 /// beginning of `buf`, and the amount is returned, *without waiting any further for more bytes to
26 /// become available*.
27 ///
28 /// If bytes are available to read:
29 /// - A non-zero amount of bytes is read to the beginning of `buf`, and the amount is returned immediately,
30 /// *without waiting for more bytes to become available*;
31 ///
32 /// Note that once some bytes are available to read, it is *not* guaranteed that all available bytes are returned.
33 /// It is possible for the implementation to read an amount of bytes less than `buf.len()` while there are more
34 /// bytes immediately available.
35 ///
36 /// This waiting behavior is important for the cases where `Read` represents the "read" leg of a pipe-like
37 /// protocol (a socket, a pipe, a serial line etc.). The semantics is that the caller - by passing a non-empty
38 /// buffer - does expect _some_ data (one or more bytes) - but _not necessarily `buf.len()` or more bytes_ -
39 /// to become available, before the peer represented by `Read` would stop sending bytes due to
40 /// application-specific reasons (as in the peer waiting for a response to the data it had sent so far).
41 ///
42 /// If the reader is at end-of-file (EOF), `Ok(0)` is returned. There is no guarantee that a reader at EOF
43 /// will always be so in the future, for example a reader can stop being at EOF if another process appends
44 /// more bytes to the underlying file.
45 ///
46 /// If `buf.len() == 0`, `read` returns without waiting, with either `Ok(0)` or an error.
47 /// The `Ok(0)` doesn't indicate EOF, unlike when called with a non-empty buffer.
48 ///
49 /// Implementations are encouraged to make this function side-effect-free on cancel (AKA "cancel-safe"), i.e.
50 /// guarantee that if you cancel (drop) a `read()` future that hasn't completed yet, the stream's
51 /// state hasn't changed (no bytes have been read).
52 ///
53 /// This is not a requirement to allow implementations that read into the user's buffer straight from
54 /// the hardware with e.g. DMA.
55 ///
56 /// Implementations should document whether they're actually side-effect-free on cancel or not.
57 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error>;
58
59 /// Read the exact number of bytes required to fill `buf`.
60 ///
61 /// This function calls `read()` in a loop until exactly `buf.len()` bytes have
62 /// been read, waiting if needed.
63 ///
64 /// This function is not side-effect-free on cancel (AKA "cancel-safe"), i.e. if you cancel (drop) a returned
65 /// future that hasn't completed yet, some bytes might have already been read, which will get lost.
66 async fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<(), ReadExactError<Self::Error>> {
67 while !buf.is_empty() {
68 match self.read(buf).await {
69 Ok(0) => break,
70 Ok(n) => buf = &mut buf[n..],
71 Err(e) => return Err(ReadExactError::Other(e)),
72 }
73 }
74 if buf.is_empty() {
75 Ok(())
76 } else {
77 Err(ReadExactError::UnexpectedEof)
78 }
79 }
80}
81
82/// Async buffered reader.
83///
84/// This trait is the `embedded-io-async` equivalent of [`std::io::BufRead`].
85pub trait BufRead: Read {
86 /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty.
87 ///
88 /// If no bytes are currently available to read, this function waits until at least one byte is available.
89 ///
90 /// If the reader is at end-of-file (EOF), an empty slice is returned. There is no guarantee that a reader at EOF
91 /// will always be so in the future, for example a reader can stop being at EOF if another process appends
92 /// more bytes to the underlying file.
93 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error>;
94
95 /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`.
96 fn consume(&mut self, amt: usize);
97}
98
99/// Async writer.
100///
101/// This trait is the `embedded-io-async` equivalent of [`std::io::Write`].
102pub trait Write: ErrorType {
103 /// Write a buffer into this writer, returning how many bytes were written.
104 ///
105 /// If the writer is not currently ready to accept more bytes (for example, its buffer is full),
106 /// this function waits until it is ready to accept least one byte.
107 ///
108 /// If it's ready to accept bytes, a non-zero amount of bytes is written from the beginning of `buf`, and the amount
109 /// is returned. It is not guaranteed that *all* available buffer space is filled, i.e. it is possible for the
110 /// implementation to write an amount of bytes less than `buf.len()` while the writer continues to be
111 /// ready to accept more bytes immediately.
112 ///
113 /// Implementations should never return `Ok(0)` when `buf.len() != 0`. Situations where the writer is not
114 /// able to accept more bytes and likely never will are better indicated with errors.
115 ///
116 /// If `buf.len() == 0`, `write` returns without waiting, with either `Ok(0)` or an error.
117 /// The `Ok(0)` doesn't indicate an error.
118 ///
119 /// Implementations are encouraged to make this function side-effect-free on cancel (AKA "cancel-safe"), i.e.
120 /// guarantee that if you cancel (drop) a `write()` future that hasn't completed yet, the stream's
121 /// state hasn't changed (no bytes have been written).
122 ///
123 /// This is not a requirement to allow implementations that write from the user's buffer straight to
124 /// the hardware with e.g. DMA.
125 ///
126 /// Implementations should document whether they're actually side-effect-free on cancel or not.
127 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error>;
128
129 /// Flush this output stream, ensuring that all intermediately buffered contents reach their destination.
130 async fn flush(&mut self) -> Result<(), Self::Error>;
131
132 /// Write an entire buffer into this writer.
133 ///
134 /// This function calls `write()` in a loop until exactly `buf.len()` bytes have
135 /// been written, waiting if needed.
136 ///
137 /// This function is not side-effect-free on cancel (AKA "cancel-safe"), i.e. if you cancel (drop) a returned
138 /// future that hasn't completed yet, some bytes might have already been written.
139 async fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
140 let mut buf = buf;
141 while !buf.is_empty() {
142 match self.write(buf).await {
143 Ok(0) => panic!("write() returned Ok(0)"),
144 Ok(n) => buf = &buf[n..],
145 Err(e) => return Err(e),
146 }
147 }
148 Ok(())
149 }
150}
151
152/// Async seek within streams.
153///
154/// This trait is the `embedded-io-async` equivalent of [`std::io::Seek`].
155pub trait Seek: ErrorType {
156 /// Seek to an offset, in bytes, in a stream.
157 async fn seek(&mut self, pos: SeekFrom) -> Result<u64, Self::Error>;
158
159 /// Rewind to the beginning of a stream.
160 async fn rewind(&mut self) -> Result<(), Self::Error> {
161 self.seek(SeekFrom::Start(0)).await?;
162 Ok(())
163 }
164
165 /// Returns the current seek position from the start of the stream.
166 async fn stream_position(&mut self) -> Result<u64, Self::Error> {
167 self.seek(SeekFrom::Current(0)).await
168 }
169}
170
171impl<T: ?Sized + Read> Read for &mut T {
172 #[inline]
173 async fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
174 T::read(self, buf).await
175 }
176
177 #[inline]
178 async fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), ReadExactError<Self::Error>> {
179 T::read_exact(self, buf).await
180 }
181}
182
183impl<T: ?Sized + BufRead> BufRead for &mut T {
184 #[inline]
185 async fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
186 T::fill_buf(self).await
187 }
188
189 #[inline]
190 fn consume(&mut self, amt: usize) {
191 T::consume(self, amt);
192 }
193}
194
195impl<T: ?Sized + Write> Write for &mut T {
196 #[inline]
197 async fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
198 T::write(self, buf).await
199 }
200
201 #[inline]
202 async fn flush(&mut self) -> Result<(), Self::Error> {
203 T::flush(self).await
204 }
205
206 #[inline]
207 async fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::Error> {
208 T::write_all(self, buf).await
209 }
210}
211
212impl<T: ?Sized + Seek> Seek for &mut T {
213 #[inline]
214 async fn seek(&mut self, pos: SeekFrom) -> Result<u64, Self::Error> {
215 T::seek(self, pos).await
216 }
217
218 #[inline]
219 async fn rewind(&mut self) -> Result<(), Self::Error> {
220 T::rewind(self).await
221 }
222
223 #[inline]
224 async fn stream_position(&mut self) -> Result<u64, Self::Error> {
225 T::stream_position(self).await
226 }
227}