use log::{debug, trace};
use thiserror::Error;
use crate::io::{StreamIo, StreamOutput};
#[derive(Clone, Debug, Error)]
pub enum WriteStreamError {
#[error("Invalid argument: expected {0}, got {1:?}")]
InvalidArgument(&'static str, StreamIo),
}
#[derive(Clone, Debug)]
pub enum WriteStreamResult {
Ok(StreamOutput),
Io(StreamIo),
Eof,
Err(WriteStreamError),
}
#[derive(Debug, Default)]
pub struct WriteStream {
bytes: Vec<u8>,
}
impl WriteStream {
pub fn new(bytes: Vec<u8>) -> Self {
trace!("init coroutine for writing {} bytes", bytes.len());
Self { bytes }
}
pub fn resume(&mut self, arg: Option<StreamIo>) -> WriteStreamResult {
let Some(arg) = arg else {
let bytes = self.bytes.drain(..).collect();
trace!("wants I/O to write bytes");
return WriteStreamResult::Io(StreamIo::Write(Err(bytes)));
};
trace!("resume after writing bytes");
let StreamIo::Write(io) = arg else {
return WriteStreamResult::Err(WriteStreamError::InvalidArgument("write output", arg));
};
let output = match io {
Ok(output) => output,
Err(bytes) => return WriteStreamResult::Io(StreamIo::Write(Err(bytes))),
};
match output.bytes_count {
0 => WriteStreamResult::Eof,
n => {
debug!("wrote {n} bytes");
WriteStreamResult::Ok(output)
}
}
}
}