qubit_codec/transcode/io/async_transcode_decode_input.rs
1// =============================================================================
2// Copyright (c) 2026 Haixing Hu.
3//
4// SPDX-License-Identifier: Apache-2.0
5//
6// Licensed under the Apache License, Version 2.0.
7// =============================================================================
8//! Buffered asynchronous input driver that decodes units into values.
9
10use core::fmt;
11use std::collections::TryReserveError;
12use std::future::poll_fn;
13use std::io::Error;
14use std::io::ErrorKind;
15use std::io::Result;
16use std::pin::Pin;
17use std::task::Context;
18use std::task::Poll;
19
20use qubit_io::AsyncBufferedInput;
21use qubit_io::AsyncInput;
22use qubit_io::Buffer;
23use qubit_utils::SliceRange;
24use qubit_utils::allocation_error;
25
26use super::async_transcode_decode_step::AsyncTranscodeDecodeStep;
27use super::transcode_progress_validation::validate_decode_progress;
28use crate::CapacityError;
29use crate::TranscodeProgress;
30use crate::Transcoder;
31
32/// Decodes an asynchronous unit stream into values.
33///
34/// The adapter owns unit buffering but not decoder state. Callers supply a
35/// streaming decoder and error mapper for each operation.
36///
37/// # Driving input through EOF
38///
39/// Reset the decoder first and collect the number of values it writes. For
40/// each [`Self::poll_transcode`] progress result, add `written()` to the output
41/// cursor; the bridge has already consumed `read()` from its unread buffer.
42/// When the status is `NeedInput { required }`, call
43/// [`Self::fill_until_async`] with `required.get()`. If it returns `true`, poll
44/// the decoder again. If it returns `false`, EOF has been confirmed and any
45/// short tail remains unread; pass that tail to [`Self::transcode_eof_step`].
46/// Keep stepping on `NeedOutput` with a sufficiently large output range. Once
47/// EOF processing returns `Complete`, call [`Self::finish`] and collect its
48/// returned output count. `EndOfInput` from polling means the unread buffer was
49/// already empty when refill confirmed EOF. In both cases, call
50/// [`Self::transcode_eof_step`] to dispatch the EOF event, including when no
51/// unread units remain.
52///
53/// # Type Parameters
54///
55/// - `I`: Wrapped asynchronous unit input.
56///
57/// # Examples
58///
59/// ```
60/// use qubit_codec::AsyncTranscodeDecodeInput;
61/// use qubit_io::AsyncInput;
62///
63/// # use std::io::Result;
64/// # use std::pin::Pin;
65/// # use std::task::Context;
66/// # use std::task::Poll;
67/// # struct EmptyInput;
68/// # impl AsyncInput for EmptyInput {
69/// # type Item = u8;
70/// # unsafe fn poll_read_unchecked(self: Pin<&mut Self>, _cx: &mut Context<'_>, _output: &mut [u8], _index: usize, _count: usize) -> Poll<Result<usize>> {
71/// # Poll::Ready(Ok(0))
72/// # }
73/// # }
74/// let mut input = AsyncTranscodeDecodeInput::with_capacity(EmptyInput, 8);
75/// assert!(input.capacity() >= 8);
76/// assert_eq!(input.unread_len(), 0);
77/// input.consume(0);
78/// assert!(input.unread().is_empty());
79/// ```
80///
81/// The following driver decodes one complete pair, preserves a one-unit tail,
82/// retries EOF processing after `NeedOutput`, and collects lifecycle output
83/// without an async runtime. The source and decoder are small fixtures; real
84/// applications use their own `AsyncInput` and `Transcoder` implementations.
85///
86/// ```
87/// use qubit_codec::{AsyncTranscodeDecodeInput, AsyncTranscodeDecodeStep, CapacityError, TranscodeDecodeError, TranscodeProgress, Transcoder};
88/// use qubit_io::AsyncInput;
89/// use std::convert::Infallible;
90/// use std::future::{poll_fn, Future};
91/// use std::io;
92/// use std::num::NonZeroUsize;
93/// use std::pin::{pin, Pin};
94/// use std::task::{Context, Poll, Waker};
95///
96/// # #[derive(Debug)] struct ThreeBytes { bytes: [u8; 3], position: usize }
97/// # impl AsyncInput for ThreeBytes {
98/// # type Item = u8;
99/// # unsafe fn poll_read_unchecked(mut self: Pin<&mut Self>, _cx: &mut Context<'_>, output: &mut [u8], index: usize, count: usize) -> Poll<io::Result<usize>> {
100/// # let read = count.min(self.bytes.len() - self.position);
101/// # output[index..index + read].copy_from_slice(&self.bytes[self.position..self.position + read]);
102/// # self.position += read;
103/// # Poll::Ready(Ok(read))
104/// # }
105/// # }
106/// # #[derive(Debug)] struct TailDecoder;
107/// # impl Transcoder for TailDecoder {
108/// # type Input = u8; type Output = u16; type Error = TranscodeDecodeError<Infallible>;
109/// # fn max_transcode_output_len(&self, n: usize) -> Result<usize, CapacityError> { Ok(n) }
110/// # fn max_reset_output_len(&self) -> Result<usize, CapacityError> { Ok(1) }
111/// # fn reset(&mut self, out: &mut [u16], index: usize) -> Result<usize, Self::Error> { out[index] = 0xaaaa; Ok(1) }
112/// # fn transcode(&mut self, input: &[u8], ii: usize, out: &mut [u16], oi: usize) -> Result<TranscodeProgress, Self::Error> {
113/// # let available = input.len() - ii;
114/// # if available < 2 { return Ok(TranscodeProgress::need_input(NonZeroUsize::new(2).unwrap(), 0, 0)); }
115/// # if out.len() == oi { return Ok(TranscodeProgress::need_output(NonZeroUsize::new(1).unwrap(), 0, 0)); }
116/// # out[oi] = u16::from_be_bytes([input[ii], input[ii + 1]]);
117/// # Ok(TranscodeProgress::complete(2, 1))
118/// # }
119/// # fn transcode_eof(&mut self, input: &[u8], ii: usize, out: &mut [u16], oi: usize) -> Result<TranscodeProgress, Self::Error> {
120/// # let available = input.len() - ii;
121/// # if available == 0 { return Ok(TranscodeProgress::complete(0, 0)); }
122/// # if available == 1 {
123/// # if out.len() - oi < 2 { return Ok(TranscodeProgress::need_output(NonZeroUsize::new(2).unwrap(), 0, 0)); }
124/// # out[oi] = u16::from(input[ii]);
125/// # return Ok(TranscodeProgress::complete(1, 1));
126/// # }
127/// # self.transcode(input, ii, out, oi)
128/// # }
129/// # fn max_finish_output_len(&self) -> Result<usize, CapacityError> { Ok(1) }
130/// # fn finish(&mut self, out: &mut [u16], index: usize) -> Result<usize, Self::Error> { out[index] = 0xbbbb; Ok(1) }
131/// # }
132/// # fn block_on<F: Future>(future: F) -> F::Output {
133/// # let mut future = pin!(future); let mut cx = Context::from_waker(Waker::noop());
134/// # loop { if let Poll::Ready(value) = future.as_mut().poll(&mut cx) { return value; } }
135/// # }
136/// let source = ThreeBytes { bytes: [0x12, 0x34, 0x56], position: 0 };
137/// let mut input = AsyncTranscodeDecodeInput::with_capacity(source, 2);
138/// let mut decoder = TailDecoder;
139/// let mut output = [0_u16; 4];
140/// let output_len = output.len();
141/// let mut map_error = |error| io::Error::new(io::ErrorKind::InvalidData, error);
142/// let mut written = input.reset(&mut decoder, &mut map_error, &mut output, 0, output_len)?;
143/// assert_eq!(1, written);
144/// let first = block_on(poll_fn(|cx| Pin::new(&mut input).poll_transcode(cx, &mut decoder, &mut map_error, &mut output, written, output_len - written)))?;
145/// let AsyncTranscodeDecodeStep::Progress(progress) = first else { panic!("expected decoded pair") };
146/// assert_eq!(TranscodeProgress::complete(2, 1), progress);
147/// written += progress.written();
148/// assert_eq!(0x1234, output[1]);
149/// let second = block_on(poll_fn(|cx| Pin::new(&mut input).poll_transcode(cx, &mut decoder, &mut map_error, &mut output, written, output_len - written)))?;
150/// assert!(matches!(second, AsyncTranscodeDecodeStep::Progress(progress) if matches!(progress.status(), qubit_codec::TranscodeStatus::NeedInput { .. })));
151/// assert!(!block_on(input.fill_until_async(2))?);
152/// assert_eq!([0x56], input.unread());
153/// let eof = input.transcode_eof_step(&mut decoder, &mut map_error, &mut output, written, 1)?;
154/// assert_eq!(TranscodeProgress::need_output(NonZeroUsize::new(2).unwrap(), 0, 0), eof);
155/// let eof = input.transcode_eof_step(&mut decoder, &mut map_error, &mut output, written, 2)?;
156/// assert_eq!(TranscodeProgress::complete(1, 1), eof);
157/// written += eof.written();
158/// let finished = input.finish(&mut decoder, &mut map_error, &mut output, written, output_len - written)?;
159/// written += finished;
160/// assert_eq!([0xaaaa, 0x1234, 0x56, 0xbbbb], output);
161/// assert_eq!(4, written);
162/// # Ok::<(), io::Error>(())
163/// ```
164#[must_use]
165pub struct AsyncTranscodeDecodeInput<I>
166where
167 I: AsyncInput,
168 I::Item: Copy + Default,
169{
170 /// Buffered asynchronous unit input.
171 input: AsyncBufferedInput<I>,
172}
173
174impl<I> AsyncTranscodeDecodeInput<I>
175where
176 I: AsyncInput,
177 I::Item: Copy + Default,
178{
179 /// Creates an adapter with the default unit-buffer capacity.
180 ///
181 /// # Parameters
182 ///
183 /// - `inner`: Unit input read by this adapter.
184 ///
185 /// # Returns
186 ///
187 /// Returns a new buffered asynchronous decoder input.
188 pub fn new(inner: I) -> Self {
189 Self {
190 input: AsyncBufferedInput::new(inner),
191 }
192 }
193
194 /// Creates an adapter with an internal unit buffer of at least capacity.
195 ///
196 /// # Parameters
197 ///
198 /// - `inner`: Unit input read by this adapter.
199 /// - `capacity`: Requested internal unit-buffer capacity.
200 ///
201 /// # Returns
202 ///
203 /// Returns a new buffered asynchronous decoder input.
204 pub fn with_capacity(inner: I, capacity: usize) -> Self {
205 Self {
206 input: AsyncBufferedInput::with_capacity(inner, capacity),
207 }
208 }
209
210 /// Tries to create an adapter with an internal unit buffer of at least
211 /// capacity.
212 ///
213 /// # Parameters
214 ///
215 /// - `inner`: Asynchronous unit source owned by the adapter.
216 /// - `capacity`: Minimum requested unit-buffer capacity.
217 ///
218 /// # Returns
219 ///
220 /// The adapter with an empty unread window on successful allocation.
221 ///
222 /// # Errors
223 ///
224 /// Returns the allocation error when the internal buffer cannot be
225 /// allocated.
226 pub fn try_with_capacity(inner: I, capacity: usize) -> std::result::Result<Self, TryReserveError> {
227 Ok(Self {
228 input: AsyncBufferedInput::try_with_capacity(inner, capacity)?,
229 })
230 }
231
232 /// Returns a shared reference to the wrapped asynchronous input.
233 ///
234 /// The input can be physically positioned after units retained in this
235 /// adapter's unread buffer.
236 ///
237 /// # Returns
238 ///
239 /// A shared borrow of the underlying source, excluding buffered units.
240 #[must_use]
241 #[inline]
242 pub const fn inner(&self) -> &I {
243 self.input.inner()
244 }
245
246 /// Returns a mutable reference to the wrapped asynchronous input.
247 ///
248 /// Direct reads can invalidate the logical stream position represented by
249 /// unread buffered units.
250 ///
251 /// # Returns
252 ///
253 /// An exclusive borrow of the source; direct reads bypass buffered units.
254 #[must_use]
255 #[inline]
256 pub fn inner_mut(&mut self) -> &mut I {
257 self.input.inner_mut()
258 }
259
260 /// Returns the number of unread units currently buffered.
261 ///
262 /// # Returns
263 ///
264 /// The number of buffered units not yet consumed.
265 #[must_use]
266 #[inline]
267 pub const fn unread_len(&self) -> usize {
268 self.input.unread_len()
269 }
270
271 /// Returns the unread buffered unit window.
272 ///
273 /// # Returns
274 ///
275 /// The currently retained units borrowed without allocation.
276 #[must_use]
277 #[inline]
278 pub fn unread(&self) -> &[I::Item] {
279 self.input.unread()
280 }
281
282 /// Returns the total internal unit-buffer capacity.
283 ///
284 /// # Returns
285 ///
286 /// The total number of units the internal buffer can hold.
287 #[must_use]
288 #[inline]
289 pub fn capacity(&self) -> usize {
290 self.input.capacity()
291 }
292
293 /// Consumes unread units from the current buffer window.
294 ///
295 /// # Parameters
296 ///
297 /// - `count`: Number of retained units to discard from the unread prefix.
298 ///
299 /// # Panics
300 ///
301 /// Panics when count exceeds the unread unit count.
302 #[inline]
303 pub fn consume(&mut self, count: usize) {
304 assert!(count <= self.unread_len(), "cannot consume beyond buffered input",);
305 // SAFETY: The asserted bound proves count fits the unread window.
306 unsafe {
307 self.input.consume(count);
308 }
309 }
310
311 /// Copies unread units into an indexed output range without consuming them.
312 ///
313 /// # Parameters
314 ///
315 /// - `output`: Destination slice receiving copies of retained units.
316 /// - `output_index`: First destination index.
317 /// - `count`: Number of unread units to copy without consuming them.
318 ///
319 /// # Safety
320 ///
321 /// The caller must guarantee that the indexed range fits in output, does
322 /// not overflow, holds no overlapping unread units, and count is no
323 /// greater than the unread unit count.
324 pub unsafe fn copy_unread_to(&self, output: &mut [I::Item], output_index: usize, count: usize) {
325 // SAFETY: The caller upholds the delegated buffer-copy contract.
326 unsafe {
327 self.input.copy_unread_to(output, output_index, count);
328 }
329 }
330
331 /// Consumes this adapter and returns the input plus its unread buffer.
332 ///
333 /// # Returns
334 ///
335 /// The owned source and buffer, preserving all unread units.
336 #[must_use = "the returned input and unread buffer must be handled"]
337 #[inline]
338 pub fn into_parts(self) -> (I, Buffer<I::Item>) {
339 self.input.into_parts()
340 }
341
342 /// Runs decoder reset into an indexed output range without I/O.
343 ///
344 /// # Type Parameters
345 ///
346 /// - `D`: Stateful decoder from source units into values.
347 /// - `M`: Callback mapping decoder errors to I/O errors.
348 /// - `Value`: Destination value type.
349 ///
350 /// # Parameters
351 ///
352 /// - `decoder`: Decoder whose state may change during this operation.
353 /// - `map_error`: Callback invoked for decoder errors.
354 /// - `output`: Destination value slice.
355 /// - `output_index`: First destination index.
356 /// - `count`: Number of writable destination positions.
357 ///
358 /// # Returns
359 ///
360 /// Number of values emitted during decoder reset.
361 ///
362 /// # Errors
363 ///
364 /// Returns invalid output-range, capacity, or mapped decoder-reset errors.
365 ///
366 /// # Panics
367 ///
368 /// Panics if the decoder writes more values than its reset bound.
369 pub fn reset<D, M, Value>(
370 &self,
371 decoder: &mut D,
372 map_error: &mut M,
373 output: &mut [Value],
374 output_index: usize,
375 count: usize,
376 ) -> Result<usize>
377 where
378 D: Transcoder<Input = I::Item, Output = Value>,
379 M: FnMut(D::Error) -> Error,
380 {
381 let required = decoder.max_reset_output_len().map_err(capacity_to_io_error)?;
382 let output_end = SliceRange::checked_range_end(
383 output.len(),
384 output_index,
385 count,
386 "reset output range exceeds destination buffer",
387 )?;
388 if count < required {
389 return Err(Error::new(
390 ErrorKind::InvalidData,
391 "insufficient output for decoder reset bound",
392 ));
393 }
394 let output = &mut output[..output_end];
395 let written = decoder.reset(output, output_index).map_err(&mut *map_error)?;
396 assert!(written <= required, "reset wrote beyond its bound");
397 Ok(written)
398 }
399
400 /// Finishes a decoder into an indexed output range without I/O.
401 ///
402 /// # Type Parameters
403 ///
404 /// - `D`: Stateful decoder from source units into values.
405 /// - `M`: Callback mapping decoder errors to I/O errors.
406 /// - `Value`: Destination value type.
407 ///
408 /// # Parameters
409 ///
410 /// - `decoder`: Decoder whose state may change during this operation.
411 /// - `map_error`: Callback invoked for decoder errors.
412 /// - `output`: Destination value slice.
413 /// - `output_index`: First destination index.
414 /// - `count`: Number of writable destination positions.
415 ///
416 /// # Returns
417 ///
418 /// Number of values emitted while finishing the decoder.
419 ///
420 /// # Errors
421 ///
422 /// Returns invalid output-range, capacity, or mapped decoder-finish
423 /// errors.
424 ///
425 /// # Panics
426 ///
427 /// Panics if the decoder writes more values than its finish bound.
428 pub fn finish<D, M, Value>(
429 &self,
430 decoder: &mut D,
431 map_error: &mut M,
432 output: &mut [Value],
433 output_index: usize,
434 count: usize,
435 ) -> Result<usize>
436 where
437 D: Transcoder<Input = I::Item, Output = Value>,
438 M: FnMut(D::Error) -> Error,
439 {
440 let required = decoder.max_finish_output_len().map_err(capacity_to_io_error)?;
441 let output_end = SliceRange::checked_range_end(
442 output.len(),
443 output_index,
444 count,
445 "finish output range exceeds destination buffer",
446 )?;
447 if count < required {
448 return Err(Error::new(
449 ErrorKind::InvalidData,
450 "insufficient output for decoder finish bound",
451 ));
452 }
453 let output = &mut output[..output_end];
454 let written = decoder.finish(output, output_index).map_err(&mut *map_error)?;
455 assert!(written <= required, "finish wrote beyond its bound");
456 Ok(written)
457 }
458}
459
460impl<I> AsyncTranscodeDecodeInput<I>
461where
462 I: AsyncInput + Unpin,
463 I::Item: Copy + Default + Unpin,
464{
465 /// Appends at least one unit to the unread buffer.
466 ///
467 /// # Returns
468 ///
469 /// Returns true when data was appended, or false at end of input.
470 ///
471 /// # Errors
472 ///
473 /// Returns input or buffer-management errors while refilling.
474 pub async fn fill_more_async(&mut self) -> Result<bool> {
475 self.input.fill_more_async().await
476 }
477
478 /// Refills until at least count unread units are available.
479 ///
480 /// # Parameters
481 ///
482 /// - `count`: Minimum desired unread unit count; grows the buffer if
483 /// needed.
484 ///
485 /// # Returns
486 ///
487 /// Returns true when count units are available, or false when EOF occurs
488 /// first.
489 ///
490 /// # Errors
491 ///
492 /// Returns allocation, input, or buffer-management errors while refilling.
493 pub async fn fill_until_async(&mut self, count: usize) -> Result<bool> {
494 if count > self.input.capacity() {
495 self.input.try_reserve_capacity(count).map_err(allocation_error)?;
496 }
497 self.input.fill_until_async(count).await
498 }
499
500 /// Polls one cancellation-safe decoder operation.
501 ///
502 /// The operation first refills only when no unread unit is buffered. After
503 /// a decoder call changes either the decoder or the buffered input, it
504 /// immediately returns [`AsyncTranscodeDecodeStep::Progress`] and never
505 /// polls the input again. This makes the returned progress the commit
506 /// boundary for cancellation: resume with the adapter's current state,
507 /// rather than replaying the previous source range.
508 ///
509 /// # Type Parameters
510 ///
511 /// - `D`: Stateful decoder from source units into values.
512 /// - `M`: Callback mapping decoder errors to I/O errors.
513 /// - `Value`: Destination value type.
514 ///
515 /// # Parameters
516 ///
517 /// - `cx`: Task context used when polling the source.
518 /// - `decoder`: Decoder whose state may change during this operation.
519 /// - `map_error`: Callback invoked for decoder errors.
520 /// - `output`: Destination value slice.
521 /// - `output_index`: First destination index.
522 /// - `count`: Number of writable destination positions.
523 ///
524 /// # Returns
525 ///
526 /// `Pending` only while awaiting source input before decoding; otherwise
527 /// ready progress or end-of-input. Successful progress has already
528 /// consumed source units.
529 ///
530 /// # Errors
531 ///
532 /// Returns input, allocation, output-range, invalid-progress, or mapped
533 /// decoder errors.
534 pub fn poll_transcode<D, M, Value>(
535 mut self: Pin<&mut Self>,
536 cx: &mut Context<'_>,
537 decoder: &mut D,
538 map_error: &mut M,
539 output: &mut [Value],
540 output_index: usize,
541 count: usize,
542 ) -> Poll<Result<AsyncTranscodeDecodeStep>>
543 where
544 D: Transcoder<Input = I::Item, Output = Value>,
545 M: FnMut(D::Error) -> Error,
546 {
547 let output_end = SliceRange::checked_range_end(
548 output.len(),
549 output_index,
550 count,
551 "decoded output range exceeds destination buffer",
552 )?;
553 if count == 0 {
554 return Poll::Ready(Ok(AsyncTranscodeDecodeStep::Progress(TranscodeProgress::complete(
555 0, 0,
556 ))));
557 }
558 let output = &mut output[..output_end];
559 if self.as_ref().get_ref().unread_len() == 0 {
560 let this = self.as_mut().get_mut();
561 match Pin::new(&mut this.input).poll_fill_more(cx) {
562 Poll::Ready(Ok(true)) => {}
563 Poll::Ready(Ok(false)) => {
564 return Poll::Ready(Ok(AsyncTranscodeDecodeStep::EndOfInput));
565 }
566 Poll::Ready(Err(error)) => return Poll::Ready(Err(error)),
567 Poll::Pending => return Poll::Pending,
568 }
569 }
570 let this = self.as_mut().get_mut();
571 let available_input = this.unread_len();
572 let progress = decoder
573 .transcode(this.unread(), 0, output, output_index)
574 .map_err(&mut *map_error)
575 .and_then(|progress| validate_decode_progress(progress, 0, available_input, output_index, count));
576 let progress = match progress {
577 Ok(progress) => progress,
578 Err(error) => return Poll::Ready(Err(error)),
579 };
580 this.consume(progress.read());
581 Poll::Ready(Ok(AsyncTranscodeDecodeStep::Progress(progress)))
582 }
583
584 /// Performs one decode step after the caller has established EOF.
585 ///
586 /// This method performs no I/O. It passes the current unread buffer to
587 /// [`Transcoder::transcode_eof`], validates progress, and commits consumed
588 /// source units before returning.
589 ///
590 /// # Type Parameters
591 ///
592 /// - `D`: Stateful decoder from source units into values.
593 /// - `M`: Callback mapping decoder errors to I/O errors.
594 /// - `Value`: Destination value type.
595 ///
596 /// # Parameters
597 ///
598 /// - `decoder`: Decoder whose state may change during this operation.
599 /// - `map_error`: Callback invoked for decoder errors.
600 /// - `output`: Destination value slice.
601 /// - `output_index`: First destination index.
602 /// - `count`: Number of writable destination positions.
603 ///
604 /// # Returns
605 ///
606 /// Validated progress with source consumption committed. A zero output
607 /// count returns zero progress without calling the decoder; an empty input
608 /// is still dispatched to `transcode_eof`.
609 ///
610 /// # Errors
611 ///
612 /// Returns invalid output-range errors, or decoder errors mapped by
613 /// `map_error`, and invalid-progress errors from contract validation.
614 pub fn transcode_eof_step<D, M, Value>(
615 &mut self,
616 decoder: &mut D,
617 map_error: &mut M,
618 output: &mut [Value],
619 output_index: usize,
620 count: usize,
621 ) -> Result<TranscodeProgress>
622 where
623 D: Transcoder<Input = I::Item, Output = Value>,
624 M: FnMut(D::Error) -> Error,
625 {
626 let output_end = SliceRange::checked_range_end(
627 output.len(),
628 output_index,
629 count,
630 "decoded EOF output range exceeds destination buffer",
631 )?;
632 if count == 0 {
633 return Ok(TranscodeProgress::complete(0, 0));
634 }
635 let available_input = self.unread_len();
636 let progress = decoder
637 .transcode_eof(self.unread(), 0, &mut output[..output_end], output_index)
638 .map_err(&mut *map_error)
639 .and_then(|progress| validate_decode_progress(progress, 0, available_input, output_index, count))?;
640 self.consume(progress.read());
641 Ok(progress)
642 }
643
644 /// Decodes one cancellation-safe progress step into an indexed output
645 /// range.
646 ///
647 /// This is the async wrapper for [`Self::poll_transcode`]. It returns after
648 /// one decoder invocation; callers that require a complete destination
649 /// range must drive successive steps and retain each returned progress.
650 ///
651 /// # Type Parameters
652 ///
653 /// - `D`: Stateful decoder from source units into values.
654 /// - `M`: Callback mapping decoder errors to I/O errors.
655 /// - `Value`: Destination value type.
656 ///
657 /// # Parameters
658 ///
659 /// - `decoder`: Decoder whose state may change during this operation.
660 /// - `map_error`: Callback invoked for decoder errors.
661 /// - `output`: Destination value slice.
662 /// - `output_index`: First destination index.
663 /// - `count`: Number of writable destination positions.
664 ///
665 /// # Returns
666 ///
667 /// One committed progress step, or end-of-input when the source is
668 /// exhausted.
669 ///
670 /// # Errors
671 ///
672 /// Returns input, allocation, output-range, invalid-progress, or mapped
673 /// decoder errors from `poll_transcode`.
674 pub async fn transcode_async<D, M, Value>(
675 &mut self,
676 decoder: &mut D,
677 map_error: &mut M,
678 output: &mut [Value],
679 output_index: usize,
680 count: usize,
681 ) -> Result<AsyncTranscodeDecodeStep>
682 where
683 D: Transcoder<Input = I::Item, Output = Value>,
684 M: FnMut(D::Error) -> Error,
685 {
686 poll_fn(|cx| Pin::new(&mut *self).poll_transcode(cx, decoder, map_error, output, output_index, count)).await
687 }
688}
689
690impl<I> AsyncInput for AsyncTranscodeDecodeInput<I>
691where
692 I: AsyncInput,
693 I::Item: Copy + Default,
694{
695 /// Item type read through the retained unit buffer.
696 type Item = I::Item;
697
698 /// Reports that this input retains unread units.
699 ///
700 /// # Returns
701 ///
702 /// Always `true`, because this adapter retains unread units.
703 #[inline]
704 fn is_buffered(&self) -> bool {
705 true
706 }
707
708 /// Polls one read through the retained unit buffer.
709 ///
710 /// # Parameters
711 ///
712 /// - `cx`: Task context used to poll the buffered source.
713 /// - `output`: Destination unit slice.
714 /// - `index`: First destination index.
715 /// - `count`: Maximum number of units to read.
716 ///
717 /// # Returns
718 ///
719 /// `Pending` while awaiting source data, or a ready read count; zero
720 /// indicates EOF.
721 ///
722 /// # Errors
723 ///
724 /// Returns errors from the buffered source or its buffer management.
725 ///
726 /// # Safety
727 ///
728 /// The caller must provide a valid indexed output range.
729 unsafe fn poll_read_unchecked(
730 mut self: Pin<&mut Self>,
731 cx: &mut Context<'_>,
732 output: &mut [Self::Item],
733 index: usize,
734 count: usize,
735 ) -> Poll<Result<usize>> {
736 // SAFETY: Pinning this wrapper pins its buffered input field.
737 let input = unsafe { Pin::new_unchecked(&mut self.as_mut().get_unchecked_mut().input) };
738 // SAFETY: The caller upholds the delegated indexed-read contract.
739 unsafe { input.poll_read_unchecked(cx, output, index, count) }
740 }
741}
742
743impl<I> fmt::Debug for AsyncTranscodeDecodeInput<I>
744where
745 I: AsyncInput,
746 I::Item: Copy + Default,
747 AsyncBufferedInput<I>: fmt::Debug,
748{
749 /// Formats this asynchronous decoder input for debugging.
750 ///
751 /// # Parameters
752 ///
753 /// - `formatter`: Debug output destination.
754 ///
755 /// # Returns
756 ///
757 /// The result of formatting the buffered input.
758 ///
759 /// # Errors
760 ///
761 /// Returns a formatting error if the destination rejects output.
762 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
763 formatter
764 .debug_struct("AsyncTranscodeDecodeInput")
765 .field("input", &self.input)
766 .finish()
767 }
768}
769
770/// Converts decoder capacity failures into invalid stream data.
771///
772/// # Parameters
773///
774/// - `error`: Capacity failure retained as the I/O error payload.
775///
776/// # Returns
777///
778/// An invalid-data error owning the original capacity failure.
779fn capacity_to_io_error(error: CapacityError) -> Error {
780 Error::new(ErrorKind::InvalidData, error)
781}