diff --git a/artiq/firmware/libio/lib.rs b/artiq/firmware/libio/lib.rs index 4fb1cef91..0524e1c6f 100644 --- a/artiq/firmware/libio/lib.rs +++ b/artiq/firmware/libio/lib.rs @@ -190,7 +190,7 @@ impl Write for Cursor<::alloc::Vec> { } #[cfg(feature = "std_artiq")] -impl Read for T where T: std_artiq::io::Read { +impl Read for T where T: std_artiq::io::Read + ?Sized { type ReadError = std_artiq::io::Error; fn read(&mut self, buf: &mut [u8]) -> result::Result { @@ -199,7 +199,7 @@ impl Read for T where T: std_artiq::io::Read { } #[cfg(feature = "std_artiq")] -impl Write for T where T: std_artiq::io::Write { +impl Write for T where T: std_artiq::io::Write + ?Sized { type WriteError = std_artiq::io::Error; type FlushError = std_artiq::io::Error; diff --git a/artiq/firmware/libio/proto.rs b/artiq/firmware/libio/proto.rs index f8c52e1e7..143e8fd8f 100644 --- a/artiq/firmware/libio/proto.rs +++ b/artiq/firmware/libio/proto.rs @@ -1,7 +1,50 @@ +use core::fmt; +use alloc::string; use byteorder::{ByteOrder, NetworkEndian}; use ::{Read, Write, Error as IoError}; +#[derive(Debug)] +pub enum ReadStringError { + Utf8Error(string::FromUtf8Error), + Other(T) +} + +impl fmt::Display for ReadStringError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match self { + &ReadStringError::Utf8Error(ref err) => + write!(f, "invalid UTF-8 ({})", err), + &ReadStringError::Other(ref err) => + write!(f, "{}", err) + } + } +} + +impl From>> for IoError +{ + fn from(value: ReadStringError>) -> IoError { + match value { + ReadStringError::Utf8Error(_) => IoError::Unrecognized, + ReadStringError::Other(err) => err + } + } +} + +#[cfg(feature = "std_artiq")] +impl From> for ::std_artiq::io::Error + where T: Into<::std_artiq::io::Error> +{ + fn from(value: ReadStringError) -> ::std_artiq::io::Error { + match value { + ReadStringError::Utf8Error(_) => + ::std_artiq::io::Error::new(::std_artiq::io::ErrorKind::InvalidData, + "invalid UTF-8"), + ReadStringError::Other(err) => err.into() + } + } +} + pub trait ProtoRead { type ReadError; @@ -49,11 +92,18 @@ pub trait ProtoRead { Ok(value) } -// fn read_string(&mut self) -> Result { -// let bytes = self.read_bytes()?; -// String::from_utf8(bytes) -// .map_err(|_| io::Error::new(io::ErrorKind::InvalidData, "invalid UTF-8")) -// } + #[cfg(feature = "alloc")] + #[inline] + fn read_string(&mut self) -> Result<::alloc::String, ReadStringError> { + match self.read_bytes() { + Ok(bytes) => + match ::alloc::String::from_utf8(bytes) { + Ok(string) => Ok(string), + Err(err) => Err(ReadStringError::Utf8Error(err)) + }, + Err(err) => Err(ReadStringError::Other(err)) + } + } } pub trait ProtoWrite { @@ -132,7 +182,7 @@ pub trait ProtoWrite { } } -impl ProtoRead for T where T: Read { +impl ProtoRead for T where T: Read + ?Sized { type ReadError = IoError; fn read_exact(&mut self, buf: &mut [u8]) -> Result<(), Self::ReadError> { @@ -140,7 +190,7 @@ impl ProtoRead for T where T: Read { } } -impl ProtoWrite for T where T: Write { +impl ProtoWrite for T where T: Write + ?Sized { type WriteError = IoError; fn write_all(&mut self, buf: &[u8]) -> Result<(), Self::WriteError> { diff --git a/artiq/firmware/libproto/mgmt_proto.rs b/artiq/firmware/libproto/mgmt_proto.rs index 569a24104..6e343c083 100644 --- a/artiq/firmware/libproto/mgmt_proto.rs +++ b/artiq/firmware/libproto/mgmt_proto.rs @@ -41,9 +41,9 @@ pub enum Reply<'a> { } impl Request { - pub fn read_from(reader: &mut T) -> Result { + pub fn read_from(reader: &mut T) -> Result { #[cfg(feature = "log")] - fn read_log_level_filter(reader: &mut T) -> + fn read_log_level_filter(reader: &mut T) -> Result { Ok(match reader.read_u8()? { 0 => log::LevelFilter::Off, @@ -80,7 +80,7 @@ impl Request { } impl<'a> Reply<'a> { - pub fn write_to(&self, writer: &mut T) -> Result<(), T::WriteError> { + pub fn write_to(&self, writer: &mut T) -> Result<(), T::WriteError> { match *self { Reply::Success => { writer.write_u8(1)?; diff --git a/artiq/firmware/libproto/moninj_proto.rs b/artiq/firmware/libproto/moninj_proto.rs index 32a833a97..b440fab14 100644 --- a/artiq/firmware/libproto/moninj_proto.rs +++ b/artiq/firmware/libproto/moninj_proto.rs @@ -15,7 +15,7 @@ pub enum DeviceMessage { } impl HostMessage { - pub fn read_from(reader: &mut T) -> Result { + pub fn read_from(reader: &mut T) -> Result { Ok(match reader.read_u8()? { 0 => HostMessage::Monitor { enable: if reader.read_u8()? == 0 { false } else { true }, @@ -37,7 +37,7 @@ impl HostMessage { } impl DeviceMessage { - pub fn write_to(&self, writer: &mut T) -> Result<(), T::WriteError> { + pub fn write_to(&self, writer: &mut T) -> Result<(), T::WriteError> { match *self { DeviceMessage::MonitorStatus { channel, probe, value } => { writer.write_u8(0)?; diff --git a/artiq/firmware/libproto/session_proto.rs b/artiq/firmware/libproto/session_proto.rs index c852f3918..8dd5dec9f 100644 --- a/artiq/firmware/libproto/session_proto.rs +++ b/artiq/firmware/libproto/session_proto.rs @@ -1,9 +1,10 @@ -use std::io::{self, Read, Write}; -use std::vec::Vec; -use std::string::String; -use {ReadExt, WriteExt}; +use alloc::vec::Vec; +use alloc::string::String; -fn read_sync(reader: &mut Read) -> io::Result<()> { +use io::{Read, Write, Error, Result}; +use io::proto::{ProtoRead, ProtoWrite}; + +fn read_sync(reader: &mut T) -> Result<(), T::ReadError> { let mut sync = [0; 4]; for i in 0.. { sync[i % 4] = reader.read_u8()?; @@ -12,7 +13,7 @@ fn read_sync(reader: &mut Read) -> io::Result<()> { Ok(()) } -fn write_sync(writer: &mut Write) -> io::Result<()> { +fn write_sync(writer: &mut T) -> Result<(), T::WriteError> { writer.write_all(&[0x5a; 4]) } @@ -42,7 +43,7 @@ pub enum Request { } impl Request { - pub fn read_from(reader: &mut Read) -> io::Result { + pub fn read_from(reader: &mut T) -> Result { read_sync(reader)?; Ok(match reader.read_u8()? { 3 => Request::SystemInfo, @@ -74,7 +75,7 @@ impl Request { 12 => Request::FlashRemove { key: reader.read_string()? }, - _ => return Err(io::Error::new(io::ErrorKind::InvalidData, "unknown request type")) + _ => return Err(Error::Unrecognized) }) } } @@ -115,7 +116,7 @@ pub enum Reply<'a> { } impl<'a> Reply<'a> { - pub fn write_to(&self, writer: &mut Write) -> io::Result<()> { + pub fn write_to(&self, writer: &mut T) -> Result<(), T::WriteError> { write_sync(writer)?; match *self { Reply::SystemInfo { ident, finished_cleanly } => { diff --git a/artiq/firmware/runtime/session.rs b/artiq/firmware/runtime/session.rs index 8b42329ee..2d617ef78 100644 --- a/artiq/firmware/runtime/session.rs +++ b/artiq/firmware/runtime/session.rs @@ -127,7 +127,7 @@ fn host_read(stream: &mut TcpStream) -> io::Result { fn host_write(stream: &mut Write, reply: host::Reply) -> io::Result<()> { debug!("comm->host {:?}", reply); - reply.write_to(stream) + Ok(reply.write_to(stream)?) } pub fn kern_send(io: &Io, request: &kern::Message) -> io::Result<()> {