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