aboutsummaryrefslogtreecommitdiff
path: root/src/lib.rs
diff options
context:
space:
mode:
Diffstat (limited to 'src/lib.rs')
-rw-r--r--src/lib.rs267
1 files changed, 267 insertions, 0 deletions
diff --git a/src/lib.rs b/src/lib.rs
new file mode 100644
index 0000000..0594e8c
--- /dev/null
+++ b/src/lib.rs
@@ -0,0 +1,267 @@
+// 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();
+ }
+}