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