use core::fmt;
use std::{
collections::TryReserveError,
future::poll_fn,
io::{
Error,
ErrorKind,
Result,
},
pin::Pin,
task::{
Context,
Poll,
},
};
use qubit_io::{
AsyncBufferedInput,
AsyncInput,
Buffer,
UncheckedSlice,
};
use crate::{
CapacityError,
TranscodeProgress,
Transcoder,
};
use super::{
async_transcode_decode_step::AsyncTranscodeDecodeStep,
transcode_progress_validation::validate_decode_progress,
};
#[must_use]
pub struct AsyncTranscodeDecodeInput<I>
where
I: AsyncInput,
I::Item: Copy + Default,
{
input: AsyncBufferedInput<I>,
}
impl<I> AsyncTranscodeDecodeInput<I>
where
I: AsyncInput,
I::Item: Copy + Default,
{
pub fn new(inner: I) -> Self {
Self {
input: AsyncBufferedInput::new(inner),
}
}
pub fn with_capacity(inner: I, capacity: usize) -> Self {
Self {
input: AsyncBufferedInput::with_capacity(inner, capacity),
}
}
pub fn try_with_capacity(
inner: I,
capacity: usize,
) -> std::result::Result<Self, TryReserveError> {
Ok(Self {
input: AsyncBufferedInput::try_with_capacity(inner, capacity)?,
})
}
#[must_use]
pub const fn inner(&self) -> &I {
self.input.inner()
}
#[must_use]
pub fn inner_mut(&mut self) -> &mut I {
self.input.inner_mut()
}
#[must_use]
pub const fn unread_len(&self) -> usize {
self.input.unread_len()
}
#[must_use]
pub fn unread(&self) -> &[I::Item] {
self.input.unread()
}
#[must_use]
pub fn capacity(&self) -> usize {
self.input.capacity()
}
pub fn consume(&mut self, count: usize) {
assert!(
count <= self.unread_len(),
"cannot consume beyond buffered input",
);
unsafe {
self.input.consume(count);
}
}
pub unsafe fn copy_unread_to(
&self,
output: &mut [I::Item],
output_index: usize,
count: usize,
) {
unsafe {
self.input.copy_unread_to(output, output_index, count);
}
}
#[must_use = "the returned input and unread buffer must be handled"]
pub fn into_parts(self) -> (I, Buffer<I::Item>) {
self.input.into_parts()
}
pub fn reset<D, M, Value>(
&self,
decoder: &mut D,
map_error: &mut M,
output: &mut [Value],
output_index: usize,
count: usize,
) -> Result<usize>
where
D: Transcoder<Input = I::Item, Output = Value>,
M: FnMut(D::Error) -> Error,
{
let required = decoder
.max_reset_output_len()
.map_err(capacity_to_io_error)?;
let output_end = UncheckedSlice::checked_range_end(
output.len(),
output_index,
count,
"reset output range exceeds destination buffer",
)?;
if count < required {
return Err(Error::new(
ErrorKind::InvalidData,
"insufficient output for decoder reset bound",
));
}
let output = &mut output[..output_end];
let written = decoder
.reset(output, output_index)
.map_err(&mut *map_error)?;
assert!(written <= required, "reset wrote beyond its bound");
Ok(written)
}
pub fn finish<D, M, Value>(
&self,
decoder: &mut D,
map_error: &mut M,
output: &mut [Value],
output_index: usize,
count: usize,
) -> Result<usize>
where
D: Transcoder<Input = I::Item, Output = Value>,
M: FnMut(D::Error) -> Error,
{
let required = decoder
.max_finish_output_len()
.map_err(capacity_to_io_error)?;
let output_end = UncheckedSlice::checked_range_end(
output.len(),
output_index,
count,
"finish output range exceeds destination buffer",
)?;
if count < required {
return Err(Error::new(
ErrorKind::InvalidData,
"insufficient output for decoder finish bound",
));
}
let output = &mut output[..output_end];
let written = decoder
.finish(output, output_index)
.map_err(&mut *map_error)?;
assert!(written <= required, "finish wrote beyond its bound");
Ok(written)
}
}
impl<I> AsyncTranscodeDecodeInput<I>
where
I: AsyncInput + Unpin,
I::Item: Copy + Default + Unpin,
{
pub async fn fill_more_async(&mut self) -> Result<bool> {
self.input.fill_more_async().await
}
pub async fn fill_until_async(&mut self, count: usize) -> Result<bool> {
if count > self.input.capacity() {
self.input
.try_reserve_capacity(count)
.map_err(allocation_to_io_error)?;
}
self.input.fill_until_async(count).await
}
pub fn poll_transcode<D, M, Value>(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
decoder: &mut D,
map_error: &mut M,
output: &mut [Value],
output_index: usize,
count: usize,
) -> Poll<Result<AsyncTranscodeDecodeStep>>
where
D: Transcoder<Input = I::Item, Output = Value>,
M: FnMut(D::Error) -> Error,
{
let output_end = UncheckedSlice::checked_range_end(
output.len(),
output_index,
count,
"decoded output range exceeds destination buffer",
)?;
if count == 0 {
return Poll::Ready(Ok(AsyncTranscodeDecodeStep::Progress(
TranscodeProgress::complete(0, 0),
)));
}
let output = &mut output[..output_end];
if self.as_ref().get_ref().unread_len() == 0 {
let this = self.as_mut().get_mut();
match Pin::new(&mut this.input).poll_fill_more(cx) {
Poll::Ready(Ok(true)) => {}
Poll::Ready(Ok(false)) => {
return Poll::Ready(Ok(
AsyncTranscodeDecodeStep::EndOfInput,
));
}
Poll::Ready(Err(error)) => return Poll::Ready(Err(error)),
Poll::Pending => return Poll::Pending,
}
}
let this = self.as_mut().get_mut();
let available_input = this.unread_len();
let progress = decoder
.transcode(this.unread(), 0, output, output_index)
.map_err(&mut *map_error)
.and_then(|progress| {
validate_decode_progress(
progress,
0,
available_input,
output_index,
count,
)
});
let progress = match progress {
Ok(progress) => progress,
Err(error) => return Poll::Ready(Err(error)),
};
this.consume(progress.read());
Poll::Ready(Ok(AsyncTranscodeDecodeStep::Progress(progress)))
}
pub fn transcode_eof_step<D, M, Value>(
&mut self,
decoder: &mut D,
map_error: &mut M,
output: &mut [Value],
output_index: usize,
count: usize,
) -> Result<TranscodeProgress>
where
D: Transcoder<Input = I::Item, Output = Value>,
M: FnMut(D::Error) -> Error,
{
let output_end = UncheckedSlice::checked_range_end(
output.len(),
output_index,
count,
"decoded EOF output range exceeds destination buffer",
)?;
if count == 0 {
return Ok(TranscodeProgress::complete(0, 0));
}
if self.unread_len() == 0 {
return Ok(TranscodeProgress::complete(0, 0));
}
let available_input = self.unread_len();
let progress = decoder
.transcode_eof(
self.unread(),
0,
&mut output[..output_end],
output_index,
)
.map_err(&mut *map_error)
.and_then(|progress| {
validate_decode_progress(
progress,
0,
available_input,
output_index,
count,
)
})?;
self.consume(progress.read());
Ok(progress)
}
pub async fn transcode_async<D, M, Value>(
&mut self,
decoder: &mut D,
map_error: &mut M,
output: &mut [Value],
output_index: usize,
count: usize,
) -> Result<AsyncTranscodeDecodeStep>
where
D: Transcoder<Input = I::Item, Output = Value>,
M: FnMut(D::Error) -> Error,
{
poll_fn(|cx| {
Pin::new(&mut *self).poll_transcode(
cx,
decoder,
map_error,
output,
output_index,
count,
)
})
.await
}
}
impl<I> AsyncInput for AsyncTranscodeDecodeInput<I>
where
I: AsyncInput,
I::Item: Copy + Default,
{
type Item = I::Item;
fn is_buffered(&self) -> bool {
true
}
unsafe fn poll_read_unchecked(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
output: &mut [Self::Item],
index: usize,
count: usize,
) -> Poll<Result<usize>> {
let input = unsafe {
Pin::new_unchecked(&mut self.as_mut().get_unchecked_mut().input)
};
unsafe { input.poll_read_unchecked(cx, output, index, count) }
}
}
impl<I> fmt::Debug for AsyncTranscodeDecodeInput<I>
where
I: AsyncInput,
I::Item: Copy + Default,
AsyncBufferedInput<I>: fmt::Debug,
{
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("AsyncTranscodeDecodeInput")
.field("input", &self.input)
.finish()
}
}
fn allocation_to_io_error(error: TryReserveError) -> Error {
Error::new(ErrorKind::OutOfMemory, error)
}
fn capacity_to_io_error(error: CapacityError) -> Error {
Error::new(ErrorKind::InvalidData, error)
}