use core::fmt;
use std::{
collections::TryReserveError,
future::poll_fn,
io::{
Error,
ErrorKind,
Result,
},
pin::Pin,
task::{
Context,
Poll,
},
};
use qubit_io::{
AsyncBufferedOutput,
AsyncOutput,
Buffer,
};
use qubit_utils::{
SliceRange,
allocation_error,
};
use crate::{
CapacityError,
TranscodeEncoder,
TranscodeProgress,
TranscodeStatus,
Transcoder,
};
use super::transcode_progress_validation::validate_encode_progress;
pub struct AsyncTranscodeEncodeOutput<O>
where
O: AsyncOutput,
O::Item: Clone + Default,
{
output: AsyncBufferedOutput<O>,
required_spare: usize,
}
impl<O> AsyncTranscodeEncodeOutput<O>
where
O: AsyncOutput,
O::Item: Clone + Default,
{
#[must_use]
pub fn new(inner: O) -> Self {
Self {
output: AsyncBufferedOutput::new(inner),
required_spare: 1,
}
}
#[must_use]
pub fn with_capacity(inner: O, capacity: usize) -> Self {
Self {
output: AsyncBufferedOutput::with_capacity(inner, capacity),
required_spare: 1,
}
}
pub fn try_with_capacity(
inner: O,
capacity: usize,
) -> std::result::Result<Self, TryReserveError> {
Ok(Self {
output: AsyncBufferedOutput::try_with_capacity(inner, capacity)?,
required_spare: 1,
})
}
#[must_use]
pub fn capacity(&self) -> usize {
self.output.capacity()
}
#[must_use]
pub const fn inner(&self) -> &O {
self.output.inner()
}
pub fn inner_mut(&mut self) -> &mut O {
self.output.inner_mut()
}
#[must_use]
pub const fn pending_len(&self) -> usize {
self.output.pending_len()
}
#[must_use = "the returned output and pending buffer must be handled"]
pub fn into_parts(self) -> (O, Buffer<O::Item>) {
self.output.into_parts()
}
}
impl<O> AsyncTranscodeEncodeOutput<O>
where
O: AsyncOutput + Unpin,
O::Item: Clone + Default + Unpin,
{
pub async fn flush_async(&mut self) -> Result<()> {
self.output.flush_async().await
}
pub async fn drain_async(&mut self) -> Result<()> {
let capacity = self.output.capacity();
self.output.ensure_spare_capacity_async(capacity).await
}
pub async fn reset_async<E, M, Value>(
&mut self,
encoder: &mut E,
map_error: &mut M,
) -> Result<()>
where
E: Transcoder<Input = Value, Output = O::Item>,
M: FnMut(E::Error) -> Error,
{
let required = encoder
.max_reset_output_len()
.map_err(capacity_error_to_invalid_data)?;
self.ensure_spare_capacity_async(required).await?;
let (units, output_index, available) =
self.output.spare_raw_parts_mut();
debug_assert!(available >= required);
let written = encoder
.reset(units, output_index)
.map_err(&mut *map_error)?;
assert!(written <= required, "reset wrote beyond its bound");
unsafe {
self.output.advance(written);
}
Ok(())
}
pub fn poll_transcode<E, M, Value>(
mut self: Pin<&mut Self>,
cx: &mut Context<'_>,
encoder: &mut E,
map_error: &mut M,
input: &[Value],
input_index: usize,
count: usize,
) -> Poll<Result<TranscodeProgress>>
where
E: TranscodeEncoder<Input = Value, Output = O::Item>,
M: FnMut(E::Error) -> Error,
{
let input_end = SliceRange::checked_range_end(
input.len(),
input_index,
count,
"encode input range exceeds source buffer",
)?;
if count == 0 {
return Poll::Ready(Ok(TranscodeProgress::complete(0, 0)));
}
let input = &input[..input_end];
let this = self.as_mut().get_mut();
let per_value = match encoder.max_transcode_output_len(1) {
Ok(required) => required.max(1),
Err(error) => {
return Poll::Ready(Err(capacity_error_to_invalid_data(error)));
}
};
let required_spare = this.required_spare.max(per_value);
let required_capacity =
this.output.pending_len().saturating_add(required_spare);
if let Err(error) = this.output.try_reserve_capacity(required_capacity)
{
return Poll::Ready(Err(allocation_error(error)));
}
match Pin::new(&mut this.output)
.poll_ensure_spare_capacity(cx, required_spare)
{
Poll::Ready(Ok(())) => {}
Poll::Ready(Err(error)) => return Poll::Ready(Err(error)),
Poll::Pending => return Poll::Pending,
}
let (units, output_index, available_output) =
this.output.spare_raw_parts_mut();
let progress = encoder
.transcode(input, input_index, units, output_index)
.map_err(&mut *map_error)
.and_then(|progress| {
validate_encode_progress(
progress,
input_index,
count,
output_index,
available_output,
)
});
let progress = match progress {
Ok(progress) => progress,
Err(error) => return Poll::Ready(Err(error)),
};
unsafe {
this.output.advance(progress.written());
}
this.required_spare =
if let TranscodeStatus::NeedOutput { required, .. } =
progress.status()
{
required.get()
} else {
debug_assert!(progress.is_complete());
1
};
Poll::Ready(Ok(progress))
}
pub async fn transcode_async<E, M, Value>(
&mut self,
encoder: &mut E,
map_error: &mut M,
input: &[Value],
input_index: usize,
count: usize,
) -> Result<TranscodeProgress>
where
E: TranscodeEncoder<Input = Value, Output = O::Item>,
M: FnMut(E::Error) -> Error,
{
poll_fn(|cx| {
Pin::new(&mut *self).poll_transcode(
cx,
encoder,
map_error,
input,
input_index,
count,
)
})
.await
}
pub async fn finish_async<E, M, Value>(
&mut self,
encoder: &mut E,
map_error: &mut M,
) -> Result<()>
where
E: Transcoder<Input = Value, Output = O::Item>,
M: FnMut(E::Error) -> Error,
{
let required = encoder
.max_finish_output_len()
.map_err(capacity_error_to_invalid_data)?;
self.ensure_spare_capacity_async(required).await?;
let (units, output_index, available) =
self.output.spare_raw_parts_mut();
debug_assert!(available >= required);
let written = encoder
.finish(units, output_index)
.map_err(&mut *map_error)?;
assert!(written <= required, "finish wrote beyond its bound");
unsafe {
self.output.advance(written);
}
Ok(())
}
async fn ensure_spare_capacity_async(
&mut self,
count: usize,
) -> Result<()> {
let required_capacity = self.output.pending_len().saturating_add(count);
self.output
.try_reserve_capacity(required_capacity)
.map_err(allocation_error)?;
self.output.ensure_spare_capacity_async(count).await
}
}
fn capacity_error_to_invalid_data(error: CapacityError) -> Error {
Error::new(ErrorKind::InvalidData, error)
}
impl<O> fmt::Debug for AsyncTranscodeEncodeOutput<O>
where
O: AsyncOutput,
O::Item: Clone + Default,
AsyncBufferedOutput<O>: fmt::Debug,
{
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("AsyncTranscodeEncodeOutput")
.field("output", &self.output)
.finish()
}
}