use crate::prelude::*;
+// ---------- common ----------
+
const CHUNK_MAX: u16 = 65534;
const CHUNK_ERR: u16 = 65535;
const CHUNK_DEF: u16 = 8192;
type BO = BigEndian;
+#[derive(Debug,Copy,Clone,Error)]
+#[error("error occurred at peer, during construction of frame data")]
+pub struct SenderError;
+
#[derive(Debug)]
pub struct Fuse<RW>(Result<RW, Broken>);
-#[derive(Debug,Copy,Clone)]
-enum ReaderState {
- Idle,
- FrameStart,
- InFrame(usize),
-}
-use ReaderState::*;
-impl ReaderState {
- fn idle(&self) -> bool {
- matches_doesnot!(self,
- = Idle,
- ! FrameStart | InFrame(_))
- }
+/// An error saved by `Fuse` so it can be repeatedly returned.
+#[derive(Clone,Error,Debug)]
+pub struct Broken {
+ msg: String,
+ kind: io::ErrorKind,
}
+// ---------- read ----------
+
#[derive(Debug)]
pub struct FrameReader<R: Read> {
inner: Fuse<R>,
fr: Result<&'r mut FrameReader<R>, Option<SenderError>>,
}
+#[derive(Debug,Copy,Clone)]
+enum ReaderState {
+ Idle,
+ FrameStart,
+ InFrame(usize),
+}
+use ReaderState::*;
+
+// ---------- write ----------
+
#[derive(Debug)]
pub struct FrameWriter<W:Write> {
inner: Fuse<W>,
struct WriteFrameRaw<'w,W:Write> {
fw: &'w mut FrameWriter<W>,
}
+
#[derive(Debug)]
pub struct WriteFrame<'w,W:Write> {
buf: BufWriter<WriteFrameRaw<'w,W>>,
}
-#[derive(Debug,Copy,Clone,Error)]
-#[error("error occurred at peer, during construction of frame data")]
-pub struct SenderError;
+// ==================== implementation -====================
-#[derive(Clone,Error,Debug)]
-pub struct Broken {
- msg: String,
- kind: io::ErrorKind,
+impl From<SenderError> for io::Error {
+ fn from(se: SenderError) -> io::Error {
+ io::Error::new(io::ErrorKind::Other, se)
+ }
+}
+
+// ---------- fuse ----------
+
+impl Display for Broken {
+ fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
+ f.write_str(&self.msg)
+ }
+}
+impl From<Broken> for io::Error {
+ fn from(broken: Broken) -> io::Error {
+ io::Error::new(broken.kind, broken)
+ }
}
impl<RW> Fuse<RW> {
}
}
-impl From<Broken> for io::Error {
- fn from(broken: Broken) -> io::Error {
- io::Error::new(broken.kind, broken)
- }
-}
-impl From<SenderError> for io::Error {
- fn from(se: SenderError) -> io::Error {
- io::Error::new(io::ErrorKind::Other, se)
- }
-}
+// ---------- read ----------
-impl Display for Broken {
- fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
- f.write_str(&self.msg)
+impl ReaderState {
+ fn idle(&self) -> bool {
+ matches_doesnot!(self,
+ = Idle,
+ ! FrameStart | InFrame(_))
}
}
}
}
+// ---------- write ----------
+
impl<W:Write> FrameWriter<W> {
pub fn new(w: W) -> FrameWriter<W> {
FrameWriter { inner: Fuse(Ok(w)), in_frame: None }
#[throws(io::Error)]
pub fn finish(self) { self.finish_with(Ok(()))? }
}
-impl<'w,W:Write> WriteFrameRaw<'w,W> {
-}
impl<'w,W:Write> Drop for WriteFrameRaw<'w,W> {
fn drop(&mut self) {
self.fw.tidy()
fn flush(&mut self) { self.buf.flush()? }
}
+// ==================== tests ====================
+
#[test]
fn write_test(){
+
+ // pretty printing the test message buffer
#[derive(Clone,Default)]
struct Framed {
buf: Vec<u8>,
}
}
+ // make the test message buffer
let mut msg = Framed::default();
let mut wr = FrameWriter::new(&mut msg.buf);
{
})().unwrap();
dbgc!(&msg);
+ // utility functions for helping with test reads
fn expect_boom<R:Read>(rd: &mut FrameReader<R>) {
let mut buf = [0u8;10];
let mut frame = rd.new_frame().unwrap();
assert!(r.into_inner().unwrap().is::<SenderError>());
assert_eq!(before, b"boom");
}
- fn expect_good<R:Read>(rd: &mut FrameReader<R>, expected: &[u8]) {
- let mut buf = vec![];
- let mut frame = rd.new_frame().unwrap();
- frame.read_to_end(&mut buf).unwrap();
- assert_eq!(&*buf ,expected);
- dbgc!(str::from_utf8(&buf).unwrap());
- }
- fn expect_eof<R:Read>(rd: &mut FrameReader<R>) {
- let mut buf = [0u8;10];
- let mut frame = rd.new_frame().unwrap();
- let r = frame.read(&mut buf).unwrap(); dbgc!(&r); assert_eq!(r, 0);
- let r = frame.read(&mut buf).unwrap(); dbgc!(&r); assert_eq!(r, 0);
- }
+ // a very simple test as far as the first boom
let mut rd = FrameReader::new(&*msg.buf);
let mut buf = [0u8;10];
{
}
expect_boom(&mut rd);
+ // check how dropping a reading frame works
let mut rd = FrameReader::new(&*msg.buf);
{
let mut _frame = rd.new_frame().unwrap();
}
expect_boom(&mut rd);
+ // utilitiesfor reading the whole input, collecting into vecs
+ fn expect_good<R:Read>(rd: &mut FrameReader<R>, expected: &[u8]) {
+ let mut buf = vec![];
+ let mut frame = rd.new_frame().unwrap();
+ frame.read_to_end(&mut buf).unwrap();
+ assert_eq!(&*buf ,expected);
+ dbgc!(str::from_utf8(&buf).unwrap());
+ }
+ fn expect_eof<R:Read>(rd: &mut FrameReader<R>) {
+ let mut buf = [0u8;10];
+ let mut frame = rd.new_frame().unwrap();
+ let r = frame.read(&mut buf).unwrap(); dbgc!(&r); assert_eq!(r, 0);
+ let r = frame.read(&mut buf).unwrap(); dbgc!(&r); assert_eq!(r, 0);
+ }
let read_all = |input: &mut dyn Read| {
let mut rd = FrameReader::new_unbuf(input);
expect_good(&mut rd, b"hello");
};
read_all(&mut &*msg.buf);
+ // try lumpy reads (ie, short reads) at every plausible boundary size
+ // this approach is not very principled but ought to test every boundary
#[cfg(not(miri))]
for lumpsize in 1..=msg.buf.len() {
#[derive(Debug)]
read_all(&mut lr);
}
+ // Unexpected EOF mid-chunk-header
{
let mut rd = FrameReader::new(&[0x55][..]);
let mut frame = rd.new_frame().unwrap();
r.into_inner().map(|i| panic!("unexpected {:?}", &i));
}
+ // Unexpected EOF mid-data
{
let mut rd = FrameReader::new(&msg.buf[0..3]);
let mut frame = rd.new_frame().unwrap();
r.into_inner().map(|i| panic!("unexpected {:?}", &i));
}
+ // Unexpected EOF after nonempty chunk
{
let mut rd = FrameReader::new(&msg.buf[0..7]);
let mut frame = rd.new_frame().unwrap();