| // SPDX-License-Identifier: Apache-2.0 |
| |
| //! Simple, Low-level I/O traits |
| //! |
| //! This crate provides two simple traits: `Read` and `Write`. These traits |
| //! mimic their counterparts in `std::io`, but are trimmed for simplicity |
| //! and can be used in `no_std` and `no_alloc` environments. Since this |
| //! crate contains only traits, inline functions and unit structs, it should |
| //! be a zero-cost abstraction. |
| //! |
| //! If the `std` feature is enabled, we provide blanket implementations for |
| //! all `std::io` types. If the `alloc` feature is enabled, we provide |
| //! implementations for `Vec<u8>`. In all cases, you get implementations |
| //! for byte slices. You can, of course, implement the traits for your own |
| //! types. |
| |
| #![cfg_attr(not(feature = "std"), no_std)] |
| #![deny(missing_docs)] |
| #![deny(clippy::all)] |
| #![deny(clippy::cargo)] |
| |
| extern crate std; |
| |
| #[cfg(feature = "alloc")] |
| extern crate alloc; |
| |
| /// A trait indicating a type that can read bytes |
| /// |
| /// Note that this is similar to `std::io::Read`, but simplified for use in a |
| /// `no_std` context. |
| pub trait Read { |
| /// The error type |
| type Error; |
| |
| /// Reads exactly `data.len()` bytes or fails |
| fn read_exact(&mut self, data: &mut [u8]) -> Result<(), Self::Error>; |
| } |
| |
| /// A trait indicating a type that can write bytes |
| /// |
| /// Note that this is similar to `std::io::Write`, but simplified for use in a |
| /// `no_std` context. |
| pub trait Write { |
| /// The error type |
| type Error; |
| |
| /// Writes all bytes from `data` or fails |
| fn write_all(&mut self, data: &[u8]) -> Result<(), Self::Error>; |
| |
| /// Flushes all output |
| fn flush(&mut self) -> Result<(), Self::Error>; |
| } |
| |
| #[cfg(feature = "std")] |
| impl<T: std::io::Read> Read for T { |
| type Error = std::io::Error; |
| |
| #[inline] |
| fn read_exact(&mut self, data: &mut [u8]) -> Result<(), Self::Error> { |
| self.read_exact(data) |
| } |
| } |
| |
| #[cfg(feature = "std")] |
| impl<T: std::io::Write> Write for T { |
| type Error = std::io::Error; |
| |
| #[inline] |
| fn write_all(&mut self, data: &[u8]) -> Result<(), Self::Error> { |
| self.write_all(data) |
| } |
| |
| #[inline] |
| fn flush(&mut self) -> Result<(), Self::Error> { |
| self.flush() |
| } |
| } |
| |
| #[cfg(not(feature = "std"))] |
| impl<R: Read + ?Sized> Read for &mut R { |
| type Error = R::Error; |
| |
| #[inline] |
| fn read_exact(&mut self, data: &mut [u8]) -> Result<(), Self::Error> { |
| (**self).read_exact(data) |
| } |
| } |
| |
| #[cfg(not(feature = "std"))] |
| impl<W: Write + ?Sized> Write for &mut W { |
| type Error = W::Error; |
| |
| #[inline] |
| fn write_all(&mut self, data: &[u8]) -> Result<(), Self::Error> { |
| (**self).write_all(data) |
| } |
| |
| #[inline] |
| fn flush(&mut self) -> Result<(), Self::Error> { |
| (**self).flush() |
| } |
| } |
| |
| /// An error indicating there are no more bytes to read |
| #[cfg(not(feature = "std"))] |
| #[derive(Debug)] |
| pub struct EndOfFile(()); |
| |
| #[cfg(not(feature = "std"))] |
| impl Read for &[u8] { |
| type Error = EndOfFile; |
| |
| #[inline] |
| fn read_exact(&mut self, data: &mut [u8]) -> Result<(), Self::Error> { |
| if data.len() > self.len() { |
| return Err(EndOfFile(())); |
| } |
| |
| let (prefix, suffix) = self.split_at(data.len()); |
| data.copy_from_slice(prefix); |
| *self = suffix; |
| Ok(()) |
| } |
| } |
| |
| /// An error indicating that the output cannot accept more bytes |
| #[cfg(not(feature = "std"))] |
| #[derive(Debug)] |
| pub struct OutOfSpace(()); |
| |
| #[cfg(not(feature = "std"))] |
| impl Write for &mut [u8] { |
| type Error = OutOfSpace; |
| |
| #[inline] |
| fn write_all(&mut self, data: &[u8]) -> Result<(), Self::Error> { |
| if data.len() > self.len() { |
| return Err(OutOfSpace(())); |
| } |
| |
| let (prefix, suffix) = core::mem::replace(self, &mut []).split_at_mut(data.len()); |
| prefix.copy_from_slice(data); |
| *self = suffix; |
| Ok(()) |
| } |
| |
| #[inline] |
| fn flush(&mut self) -> Result<(), Self::Error> { |
| Ok(()) |
| } |
| } |
| |
| #[cfg(all(not(feature = "std"), feature = "alloc"))] |
| impl Write for alloc::vec::Vec<u8> { |
| type Error = core::convert::Infallible; |
| |
| #[inline] |
| fn write_all(&mut self, data: &[u8]) -> Result<(), Self::Error> { |
| self.extend_from_slice(data); |
| Ok(()) |
| } |
| |
| #[inline] |
| fn flush(&mut self) -> Result<(), Self::Error> { |
| Ok(()) |
| } |
| } |
| |
| #[cfg(test)] |
| mod test { |
| use super::*; |
| |
| #[test] |
| fn read_eof() { |
| let mut reader = &[1u8; 0][..]; |
| let mut buffer = [0u8; 1]; |
| |
| reader.read_exact(&mut buffer[..]).unwrap_err(); |
| } |
| |
| #[test] |
| fn read_one() { |
| let mut reader = &[1u8; 1][..]; |
| let mut buffer = [0u8; 1]; |
| |
| reader.read_exact(&mut buffer[..]).unwrap(); |
| assert_eq!(buffer[0], 1); |
| |
| reader.read_exact(&mut buffer[..]).unwrap_err(); |
| } |
| |
| #[test] |
| fn read_two() { |
| let mut reader = &[1u8; 2][..]; |
| let mut buffer = [0u8; 1]; |
| |
| reader.read_exact(&mut buffer[..]).unwrap(); |
| assert_eq!(buffer[0], 1); |
| |
| reader.read_exact(&mut buffer[..]).unwrap(); |
| assert_eq!(buffer[0], 1); |
| |
| reader.read_exact(&mut buffer[..]).unwrap_err(); |
| } |
| |
| #[test] |
| #[cfg(feature = "std")] |
| fn read_std() { |
| let mut reader = std::io::repeat(1); |
| let mut buffer = [0u8; 2]; |
| |
| reader.read_exact(&mut buffer[..]).unwrap(); |
| assert_eq!(buffer[0], 1); |
| assert_eq!(buffer[1], 1); |
| } |
| |
| #[test] |
| fn write_oos() { |
| let mut writer = &mut [0u8; 0][..]; |
| |
| writer.write_all(&[1u8; 1][..]).unwrap_err(); |
| } |
| |
| #[test] |
| fn write_one() { |
| let mut buffer = [0u8; 1]; |
| let mut writer = &mut buffer[..]; |
| |
| writer.write_all(&[1u8; 1][..]).unwrap(); |
| writer.write_all(&[1u8; 1][..]).unwrap_err(); |
| assert_eq!(buffer[0], 1); |
| } |
| |
| #[test] |
| fn write_two() { |
| let mut buffer = [0u8; 2]; |
| let mut writer = &mut buffer[..]; |
| |
| writer.write_all(&[1u8; 1][..]).unwrap(); |
| writer.write_all(&[1u8; 1][..]).unwrap(); |
| writer.write_all(&[1u8; 1][..]).unwrap_err(); |
| assert_eq!(buffer[0], 1); |
| assert_eq!(buffer[1], 1); |
| } |
| |
| #[test] |
| #[cfg(feature = "alloc")] |
| fn write_vec() { |
| let mut buffer = alloc::vec::Vec::new(); |
| |
| buffer.write_all(&[1u8; 1][..]).unwrap(); |
| buffer.write_all(&[1u8; 1][..]).unwrap(); |
| |
| assert_eq!(buffer.len(), 2); |
| assert_eq!(buffer[0], 1); |
| assert_eq!(buffer[1], 1); |
| } |
| |
| #[test] |
| #[cfg(feature = "std")] |
| fn write_std() { |
| let mut writer = std::io::sink(); |
| |
| writer.write_all(&[1u8; 1][..]).unwrap(); |
| writer.write_all(&[1u8; 1][..]).unwrap(); |
| } |
| } |