embedded_io/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
6use core::fmt;
7
8// needed to prevent defmt macros from breaking, since they emit code that does `defmt::blahblah`.
9#[cfg(feature = "defmt-03")]
10use defmt_03 as defmt;
11
12#[cfg(feature = "alloc")]
13extern crate alloc;
14
15mod impls;
16
17/// Enumeration of possible methods to seek within an I/O object.
18///
19/// This is the `embedded-io` equivalent of [`std::io::SeekFrom`].
20#[derive(Debug, Copy, Clone, Eq, PartialEq)]
21#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
22pub enum SeekFrom {
23 /// Sets the offset to the provided number of bytes.
24 Start(u64),
25 /// Sets the offset to the size of this object plus the specified number of bytes.
26 End(i64),
27 /// Sets the offset to the current position plus the specified number of bytes.
28 Current(i64),
29}
30
31#[cfg(feature = "std")]
32#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
33impl From<SeekFrom> for std::io::SeekFrom {
34 fn from(pos: SeekFrom) -> Self {
35 match pos {
36 SeekFrom::Start(n) => std::io::SeekFrom::Start(n),
37 SeekFrom::End(n) => std::io::SeekFrom::End(n),
38 SeekFrom::Current(n) => std::io::SeekFrom::Current(n),
39 }
40 }
41}
42
43#[cfg(feature = "std")]
44#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
45impl From<std::io::SeekFrom> for SeekFrom {
46 fn from(pos: std::io::SeekFrom) -> SeekFrom {
47 match pos {
48 std::io::SeekFrom::Start(n) => SeekFrom::Start(n),
49 std::io::SeekFrom::End(n) => SeekFrom::End(n),
50 std::io::SeekFrom::Current(n) => SeekFrom::Current(n),
51 }
52 }
53}
54
55/// Possible kinds of errors.
56///
57/// This list is intended to grow over time and it is not recommended to
58/// exhaustively match against it. In application code, use `match` for the `ErrorKind`
59/// values you are expecting; use `_` to match "all other errors".
60///
61/// This is the `embedded-io` equivalent of [`std::io::ErrorKind`], except with the following changes:
62///
63/// - `WouldBlock` is removed, since `embedded-io` traits are always blocking. See the [crate-level documentation](crate) for details.
64#[derive(Debug, Copy, Clone, Eq, PartialEq)]
65#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
66#[non_exhaustive]
67pub enum ErrorKind {
68 /// Unspecified error kind.
69 Other,
70
71 /// An entity was not found, often a file.
72 NotFound,
73 /// The operation lacked the necessary privileges to complete.
74 PermissionDenied,
75 /// The connection was refused by the remote server.
76 ConnectionRefused,
77 /// The connection was reset by the remote server.
78 ConnectionReset,
79 /// The connection was aborted (terminated) by the remote server.
80 ConnectionAborted,
81 /// The network operation failed because it was not connected yet.
82 NotConnected,
83 /// A socket address could not be bound because the address is already in
84 /// use elsewhere.
85 AddrInUse,
86 /// A nonexistent interface was requested or the requested address was not
87 /// local.
88 AddrNotAvailable,
89 /// The operation failed because a pipe was closed.
90 BrokenPipe,
91 /// An entity already exists, often a file.
92 AlreadyExists,
93 /// A parameter was incorrect.
94 InvalidInput,
95 /// Data not valid for the operation were encountered.
96 ///
97 /// Unlike [`InvalidInput`], this typically means that the operation
98 /// parameters were valid, however the error was caused by malformed
99 /// input data.
100 ///
101 /// For example, a function that reads a file into a string will error with
102 /// `InvalidData` if the file's contents are not valid UTF-8.
103 ///
104 /// [`InvalidInput`]: ErrorKind::InvalidInput
105 InvalidData,
106 /// The I/O operation's timeout expired, causing it to be canceled.
107 TimedOut,
108 /// This operation was interrupted.
109 ///
110 /// Interrupted operations can typically be retried.
111 Interrupted,
112 /// This operation is unsupported on this platform.
113 ///
114 /// This means that the operation can never succeed.
115 Unsupported,
116 /// An operation could not be completed, because it failed
117 /// to allocate enough memory.
118 OutOfMemory,
119 /// An attempted write could not write any data.
120 WriteZero,
121}
122
123#[cfg(feature = "std")]
124#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
125impl From<ErrorKind> for std::io::ErrorKind {
126 fn from(value: ErrorKind) -> Self {
127 match value {
128 ErrorKind::NotFound => std::io::ErrorKind::NotFound,
129 ErrorKind::PermissionDenied => std::io::ErrorKind::PermissionDenied,
130 ErrorKind::ConnectionRefused => std::io::ErrorKind::ConnectionRefused,
131 ErrorKind::ConnectionReset => std::io::ErrorKind::ConnectionReset,
132 ErrorKind::ConnectionAborted => std::io::ErrorKind::ConnectionAborted,
133 ErrorKind::NotConnected => std::io::ErrorKind::NotConnected,
134 ErrorKind::AddrInUse => std::io::ErrorKind::AddrInUse,
135 ErrorKind::AddrNotAvailable => std::io::ErrorKind::AddrNotAvailable,
136 ErrorKind::BrokenPipe => std::io::ErrorKind::BrokenPipe,
137 ErrorKind::AlreadyExists => std::io::ErrorKind::AlreadyExists,
138 ErrorKind::InvalidInput => std::io::ErrorKind::InvalidInput,
139 ErrorKind::InvalidData => std::io::ErrorKind::InvalidData,
140 ErrorKind::TimedOut => std::io::ErrorKind::TimedOut,
141 ErrorKind::Interrupted => std::io::ErrorKind::Interrupted,
142 ErrorKind::Unsupported => std::io::ErrorKind::Unsupported,
143 ErrorKind::OutOfMemory => std::io::ErrorKind::OutOfMemory,
144 _ => std::io::ErrorKind::Other,
145 }
146 }
147}
148
149#[cfg(feature = "std")]
150#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
151impl From<std::io::ErrorKind> for ErrorKind {
152 fn from(value: std::io::ErrorKind) -> Self {
153 match value {
154 std::io::ErrorKind::NotFound => ErrorKind::NotFound,
155 std::io::ErrorKind::PermissionDenied => ErrorKind::PermissionDenied,
156 std::io::ErrorKind::ConnectionRefused => ErrorKind::ConnectionRefused,
157 std::io::ErrorKind::ConnectionReset => ErrorKind::ConnectionReset,
158 std::io::ErrorKind::ConnectionAborted => ErrorKind::ConnectionAborted,
159 std::io::ErrorKind::NotConnected => ErrorKind::NotConnected,
160 std::io::ErrorKind::AddrInUse => ErrorKind::AddrInUse,
161 std::io::ErrorKind::AddrNotAvailable => ErrorKind::AddrNotAvailable,
162 std::io::ErrorKind::BrokenPipe => ErrorKind::BrokenPipe,
163 std::io::ErrorKind::AlreadyExists => ErrorKind::AlreadyExists,
164 std::io::ErrorKind::InvalidInput => ErrorKind::InvalidInput,
165 std::io::ErrorKind::InvalidData => ErrorKind::InvalidData,
166 std::io::ErrorKind::TimedOut => ErrorKind::TimedOut,
167 std::io::ErrorKind::Interrupted => ErrorKind::Interrupted,
168 std::io::ErrorKind::Unsupported => ErrorKind::Unsupported,
169 std::io::ErrorKind::OutOfMemory => ErrorKind::OutOfMemory,
170 _ => ErrorKind::Other,
171 }
172 }
173}
174
175/// Error trait.
176///
177/// This trait allows generic code to do limited inspecting of errors,
178/// to react differently to different kinds.
179pub trait Error: fmt::Debug {
180 /// Get the kind of this error.
181 fn kind(&self) -> ErrorKind;
182}
183
184impl Error for core::convert::Infallible {
185 fn kind(&self) -> ErrorKind {
186 match *self {}
187 }
188}
189
190impl Error for ErrorKind {
191 fn kind(&self) -> ErrorKind {
192 *self
193 }
194}
195
196#[cfg(feature = "std")]
197#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
198impl Error for std::io::Error {
199 fn kind(&self) -> ErrorKind {
200 self.kind().into()
201 }
202}
203
204/// Base trait for all IO traits, defining the error type.
205///
206/// All IO operations of all traits return the error defined in this trait.
207///
208/// Having a shared trait instead of having every trait define its own
209/// `Error` associated type enforces all impls on the same type use the same error.
210/// This is very convenient when writing generic code, it means you have to
211/// handle a single error type `T::Error`, instead of `<T as Read>::Error` and `<T as Write>::Error`
212/// which might be different types.
213pub trait ErrorType {
214 /// Error type of all the IO operations on this type.
215 type Error: Error;
216}
217
218impl<T: ?Sized + ErrorType> ErrorType for &mut T {
219 type Error = T::Error;
220}
221
222/// Error returned by [`Read::read_exact`]
223#[derive(Debug, Copy, Clone, Eq, PartialEq)]
224#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
225pub enum ReadExactError<E> {
226 /// An EOF error was encountered before reading the exact amount of requested bytes.
227 UnexpectedEof,
228 /// Error returned by the inner Read.
229 Other(E),
230}
231
232impl<E> From<E> for ReadExactError<E> {
233 fn from(err: E) -> Self {
234 Self::Other(err)
235 }
236}
237
238#[cfg(feature = "std")]
239#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
240impl From<ReadExactError<std::io::Error>> for std::io::Error {
241 fn from(err: ReadExactError<std::io::Error>) -> Self {
242 match err {
243 ReadExactError::UnexpectedEof => std::io::Error::new(
244 std::io::ErrorKind::UnexpectedEof,
245 "UnexpectedEof".to_owned(),
246 ),
247 ReadExactError::Other(e) => std::io::Error::new(e.kind(), format!("{e:?}")),
248 }
249 }
250}
251
252impl<E: fmt::Debug> fmt::Display for ReadExactError<E> {
253 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
254 write!(f, "{self:?}")
255 }
256}
257
258#[cfg(feature = "std")]
259#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
260impl<E: fmt::Debug> std::error::Error for ReadExactError<E> {}
261
262/// Errors that could be returned by `Write` on `&mut [u8]`.
263#[derive(Debug, Copy, Clone, Eq, PartialEq)]
264#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
265#[non_exhaustive]
266pub enum SliceWriteError {
267 /// The target slice was full and so could not receive any new data.
268 Full,
269}
270
271/// Error returned by [`Write::write_fmt`]
272#[derive(Debug, Copy, Clone, Eq, PartialEq)]
273#[cfg_attr(feature = "defmt-03", derive(defmt::Format))]
274pub enum WriteFmtError<E> {
275 /// An error was encountered while formatting.
276 FmtError,
277 /// Error returned by the inner Write.
278 Other(E),
279}
280
281impl<E> From<E> for WriteFmtError<E> {
282 fn from(err: E) -> Self {
283 Self::Other(err)
284 }
285}
286
287impl<E: fmt::Debug> fmt::Display for WriteFmtError<E> {
288 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
289 write!(f, "{self:?}")
290 }
291}
292
293#[cfg(feature = "std")]
294#[cfg_attr(docsrs, doc(cfg(feature = "std")))]
295impl<E: fmt::Debug> std::error::Error for WriteFmtError<E> {}
296
297/// Blocking reader.
298///
299/// This trait is the `embedded-io` equivalent of [`std::io::Read`].
300pub trait Read: ErrorType {
301 /// Read some bytes from this source into the specified buffer, returning how many bytes were read.
302 ///
303 /// If no bytes are currently available to read, this function blocks until at least one byte is available.
304 ///
305 /// If bytes are available, a non-zero amount of bytes is read to the beginning of `buf`, and the amount
306 /// is returned. It is not guaranteed that *all* available bytes are returned, it is possible for the
307 /// implementation to read an amount of bytes less than `buf.len()` while there are more bytes immediately
308 /// available.
309 ///
310 /// If the reader is at end-of-file (EOF), `Ok(0)` is returned. There is no guarantee that a reader at EOF
311 /// will always be so in the future, for example a reader can stop being at EOF if another process appends
312 /// more bytes to the underlying file.
313 ///
314 /// If `buf.len() == 0`, `read` returns without blocking, with either `Ok(0)` or an error.
315 /// The `Ok(0)` doesn't indicate EOF, unlike when called with a non-empty buffer.
316 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error>;
317
318 /// Read the exact number of bytes required to fill `buf`.
319 ///
320 /// This function calls `read()` in a loop until exactly `buf.len()` bytes have
321 /// been read, blocking if needed.
322 ///
323 /// If you are using [`ReadReady`] to avoid blocking, you should not use this function.
324 /// `ReadReady::read_ready()` returning true only guarantees the first call to `read()` will
325 /// not block, so this function may still block in subsequent calls.
326 fn read_exact(&mut self, mut buf: &mut [u8]) -> Result<(), ReadExactError<Self::Error>> {
327 while !buf.is_empty() {
328 match self.read(buf) {
329 Ok(0) => break,
330 Ok(n) => buf = &mut buf[n..],
331 Err(e) => return Err(ReadExactError::Other(e)),
332 }
333 }
334 if buf.is_empty() {
335 Ok(())
336 } else {
337 Err(ReadExactError::UnexpectedEof)
338 }
339 }
340}
341
342/// Blocking buffered reader.
343///
344/// This trait is the `embedded-io` equivalent of [`std::io::BufRead`].
345pub trait BufRead: ErrorType {
346 /// Return the contents of the internal buffer, filling it with more data from the inner reader if it is empty.
347 ///
348 /// If no bytes are currently available to read, this function blocks until at least one byte is available.
349 ///
350 /// If the reader is at end-of-file (EOF), an empty slice is returned. There is no guarantee that a reader at EOF
351 /// will always be so in the future, for example a reader can stop being at EOF if another process appends
352 /// more bytes to the underlying file.
353 fn fill_buf(&mut self) -> Result<&[u8], Self::Error>;
354
355 /// Tell this buffer that `amt` bytes have been consumed from the buffer, so they should no longer be returned in calls to `fill_buf`.
356 fn consume(&mut self, amt: usize);
357}
358
359/// Blocking writer.
360///
361/// This trait is the `embedded-io` equivalent of [`std::io::Write`].
362pub trait Write: ErrorType {
363 /// Write a buffer into this writer, returning how many bytes were written.
364 ///
365 /// If the writer is not currently ready to accept more bytes (for example, its buffer is full),
366 /// this function blocks until it is ready to accept least one byte.
367 ///
368 /// If it's ready to accept bytes, a non-zero amount of bytes is written from the beginning of `buf`, and the amount
369 /// is returned. It is not guaranteed that *all* available buffer space is filled, i.e. it is possible for the
370 /// implementation to write an amount of bytes less than `buf.len()` while the writer continues to be
371 /// ready to accept more bytes immediately.
372 ///
373 /// Implementations must not return `Ok(0)` unless `buf` is empty. Situations where the
374 /// writer is not able to accept more bytes must instead be indicated with an error,
375 /// where the `ErrorKind` is `WriteZero`.
376 ///
377 /// If `buf` is empty, `write` returns without blocking, with either `Ok(0)` or an error.
378 /// `Ok(0)` doesn't indicate an error.
379 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error>;
380
381 /// Flush this output stream, blocking until all intermediately buffered contents reach their destination.
382 fn flush(&mut self) -> Result<(), Self::Error>;
383
384 /// Write an entire buffer into this writer.
385 ///
386 /// This function calls `write()` in a loop until exactly `buf.len()` bytes have
387 /// been written, blocking if needed.
388 ///
389 /// If you are using [`WriteReady`] to avoid blocking, you should not use this function.
390 /// `WriteReady::write_ready()` returning true only guarantees the first call to `write()` will
391 /// not block, so this function may still block in subsequent calls.
392 ///
393 /// This function will panic if `write()` returns `Ok(0)`.
394 fn write_all(&mut self, mut buf: &[u8]) -> Result<(), Self::Error> {
395 while !buf.is_empty() {
396 match self.write(buf) {
397 Ok(0) => panic!("write() returned Ok(0)"),
398 Ok(n) => buf = &buf[n..],
399 Err(e) => return Err(e),
400 }
401 }
402 Ok(())
403 }
404
405 /// Write a formatted string into this writer, returning any error encountered.
406 ///
407 /// This function calls `write()` in a loop until the entire formatted string has
408 /// been written, blocking if needed.
409 ///
410 /// If you are using [`WriteReady`] to avoid blocking, you should not use this function.
411 /// `WriteReady::write_ready()` returning true only guarantees the first call to `write()` will
412 /// not block, so this function may still block in subsequent calls.
413 ///
414 /// Unlike [`Write::write`], the number of bytes written is not returned. However, in the case of
415 /// writing to an `&mut [u8]` its possible to calculate the number of bytes written by subtracting
416 /// the length of the slice after the write, from the initial length of the slice.
417 ///
418 /// ```rust
419 /// # use embedded_io::Write;
420 /// let mut buf: &mut [u8] = &mut [0u8; 256];
421 /// let start = buf.len();
422 /// let len = write!(buf, "{}", "Test").and_then(|_| Ok(start - buf.len()));
423 /// ```
424 fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> Result<(), WriteFmtError<Self::Error>> {
425 // Create a shim which translates a Write to a fmt::Write and saves
426 // off I/O errors. instead of discarding them
427 struct Adapter<'a, T: Write + ?Sized + 'a> {
428 inner: &'a mut T,
429 error: Result<(), T::Error>,
430 }
431
432 impl<T: Write + ?Sized> fmt::Write for Adapter<'_, T> {
433 fn write_str(&mut self, s: &str) -> fmt::Result {
434 match self.inner.write_all(s.as_bytes()) {
435 Ok(()) => Ok(()),
436 Err(e) => {
437 self.error = Err(e);
438 Err(fmt::Error)
439 }
440 }
441 }
442 }
443
444 let mut output = Adapter {
445 inner: self,
446 error: Ok(()),
447 };
448 match fmt::write(&mut output, fmt) {
449 Ok(()) => Ok(()),
450 Err(..) => match output.error {
451 // check if the error came from the underlying `Write` or not
452 Err(e) => Err(WriteFmtError::Other(e)),
453 Ok(()) => Err(WriteFmtError::FmtError),
454 },
455 }
456 }
457}
458
459/// Blocking seek within streams.
460///
461/// This trait is the `embedded-io` equivalent of [`std::io::Seek`].
462pub trait Seek: ErrorType {
463 /// Seek to an offset, in bytes, in a stream.
464 fn seek(&mut self, pos: SeekFrom) -> Result<u64, Self::Error>;
465
466 /// Rewind to the beginning of a stream.
467 fn rewind(&mut self) -> Result<(), Self::Error> {
468 self.seek(SeekFrom::Start(0))?;
469 Ok(())
470 }
471
472 /// Returns the current seek position from the start of the stream.
473 fn stream_position(&mut self) -> Result<u64, Self::Error> {
474 self.seek(SeekFrom::Current(0))
475 }
476}
477
478/// Get whether a reader is ready.
479///
480/// This allows using a [`Read`] or [`BufRead`] in a nonblocking fashion, i.e. trying to read
481/// only when it is ready.
482pub trait ReadReady: ErrorType {
483 /// Get whether the reader is ready for immediately reading.
484 ///
485 /// This usually means that there is either some bytes have been received and are buffered and ready to be read,
486 /// or that the reader is at EOF.
487 ///
488 /// If this returns `true`, it's guaranteed that the next call to [`Read::read`] or [`BufRead::fill_buf`] will not block.
489 fn read_ready(&mut self) -> Result<bool, Self::Error>;
490}
491
492/// Get whether a writer is ready.
493///
494/// This allows using a [`Write`] in a nonblocking fashion, i.e. trying to write
495/// only when it is ready.
496pub trait WriteReady: ErrorType {
497 /// Get whether the writer is ready for immediately writing.
498 ///
499 /// This usually means that there is free space in the internal transmit buffer.
500 ///
501 /// If this returns `true`, it's guaranteed that the next call to [`Write::write`] will not block.
502 fn write_ready(&mut self) -> Result<bool, Self::Error>;
503}
504
505impl<T: ?Sized + Read> Read for &mut T {
506 #[inline]
507 fn read(&mut self, buf: &mut [u8]) -> Result<usize, Self::Error> {
508 T::read(self, buf)
509 }
510}
511
512impl<T: ?Sized + BufRead> BufRead for &mut T {
513 fn fill_buf(&mut self) -> Result<&[u8], Self::Error> {
514 T::fill_buf(self)
515 }
516
517 fn consume(&mut self, amt: usize) {
518 T::consume(self, amt);
519 }
520}
521
522impl<T: ?Sized + Write> Write for &mut T {
523 #[inline]
524 fn write(&mut self, buf: &[u8]) -> Result<usize, Self::Error> {
525 T::write(self, buf)
526 }
527
528 #[inline]
529 fn flush(&mut self) -> Result<(), Self::Error> {
530 T::flush(self)
531 }
532}
533
534impl<T: ?Sized + Seek> Seek for &mut T {
535 #[inline]
536 fn seek(&mut self, pos: SeekFrom) -> Result<u64, Self::Error> {
537 T::seek(self, pos)
538 }
539}
540
541impl<T: ?Sized + ReadReady> ReadReady for &mut T {
542 #[inline]
543 fn read_ready(&mut self) -> Result<bool, Self::Error> {
544 T::read_ready(self)
545 }
546}
547
548impl<T: ?Sized + WriteReady> WriteReady for &mut T {
549 #[inline]
550 fn write_ready(&mut self) -> Result<bool, Self::Error> {
551 T::write_ready(self)
552 }
553}