use std::io::{self, Read, Seek, SeekFrom, Write};
use std::num::NonZeroUsize;
use super::bounded::{BoundedStorageProvider, BoundedStorageReader, BoundedStorageWriter};
use super::{StorageProvider, StorageReader, StorageWriter};
#[derive(Clone, Debug)]
pub struct AdaptiveStorageProvider<F, V>
where
F: StorageProvider,
V: StorageProvider,
{
buffer_size: NonZeroUsize,
fixed_storage: F,
variable_storage: V,
}
impl<F, V> AdaptiveStorageProvider<F, V>
where
F: StorageProvider,
V: StorageProvider,
{
pub fn with_fixed_and_variable(
fixed_storage: F,
variable_storage: V,
buffer_size: NonZeroUsize,
) -> Self {
Self {
buffer_size,
fixed_storage,
variable_storage,
}
}
}
impl<T> AdaptiveStorageProvider<T, T>
where
T: StorageProvider,
{
pub fn new(provider: T, buffer_size: NonZeroUsize) -> Self
where
T: Clone,
{
Self::with_fixed_and_variable(provider.clone(), provider, buffer_size)
}
}
impl<F, V> StorageProvider for AdaptiveStorageProvider<F, V>
where
F: StorageProvider,
V: StorageProvider,
{
type Reader = AdaptiveStorageReader<F::Reader, V::Reader>;
type Writer = AdaptiveStorageWriter<F::Writer, V::Writer>;
fn into_reader_writer(
self,
content_length: Option<u64>,
) -> io::Result<(Self::Reader, Self::Writer)> {
match content_length {
None => {
let provider = BoundedStorageProvider::new(self.fixed_storage, self.buffer_size);
let (reader, writer) = provider.into_reader_writer(None)?;
Ok((Self::Reader::Bounded(reader), Self::Writer::Bounded(writer)))
}
Some(length) => {
if u64::try_from(self.buffer_size.get()).is_ok_and(|buffer| length <= buffer) {
let (reader, writer) = self.fixed_storage.into_reader_writer(Some(length))?;
Ok((Self::Reader::Fixed(reader), Self::Writer::Fixed(writer)))
} else {
let (reader, writer) =
self.variable_storage.into_reader_writer(Some(length))?;
Ok((
Self::Reader::Variable(reader),
Self::Writer::Variable(writer),
))
}
}
}
}
}
#[derive(Debug)]
pub enum AdaptiveStorageReader<F, V>
where
F: StorageReader,
V: StorageReader,
{
Bounded(BoundedStorageReader<F>),
Fixed(F),
Variable(V),
}
impl<F, V> Read for AdaptiveStorageReader<F, V>
where
F: StorageReader,
V: StorageReader,
{
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
match self {
Self::Bounded(r) => r.read(buf),
Self::Fixed(r) => r.read(buf),
Self::Variable(r) => r.read(buf),
}
}
}
impl<F, V> Seek for AdaptiveStorageReader<F, V>
where
F: StorageReader,
V: StorageReader,
{
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
match self {
Self::Bounded(r) => r.seek(pos),
Self::Fixed(r) => r.seek(pos),
Self::Variable(r) => r.seek(pos),
}
}
}
#[derive(Debug)]
pub enum AdaptiveStorageWriter<F, V>
where
F: StorageWriter,
V: StorageWriter,
{
Bounded(BoundedStorageWriter<F>),
Fixed(F),
Variable(V),
}
impl<F, V> Write for AdaptiveStorageWriter<F, V>
where
F: StorageWriter,
V: StorageWriter,
{
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
match self {
Self::Bounded(w) => w.write(buf),
Self::Fixed(w) => w.write(buf),
Self::Variable(w) => w.write(buf),
}
}
fn flush(&mut self) -> io::Result<()> {
match self {
Self::Bounded(w) => w.flush(),
Self::Fixed(w) => w.flush(),
Self::Variable(w) => w.flush(),
}
}
}
impl<F, V> Seek for AdaptiveStorageWriter<F, V>
where
F: StorageWriter,
V: StorageWriter,
{
fn seek(&mut self, pos: SeekFrom) -> io::Result<u64> {
match self {
Self::Bounded(w) => w.seek(pos),
Self::Fixed(w) => w.seek(pos),
Self::Variable(w) => w.seek(pos),
}
}
}