use {
alloc::string::String,
core::{
cell::RefCell,
fmt::{self, Display, Formatter},
},
fehler::{throw, throws},
market::{
Agent, Consumer, ConsumptionFlaws, EmptyStock, Failure, Fault, FullStock, Producer,
ProductionFlaws, Recall,
},
std::io::{Read, Write},
};
pub trait ReadNow: Read {}
pub trait WriteNow: Write {}
#[derive(Debug)]
pub struct ReadDefect(std::io::Error);
impl Display for ReadDefect {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl std::error::Error for ReadDefect {}
impl From<std::io::Error> for ReadDefect {
fn from(error: std::io::Error) -> Self {
Self(error)
}
}
#[derive(Debug)]
pub struct WriteDefect(std::io::Error);
impl Display for WriteDefect {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "{}", self.0)
}
}
impl std::error::Error for WriteDefect {}
impl From<std::io::Error> for WriteDefect {
fn from(error: std::io::Error) -> Self {
Self(error)
}
}
#[derive(Debug)]
pub struct Reader<R> {
name: String,
reader: RefCell<R>,
}
impl<R> Reader<R> {
pub const fn new(reader: R, name: String) -> Self {
Self {
reader: RefCell::new(reader),
name,
}
}
}
impl<R> Agent for Reader<R> {
type Good = u8;
}
impl<R: ReadNow> Consumer for Reader<R> {
type Flaws = ConsumptionFlaws<ReadDefect>;
#[throws(Failure<Self::Flaws>)]
fn consume(&self) -> Self::Good {
let mut buffer = [0; 1];
if self
.reader
.borrow_mut()
.read(&mut buffer)
.map_err(|error| self.failure(Fault::Defect(error.into())))?
== 0
{
throw!(self.failure(Fault::Insufficiency(EmptyStock::default())));
} else {
buffer[0]
}
}
}
impl<R> Display for Reader<R> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Reader of `{}`", self.name)
}
}
#[derive(Debug)]
pub struct Writer<W> {
name: String,
writer: RefCell<W>,
}
impl<W> Writer<W> {
pub const fn new(writer: W, name: String) -> Self {
Self {
writer: RefCell::new(writer),
name,
}
}
}
impl<W> Agent for Writer<W> {
type Good = u8;
}
impl<W> Display for Writer<W> {
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
write!(f, "Writer of `{}`", self.name)
}
}
impl<W: WriteNow> Producer for Writer<W> {
type Flaws = ProductionFlaws<WriteDefect>;
#[throws(Recall<Self::Flaws, Self::Good>)]
fn produce(&self, good: Self::Good) {
let bytes_written = self
.writer
.borrow_mut()
.write(&[good])
.map_err(|error| self.recall(Fault::Defect(error.into()), good))?;
if bytes_written == 0 {
throw!(self.recall(Fault::Insufficiency(FullStock::default()), good));
}
}
}