From d7f45d473e16964606f1cfbf1234fc2c89cd8d3a Mon Sep 17 00:00:00 2001 From: mwojcik Date: Wed, 6 Oct 2021 13:01:52 +0800 Subject: [PATCH] add libio (to be shared between runtime and satman) Reviewed-on: https://git.m-labs.hk/M-Labs/artiq-zynq/pulls/138 Co-authored-by: mwojcik Co-committed-by: mwojcik --- src/libio/Cargo.toml | 17 +++++ src/libio/cursor.rs | 81 ++++++++++++++++++++++ src/libio/lib.rs | 22 ++++++ src/libio/proto.rs | 158 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 278 insertions(+) create mode 100644 src/libio/Cargo.toml create mode 100644 src/libio/cursor.rs create mode 100644 src/libio/lib.rs create mode 100644 src/libio/proto.rs diff --git a/src/libio/Cargo.toml b/src/libio/Cargo.toml new file mode 100644 index 00000000..c02f08ab --- /dev/null +++ b/src/libio/Cargo.toml @@ -0,0 +1,17 @@ +[package] +authors = ["M-Labs"] +name = "io" +version = "0.0.0" + +[lib] +name = "io" +path = "lib.rs" + +[dependencies] +core_io = { version = "0.1", features = ["collections"] } +byteorder = { version = "1.0", default-features = false, optional = true } + +libsupport_zynq = { default-features = false, features = ["alloc_core"], git = "https://git.m-labs.hk/M-Labs/zynq-rs.git" } + +[features] +alloc = [] diff --git a/src/libio/cursor.rs b/src/libio/cursor.rs new file mode 100644 index 00000000..c31c8da5 --- /dev/null +++ b/src/libio/cursor.rs @@ -0,0 +1,81 @@ +use core_io::{Read, Write, Error as IoError}; + +#[derive(Debug, Clone)] +pub struct Cursor { + inner: T, + pos: usize +} + +impl Cursor { + #[inline] + pub fn new(inner: T) -> Cursor { + Cursor { inner, pos: 0 } + } + + #[inline] + pub fn into_inner(self) -> T { + self.inner + } + + #[inline] + pub fn get_ref(&self) -> &T { + &self.inner + } + + #[inline] + pub fn get_mut(&mut self) -> &mut T { + &mut self.inner + } + + #[inline] + pub fn position(&self) -> usize { + self.pos + } + + #[inline] + pub fn set_position(&mut self, pos: usize) { + self.pos = pos + } +} + +impl> Read for Cursor { + + fn read(&mut self, buf: &mut [u8]) -> Result { + let data = &self.inner.as_ref()[self.pos..]; + let len = buf.len().min(data.len()); + buf[..len].copy_from_slice(&data[..len]); + self.pos += len; + Ok(len) + } +} + +impl Write for Cursor<&mut [u8]> { + + fn write(&mut self, buf: &[u8]) -> Result { + let data = &mut self.inner[self.pos..]; + let len = buf.len().min(data.len()); + data[..len].copy_from_slice(&buf[..len]); + self.pos += len; + Ok(len) + } + + #[inline] + fn flush(&mut self) -> Result<(), IoError> { + Ok(()) + } +} + +#[cfg(feature = "alloc")] +impl Write for Cursor<::alloc::Vec> { + + #[inline] + fn write(&mut self, buf: &[u8]) -> Result { + self.inner.extend_from_slice(buf); + Ok(buf.len()) + } + + #[inline] + fn flush(&mut self) -> Result<(), IoError> { + Ok(()) + } +} diff --git a/src/libio/lib.rs b/src/libio/lib.rs new file mode 100644 index 00000000..e754be48 --- /dev/null +++ b/src/libio/lib.rs @@ -0,0 +1,22 @@ +#![no_std] +#![feature(never_type)] +#![cfg_attr(feature = "alloc", feature(alloc))] + +extern crate alloc; +extern crate core_io; + +#[cfg(feature = "alloc")] +#[macro_use] +use alloc; +#[cfg(feature = "byteorder")] +extern crate byteorder; + +pub mod cursor; +#[cfg(feature = "byteorder")] +pub mod proto; + +pub use cursor::Cursor; +#[cfg(feature = "byteorder")] +pub use proto::{ProtoRead, ProtoWrite}; +#[cfg(all(feature = "byteorder", feature = "alloc"))] +pub use proto::ReadStringError; \ No newline at end of file diff --git a/src/libio/proto.rs b/src/libio/proto.rs new file mode 100644 index 00000000..c165606b --- /dev/null +++ b/src/libio/proto.rs @@ -0,0 +1,158 @@ +use core::str::Utf8Error; +use byteorder::{ByteOrder, NativeEndian}; +use alloc::vec; +use alloc::string::String; + +use core_io::{Read, Write, Error as IoError}; + +#[allow(dead_code)] +#[derive(Debug, Clone, PartialEq)] +pub enum ReadStringError { + Utf8(Utf8Error), + Other(T) +} + +pub trait ProtoRead { + type ReadError; + + fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::ReadError>; + + #[inline] + fn read_u8(&mut self) -> Result { + let mut bytes = [0; 1]; + self.read_exact(&mut bytes)?; + Ok(bytes[0]) + } + + #[inline] + fn read_u16(&mut self) -> Result { + let mut bytes = [0; 2]; + self.read_exact(&mut bytes)?; + Ok(NativeEndian::read_u16(&bytes)) + } + + #[inline] + fn read_u32(&mut self) -> Result { + let mut bytes = [0; 4]; + self.read_exact(&mut bytes)?; + Ok(NativeEndian::read_u32(&bytes)) + } + + #[inline] + fn read_u64(&mut self) -> Result { + let mut bytes = [0; 8]; + self.read_exact(&mut bytes)?; + Ok(NativeEndian::read_u64(&bytes)) + } + + #[inline] + fn read_bool(&mut self) -> Result { + Ok(self.read_u8()? != 0) + } + + #[inline] + fn read_bytes(&mut self) -> Result<::alloc::vec::Vec, Self::ReadError> { + let length = self.read_u32()?; + let mut value = vec![0; length as usize]; + self.read_exact(&mut value)?; + Ok(value) + } + + #[inline] + fn read_string(&mut self) -> Result<::alloc::string::String, ReadStringError> { + let bytes = self.read_bytes().map_err(ReadStringError::Other)?; + String::from_utf8(bytes).map_err(|err| ReadStringError::Utf8(err.utf8_error())) + } +} + +pub trait ProtoWrite { + type WriteError; + + fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::WriteError>; + + #[inline] + fn write_u8(&mut self, value: u8) -> Result<(), Self::WriteError> { + let bytes = [value; 1]; + self.write_all(&bytes) + } + + #[inline] + fn write_i8(&mut self, value: i8) -> Result<(), Self::WriteError> { + let bytes = [value as u8; 1]; + self.write_all(&bytes) + } + + #[inline] + fn write_u16(&mut self, value: u16) -> Result<(), Self::WriteError> { + let mut bytes = [0; 2]; + NativeEndian::write_u16(&mut bytes, value); + self.write_all(&bytes) + } + + #[inline] + fn write_i16(&mut self, value: i16) -> Result<(), Self::WriteError> { + let mut bytes = [0; 2]; + NativeEndian::write_i16(&mut bytes, value); + self.write_all(&bytes) + } + + #[inline] + fn write_u32(&mut self, value: u32) -> Result<(), Self::WriteError> { + let mut bytes = [0; 4]; + NativeEndian::write_u32(&mut bytes, value); + self.write_all(&bytes) + } + + #[inline] + fn write_i32(&mut self, value: i32) -> Result<(), Self::WriteError> { + let mut bytes = [0; 4]; + NativeEndian::write_i32(&mut bytes, value); + self.write_all(&bytes) + } + + #[inline] + fn write_u64(&mut self, value: u64) -> Result<(), Self::WriteError> { + let mut bytes = [0; 8]; + NativeEndian::write_u64(&mut bytes, value); + self.write_all(&bytes) + } + + #[inline] + fn write_i64(&mut self, value: i64) -> Result<(), Self::WriteError> { + let mut bytes = [0; 8]; + NativeEndian::write_i64(&mut bytes, value); + self.write_all(&bytes) + } + + #[inline] + fn write_bool(&mut self, value: bool) -> Result<(), Self::WriteError> { + self.write_u8(value as u8) + } + + #[inline] + fn write_bytes(&mut self, value: &[u8]) -> Result<(), Self::WriteError> { + self.write_u32(value.len() as u32)?; + self.write_all(value) + } + + #[inline] + fn write_string(&mut self, value: &str) -> Result<(), Self::WriteError> { + self.write_bytes(value.as_bytes()) + } +} + +impl ProtoRead for T where T: Read + ?Sized { + type ReadError = IoError; + + fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::ReadError> { + T::read_exact(self, buf) + } +} + +impl ProtoWrite for T where T: Write + ?Sized { + type WriteError = IoError; + + fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::WriteError> { + T::write_all(self, buf) + } +}