Skip to content

Commit 95ae818

Browse files
committed
Introduce BufRead::skip_until and change ReadExactError -> OperationError
1 parent 5209452 commit 95ae818

File tree

2 files changed

+77
-17
lines changed

2 files changed

+77
-17
lines changed

embedded-io-async/src/lib.rs

Lines changed: 34 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ extern crate alloc;
1010
mod impls;
1111

1212
pub use embedded_io::{
13-
Error, ErrorKind, ErrorType, ReadExactError, ReadReady, SeekFrom, WriteReady,
13+
Error, ErrorKind, ErrorType, OperationError, ReadReady, SeekFrom, WriteReady,
1414
};
1515

1616
/// Async reader.
@@ -63,18 +63,18 @@ pub trait Read: ErrorType {
6363
///
6464
/// This function is not side-effect-free on cancel (AKA "cancel-safe"), i.e. if you cancel (drop) a returned
6565
/// 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>> {
66+
async fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<(), OperationError<Self::Error>> {
6767
while !buf.is_empty() {
6868
match self.read(buf).await {
6969
Ok(0) => break,
7070
Ok(n) => buf = &mut buf[n..],
71-
Err(e) => return Err(ReadExactError::Other(e)),
71+
Err(e) => return Err(OperationError::Other(e)),
7272
}
7373
}
7474
if buf.is_empty() {
7575
Ok(())
7676
} else {
77-
Err(ReadExactError::UnexpectedEof)
77+
Err(OperationError::UnexpectedEof)
7878
}
7979
}
8080
}
@@ -94,6 +94,36 @@ pub trait BufRead: ErrorType {
9494

9595
/// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`.
9696
fn consume(&mut self, amt: usize);
97+
98+
/// Skips all bytes until the delimiter `byte` or EOF is reached.
99+
///
100+
/// This function will read (and discard) bytes from the underlying stream, waiting until the
101+
/// delimiter is found, or an EOF condition is reached.
102+
///
103+
/// If successful, this function will return the total number of bytes read,
104+
/// including the delimiter byte.
105+
async fn skip_until(&mut self, delim: u8) -> Result<usize, OperationError<Self::Error>> {
106+
let mut read: usize = 0;
107+
loop {
108+
let (done, used) = {
109+
let available = self.fill_buf().await?;
110+
111+
if available.is_empty() {
112+
return Err(OperationError::UnexpectedEof)
113+
}
114+
115+
match available.iter().position(|p| *p == delim) {
116+
Some(i) => (true, i + 1),
117+
None => (false, available.len()),
118+
}
119+
};
120+
self.consume(used);
121+
read += used;
122+
if done || used == 0 {
123+
return Ok(read);
124+
}
125+
}
126+
}
97127
}
98128

99129
/// Async writer.

embedded-io/src/lib.rs

Lines changed: 43 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -227,43 +227,43 @@ impl<T: ?Sized + ErrorType> ErrorType for &mut T {
227227
type Error = T::Error;
228228
}
229229

230-
/// Error returned by [`Read::read_exact`]
230+
/// Error returned by [`Read::read_exact`] and [`BufRead::skip_until`]
231231
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
232232
#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
233-
pub enum ReadExactError<E> {
234-
/// An EOF error was encountered before reading the exact amount of requested bytes.
233+
pub enum OperationError<E> {
234+
/// An EOF error was encountered before the operation could complete.
235235
UnexpectedEof,
236236
/// Error returned by the inner Read.
237237
Other(E),
238238
}
239239

240-
impl<E> From<E> for ReadExactError<E> {
240+
impl<E> From<E> for OperationError<E> {
241241
fn from(err: E) -> Self {
242242
Self::Other(err)
243243
}
244244
}
245245

246246
#[cfg(feature = "std")]
247247
#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
248-
impl From<ReadExactError<std::io::Error>> for std::io::Error {
249-
fn from(err: ReadExactError<std::io::Error>) -> Self {
248+
impl From<OperationError<std::io::Error>> for std::io::Error {
249+
fn from(err: OperationError<std::io::Error>) -> Self {
250250
match err {
251-
ReadExactError::UnexpectedEof => std::io::Error::new(
251+
OperationError::UnexpectedEof => std::io::Error::new(
252252
std::io::ErrorKind::UnexpectedEof,
253253
"UnexpectedEof".to_owned(),
254254
),
255-
ReadExactError::Other(e) => std::io::Error::new(e.kind(), format!("{e:?}")),
255+
OperationError::Other(e) => std::io::Error::new(e.kind(), format!("{e:?}")),
256256
}
257257
}
258258
}
259259

260-
impl<E: fmt::Debug> fmt::Display for ReadExactError<E> {
260+
impl<E: fmt::Debug> fmt::Display for OperationError<E> {
261261
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
262262
write!(f, "{self:?}")
263263
}
264264
}
265265

266-
impl<E: fmt::Debug> core::error::Error for ReadExactError<E> {}
266+
impl<E: fmt::Debug> core::error::Error for OperationError<E> {}
267267

268268
/// Errors that could be returned by `Write` on `&mut [u8]`.
269269
#[derive(Debug, Copy, Clone, Eq, PartialEq)]
@@ -340,18 +340,18 @@ pub trait Read: ErrorType {
340340
/// If you are using [`ReadReady`] to avoid blocking, you should not use this function.
341341
/// `ReadReady::read_ready()` returning true only guarantees the first call to `read()` will
342342
/// not block, so this function may still block in subsequent calls.
343-
fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<(), ReadExactError<Self::Error>> {
343+
fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<(), OperationError<Self::Error>> {
344344
while !buf.is_empty() {
345345
match self.read(buf) {
346346
Ok(0) => break,
347347
Ok(n) => buf = &mut buf[n..],
348-
Err(e) => return Err(ReadExactError::Other(e)),
348+
Err(e) => return Err(OperationError::Other(e)),
349349
}
350350
}
351351
if buf.is_empty() {
352352
Ok(())
353353
} else {
354-
Err(ReadExactError::UnexpectedEof)
354+
Err(OperationError::UnexpectedEof)
355355
}
356356
}
357357
}
@@ -371,6 +371,36 @@ pub trait BufRead: ErrorType {
371371

372372
/// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`.
373373
fn consume(&mut self, amt: usize);
374+
375+
/// Skips all bytes until the delimiter `byte` or EOF is reached.
376+
///
377+
/// This function will read (and discard) bytes from the underlying stream, blocking until the
378+
/// delimiter is found, or an EOF condition is reached.
379+
///
380+
/// If successful, this function will return the total number of bytes read,
381+
/// including the delimiter byte.
382+
fn skip_until(&mut self, delim: u8) -> Result<usize, OperationError<Self::Error>> {
383+
let mut read: usize = 0;
384+
loop {
385+
let (done, used) = {
386+
let available = self.fill_buf()?;
387+
388+
if available.is_empty() {
389+
return Err(OperationError::UnexpectedEof)
390+
}
391+
392+
match available.iter().position(|p| *p == delim) {
393+
Some(i) => (true, i + 1),
394+
None => (false, available.len()),
395+
}
396+
};
397+
self.consume(used);
398+
read += used;
399+
if done || used == 0 {
400+
return Ok(read);
401+
}
402+
}
403+
}
374404
}
375405

376406
/// Blocking writer.

0 commit comments

Comments
 (0)