blob: 0594e8cc24724b14c42afafd2a4e8d1cd823a724 [file] [log] [blame]
// 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();
}
}