use std::io::BufWriter;
use crate::save::{Error, Handle, Result, Value};
macro_rules! delegate_write_and_seek {
($field:ident, $T:ty) => {
impl std::io::Write for $T {
fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
self.$field.write(buf)
}
fn flush(&mut self) -> std::io::Result<()> {
self.$field.flush()
}
fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result<usize> {
self.$field.write_vectored(bufs)
}
fn write_all(&mut self, buf: &[u8]) -> std::io::Result<()> {
self.$field.write_all(buf)
}
fn write_fmt(&mut self, args: std::fmt::Arguments<'_>) -> std::io::Result<()> {
self.$field.write_fmt(args)
}
}
impl std::io::Seek for $T {
fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result<u64> {
self.$field.seek(pos)
}
fn rewind(&mut self) -> std::io::Result<()> {
self.$field.rewind()
}
fn stream_position(&mut self) -> std::io::Result<u64> {
self.$field.stream_position()
}
fn seek_relative(&mut self, offset: i64) -> std::io::Result<()> {
self.$field.seek_relative(offset)
}
}
};
}
pub(crate) use delegate_write_and_seek;
pub(crate) trait SaveContext {
type Output;
fn write(&self, key: Option<&str>) -> Result<Writer<'_>>;
fn finish(self, value: Value<'_>) -> Result<Self::Output>;
}
pub(super) trait GetWrite {
fn write(&self, key: Option<&str>) -> Result<Writer<'_>>;
}
impl<T> GetWrite for T
where
T: SaveContext,
{
fn write(&self, key: Option<&str>) -> Result<Writer<'_>> {
<T as SaveContext>::write(self, key)
}
}
#[derive(Clone)]
pub struct Context<'a> {
inner: &'a dyn GetWrite,
}
impl<'a> Context<'a> {
pub(super) fn new(inner: &'a dyn GetWrite) -> Self {
Self { inner }
}
pub fn write(&self, key: Option<&str>) -> Result<Writer<'_>> {
self.inner.write(key)
}
}
pub(crate) trait WriterInner: std::io::Write + std::io::Seek + std::fmt::Debug {
fn finish(self: Box<Self>, name: String) -> Result<Handle>;
}
#[derive(Debug)]
pub struct Writer<'a> {
inner: BufWriter<Box<dyn WriterInner + 'a>>,
name: String,
}
impl<'a> Writer<'a> {
pub(crate) fn new<T>(inner: T, name: String) -> Self
where
T: WriterInner + 'a,
{
Self {
inner: BufWriter::new(Box::new(inner)),
name,
}
}
pub fn finish(self) -> Result<Handle> {
let inner = self
.inner
.into_inner()
.map_err(|err| Error::new(err.into_error()))?;
inner.finish(self.name)
}
}
delegate_write_and_seek!(inner, Writer<'_>);