qubit_codec/transcode/io/transcode_encode_output.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 output driver that encodes values into units.
9
10use core::fmt;
11use core::result::Result as CoreResult;
12use std::collections::TryReserveError;
13use std::io::Error;
14use std::io::ErrorKind;
15use std::io::Result;
16use std::io::Seek;
17use std::io::SeekFrom;
18use std::io::Write;
19
20use qubit_io::BufferedOutput;
21use qubit_io::BufferedOutputRecovery;
22use qubit_io::ByteOutput;
23use qubit_io::Output;
24use qubit_io::SeekableByteOutput;
25use qubit_utils::SliceRange;
26use qubit_utils::allocation_error;
27
28use super::transcode_progress_validation::validate_encode_progress;
29use crate::CapacityError;
30use crate::Codec;
31use crate::TranscodeEncodeError;
32use crate::TranscodeEncodeErrorOf;
33use crate::TranscodeEncoder;
34use crate::TranscodeProgress;
35use crate::TranscodeStatus;
36use crate::Transcoder;
37use crate::value::codec_value_lifecycle::encode_complete_value_into_reserved;
38use crate::value::codec_value_lifecycle::max_complete_encode_units;
39
40/// Encodes an [`Output`] value stream into an [`Output`] unit stream.
41///
42/// This type owns only the unit-level [`qubit_io::BufferedOutput`]. Callers
43/// pass a [`crate::Codec`] and error mapper to each encode operation, which
44/// lets one buffered output drive different encoders without nesting buffers or
45/// storing codec-specific state in the buffer owner.
46///
47/// [`Self::flush`] only drains already buffered units. State-aware streaming
48/// encoders can use [`Self::reset`], [`Self::transcode`], and [`Self::finish`]
49/// explicitly.
50///
51/// # Type Parameters
52///
53/// * `O` - Wrapped unit output.
54///
55/// # Examples
56///
57/// ```
58/// use std::io::Cursor;
59///
60/// use qubit_codec::TranscodeEncodeOutput;
61///
62/// let output = TranscodeEncodeOutput::with_capacity(Cursor::new(Vec::<u8>::new()), 8);
63/// assert!(output.spare_capacity() >= 8);
64/// ```
65pub struct TranscodeEncodeOutput<O>
66where
67 O: Output,
68 O::Item: Copy + Default,
69{
70 /// Owns the wrapped unit sink and pending encoded units awaiting delivery.
71 output: BufferedOutput<O>,
72}
73
74impl<O> TranscodeEncodeOutput<O>
75where
76 O: Output,
77 O::Item: Copy + Default,
78{
79 /// Creates an encoder output with the default unit buffer capacity.
80 ///
81 /// # Parameters
82 ///
83 /// * `inner` - Unit output written by this adapter.
84 ///
85 /// # Returns
86 ///
87 /// A new buffered encoder output.
88 #[must_use]
89 pub fn new(inner: O) -> Self {
90 Self {
91 output: BufferedOutput::new(inner),
92 }
93 }
94
95 /// Creates an encoder output with a unit buffer of at least `capacity`.
96 ///
97 /// # Parameters
98 ///
99 /// * `inner` - Unit output written by this adapter.
100 /// * `capacity` - Requested internal unit buffer capacity.
101 ///
102 /// # Returns
103 ///
104 /// A new buffered encoder output.
105 #[must_use]
106 pub fn with_capacity(inner: O, capacity: usize) -> Self {
107 Self {
108 output: BufferedOutput::with_capacity(inner, capacity),
109 }
110 }
111
112 /// Creates an encoder output with a unit buffer of at least `capacity`.
113 ///
114 /// # Parameters
115 ///
116 /// * `inner` - Unit output written by this adapter.
117 /// * `capacity` - Requested internal unit buffer capacity.
118 ///
119 /// # Errors
120 ///
121 /// Returns an allocation error when the requested buffer cannot be
122 /// allocated.
123 ///
124 /// # Returns
125 ///
126 /// A buffered adapter owning `inner` on success.
127 pub fn try_with_capacity(inner: O, capacity: usize) -> CoreResult<Self, TryReserveError> {
128 Ok(Self {
129 output: BufferedOutput::try_with_capacity(inner, capacity)?,
130 })
131 }
132
133 /// Returns a shared reference to the wrapped unit output.
134 ///
135 /// Pending units remain in this adapter's internal buffer and are not
136 /// visible through the returned output until [`Self::flush`] succeeds.
137 ///
138 /// # Returns
139 ///
140 /// A shared reference to the wrapped unit output.
141 #[must_use]
142 #[inline]
143 pub const fn inner(&self) -> &O {
144 self.output.inner()
145 }
146
147 /// Returns the available capacity of the spare output buffer.
148 ///
149 /// # Returns
150 ///
151 /// The number of output units that can still be appended without flushing.
152 #[must_use]
153 #[inline]
154 pub fn spare_capacity(&self) -> usize {
155 self.output.spare_capacity()
156 }
157
158 /// Returns raw spare-buffer parts for the internal output buffer.
159 ///
160 /// # Returns
161 ///
162 /// The full backing storage, the spare start index, and the spare unit
163 /// count.
164 #[must_use]
165 #[inline]
166 pub fn spare_raw_parts_mut(&mut self) -> (&mut [O::Item], usize, usize) {
167 self.output.spare_raw_parts_mut()
168 }
169
170 /// Marks `count` units from [`Self::spare_raw_parts_mut`] as written.
171 ///
172 /// # Parameters
173 ///
174 /// * `count` - Initialized units to commit from the spare window.
175 ///
176 /// # Safety
177 ///
178 /// The caller must guarantee that `count <= Self::spare_capacity()` and
179 /// that the corresponding units in the returned spare slice have been
180 /// initialized.
181 #[inline]
182 pub unsafe fn advance(&mut self, count: usize) {
183 // SAFETY: The caller guarantees `count` and initialization invariants.
184 unsafe { self.output.advance(count) }
185 }
186
187 /// Ensures that at least `count` spare units are available.
188 ///
189 /// # Parameters
190 ///
191 /// * `count` - Number of spare units required.
192 ///
193 /// # Errors
194 ///
195 /// Returns allocation errors mapped to [`ErrorKind::OutOfMemory`], or I/O
196 /// errors from the wrapped output while delivering pending units.
197 pub fn ensure_spare_capacity(&mut self, count: usize) -> Result<()> {
198 self.output.try_reserve_capacity(count).map_err(allocation_error)?;
199 self.output.ensure_spare_capacity(count)
200 }
201
202 /// Consumes this adapter without flushing the wrapped output.
203 ///
204 /// This method does not call [`Self::flush`] and performs no I/O. `Pending`
205 /// units were not reported as written and may be retried. `Indeterminate`
206 /// means an inner write panicked and may have produced an external prefix;
207 /// do not replay it automatically.
208 ///
209 /// # Returns
210 ///
211 /// The wrapped output and pending or indeterminate units.
212 #[must_use = "the returned output and recovery status must be handled"]
213 #[inline]
214 pub fn into_parts(self) -> (O, BufferedOutputRecovery<O::Item>) {
215 self.output.into_parts()
216 }
217
218 /// Flushes buffered units without finishing any encoder stream.
219 ///
220 /// # Errors
221 ///
222 /// Returns errors from the wrapped output while flushing pending units.
223 pub fn flush(&mut self) -> Result<()> {
224 self.output.flush()
225 }
226
227 /// Encodes one codec value into this buffered unit output.
228 ///
229 /// The method grows the persistent internal buffer when necessary, then
230 /// writes the complete encoded value into its spare window.
231 ///
232 /// # Type Parameters
233 ///
234 /// * `C` - Codec producing the wrapped output unit type.
235 /// * `M` - Mapper from codec errors into I/O errors.
236 ///
237 /// # Parameters
238 ///
239 /// * `codec` - Codec used for this single-value encode.
240 /// * `value` - Value to encode.
241 /// * `map_error` - Mapper for codec-domain encode errors.
242 ///
243 /// # Errors
244 ///
245 /// Returns I/O errors from the wrapped output, `InvalidInput` when the
246 /// codec output bound overflows or the value is outside the codec domain,
247 /// or the error returned by `map_error` for codec encode, reset, and finish
248 /// failures.
249 ///
250 /// # Panics
251 ///
252 /// Panics when the codec violates its declared reset, value-width, or
253 /// finish bounds, or when `encode` writes a length different from
254 /// `encode_len` in the same reset state.
255 pub fn write_encoded_with<C, M>(&mut self, codec: &mut C, value: &C::Value, mut map_error: M) -> Result<()>
256 where
257 C: Codec<Unit = O::Item>,
258 M: FnMut(C::EncodeError) -> Error,
259 {
260 let max_units = map_encode_value_result(
261 max_complete_encode_units::<C>().map_err(TranscodeEncodeErrorOf::<C>::from),
262 &mut map_error,
263 )?;
264 self.ensure_spare_capacity(max_units)?;
265 let (units, output_index, available) = self.output.spare_raw_parts_mut();
266 debug_assert!(
267 available >= max_units,
268 "reserved spare buffer is smaller than codec upper bound",
269 );
270 let written = map_encode_value_result(
271 encode_complete_value_into_reserved(codec, value, units, output_index, max_units),
272 &mut map_error,
273 )?;
274 // SAFETY: The spare buffer has the conservative complete lifecycle
275 // capacity, and the helper reports how many initialized units it
276 // actually wrote.
277 unsafe {
278 self.output.advance(written);
279 }
280 Ok(())
281 }
282
283 /// Runs encoder reset and buffers any stream-prefix units.
284 ///
285 /// This method reserves enough persistent buffer capacity for all reset
286 /// output before calling `encoder`. Preparing that space may deliver
287 /// previously buffered units to the wrapped output and can return an I/O
288 /// error before `encoder.reset` runs. This delivery does not call the
289 /// wrapped output's `flush` method.
290 ///
291 /// # Type Parameters
292 ///
293 /// * `E` - Transcoder producing the wrapped output unit type.
294 /// * `M` - Mapper from transcoder errors into I/O errors.
295 /// * `Value` - Source value type accepted by the transcoder.
296 ///
297 /// # Parameters
298 ///
299 /// * `encoder` - Transcoder whose stream prefix is being collected.
300 /// * `map_error` - Mapper for reset failures.
301 ///
302 /// # Errors
303 ///
304 /// Returns capacity errors, allocation errors, or reset errors mapped by
305 /// `map_error`.
306 ///
307 /// # Panics
308 ///
309 /// Panics when `encoder` writes more than its declared reset bound.
310 pub fn reset<E, M, Value>(&mut self, encoder: &mut E, map_error: &mut M) -> Result<()>
311 where
312 E: Transcoder<Input = Value, Output = O::Item>,
313 M: FnMut(E::Error) -> Error,
314 {
315 let required = encoder.max_reset_output_len().map_err(capacity_error_to_invalid_data)?;
316 self.ensure_spare_capacity(required)?;
317 let (units, output_index, available) = self.output.spare_raw_parts_mut();
318 debug_assert!(
319 available >= required,
320 "insufficient reset capacity reserved in spare output buffer",
321 );
322 let written = encoder.reset(units, output_index).map_err(&mut *map_error)?;
323 assert!(written <= required, "reset wrote beyond its bound");
324 // SAFETY: The encoder reported initialized units within the spare
325 // range reserved above.
326 unsafe {
327 self.output.advance(written);
328 }
329 Ok(())
330 }
331
332 /// Encodes at most one step of the selected input range.
333 ///
334 /// Unlike [`Self::transcode`], this method does not reserve output space
335 /// for the entire range and calls the encoder exactly once. The returned
336 /// progress is relative to this call's input and output windows. Advance
337 /// the input index by [`TranscodeProgress::read`]; if the status is
338 /// `NeedOutput`, provide the requested spare capacity before retrying.
339 /// Written units have already been committed to this adapter's pending
340 /// buffer and must not be advanced again. A zero count validates the range
341 /// and returns complete progress without delivering pending units or
342 /// calling the encoder.
343 ///
344 /// # Parameters
345 ///
346 /// * `encoder` - Encoder that processes one progress step.
347 /// * `map_error` - Maps encoder errors to I/O errors.
348 /// * `input` - Source values.
349 /// * `input_index` - Start index inside `input`.
350 /// * `count` - Number of values available from `input_index`.
351 ///
352 /// # Returns
353 ///
354 /// Progress for the single encoder call, including consumed input,
355 /// committed output, and whether more output capacity is needed.
356 ///
357 /// # Errors
358 ///
359 /// Returns invalid input ranges, capacity, encoder, or output errors. An
360 /// invalid encoder progress report is returned as `ErrorKind::InvalidData`.
361 /// An error does not provide general transactional rollback or complete
362 /// progress. The encoder may already have advanced, but units written by
363 /// its failing call are not committed to this adapter's pending output.
364 /// Do not replay the original input range without an encoder-specific
365 /// recovery protocol. Earlier pending units retain the wrapped output's
366 /// recovery contract; reset starts a new logical stream and does not undo
367 /// output already delivered.
368 ///
369 /// # Examples
370 ///
371 /// ```
372 /// use std::io::Cursor;
373 ///
374 /// # use core::convert::Infallible;
375 /// # use core::num::NonZeroUsize;
376 /// # use qubit_codec::Codec;
377 /// # use qubit_codec::CodecTranscodeEncoder;
378 /// # use qubit_codec::DecodeFailure;
379 /// use qubit_codec::TranscodeEncodeOutput;
380 /// use qubit_codec::TranscodeEncoder;
381 /// use qubit_codec::TranscodeStatus;
382 ///
383 /// # struct ByteCodec;
384 /// # impl Codec for ByteCodec {
385 /// # type Value = u8;
386 /// # type Unit = u8;
387 /// # type DecodeError = Infallible;
388 /// # type EncodeError = Infallible;
389 /// # const MIN_UNITS_PER_VALUE: usize = 1;
390 /// # const MAX_ENCODE_UNITS_PER_VALUE: usize = 1;
391 /// # const MAX_DECODE_UNITS_PER_VALUE: usize = 1;
392 /// # unsafe fn decode(
393 /// # &mut self,
394 /// # input: &[u8],
395 /// # index: usize,
396 /// # ) -> Result<(u8, NonZeroUsize), DecodeFailure<Infallible>> {
397 /// # Ok((input[index], NonZeroUsize::MIN))
398 /// # }
399 /// # unsafe fn encode(
400 /// # &mut self,
401 /// # value: &u8,
402 /// # output: &mut [u8],
403 /// # index: usize,
404 /// # ) -> Result<usize, Infallible> {
405 /// # output[index] = *value;
406 /// # Ok(1)
407 /// # }
408 /// # }
409 /// fn encode<E>(encoder: &mut E, values: &[E::Input]) -> std::io::Result<Vec<u8>>
410 /// where
411 /// E: TranscodeEncoder<Output = u8>,
412 /// {
413 /// let mut output = TranscodeEncodeOutput::with_capacity(Cursor::new(Vec::new()), 8);
414 /// let mut map_error = |_| std::io::Error::other("encode error");
415 /// output.reset(encoder, &mut map_error)?;
416 /// let mut offset = 0;
417 /// while offset < values.len() {
418 /// let progress = output.transcode_step(
419 /// encoder,
420 /// &mut map_error,
421 /// values,
422 /// offset,
423 /// values.len() - offset,
424 /// )?;
425 /// offset += progress.read();
426 /// if let TranscodeStatus::NeedOutput { required, .. } = progress.status() {
427 /// output.ensure_spare_capacity(required.get())?;
428 /// }
429 /// }
430 /// output.finish(encoder, &mut map_error)?;
431 /// let (cursor, _) = output.into_parts();
432 /// Ok(cursor.into_inner())
433 /// }
434 ///
435 /// let mut encoder = CodecTranscodeEncoder::new(ByteCodec);
436 /// assert_eq!(encode(&mut encoder, &[1, 2, 3]).unwrap(), vec![1, 2, 3]);
437 /// let mut empty_encoder = CodecTranscodeEncoder::new(ByteCodec);
438 /// assert_eq!(encode(&mut empty_encoder, &[]).unwrap(), Vec::<u8>::new());
439 /// ```
440 pub fn transcode_step<E, M, Value>(
441 &mut self,
442 encoder: &mut E,
443 map_error: &mut M,
444 input: &[Value],
445 input_index: usize,
446 count: usize,
447 ) -> Result<TranscodeProgress>
448 where
449 E: TranscodeEncoder<Input = Value, Output = O::Item>,
450 M: FnMut(E::Error) -> Error,
451 {
452 let input_end = SliceRange::checked_range_end(
453 input.len(),
454 input_index,
455 count,
456 "encode input range exceeds source buffer",
457 )?;
458 if count == 0 {
459 return Ok(TranscodeProgress::complete(0, 0));
460 }
461 let required = encoder
462 .max_transcode_output_len(1)
463 .map_err(capacity_error_to_invalid_data)?
464 .max(1);
465 self.ensure_spare_capacity(required)?;
466 let (units, output_index, available_output) = self.output.spare_raw_parts_mut();
467 let progress = encoder
468 .transcode(&input[..input_end], input_index, units, output_index)
469 .map_err(&mut *map_error)?;
470 let progress = validate_encode_progress(progress, input_index, count, output_index, available_output)?;
471 // SAFETY: Validated progress fits the spare output window.
472 unsafe {
473 self.output.advance(progress.written());
474 }
475 Ok(progress)
476 }
477
478 /// Encodes values from an indexed input range using a streaming
479 /// [`Transcoder`].
480 ///
481 /// This streaming path reserves the encoder's conservative output bound
482 /// for the whole batch before calling it. Preparing that space may deliver
483 /// previously buffered units to the wrapped output and can return an I/O
484 /// error before consuming source values. Split large batches into smaller
485 /// calls when you need to limit the memory required for one operation.
486 ///
487 /// # Type Parameters
488 ///
489 /// * `E` - Encoder producing the wrapped output unit type.
490 /// * `M` - Mapper from encoder errors into I/O errors.
491 /// * `Value` - Source value type accepted by the encoder.
492 ///
493 /// # Parameters
494 ///
495 /// * `encoder` - Streaming encoder used for this operation.
496 /// * `map_error` - Function mapping transcode errors into I/O errors.
497 /// * `input` - Source values.
498 /// * `input_index` - Start index inside `input`.
499 /// * `count` - Maximum number of values to encode.
500 ///
501 /// # Returns
502 ///
503 /// The number of source values consumed.
504 ///
505 /// # Errors
506 ///
507 /// Returns invalid input ranges, capacity, transcode, or output errors. An
508 /// output-bound contract violation is reported as `ErrorKind::InvalidData`.
509 /// An error does not provide general transactional rollback or complete
510 /// progress. The encoder may already have advanced, while units written by
511 /// its failing call are not committed to this adapter's pending output.
512 /// Do not replay the original input range unless the concrete encoder
513 /// provides an explicit recovery protocol. Previously committed pending
514 /// output remains subject to the wrapped output's recovery contract, and
515 /// reset starts a new logical stream without undoing output already
516 /// delivered.
517 ///
518 /// # Examples
519 ///
520 /// A value that only implements [`Transcoder`] is not an encoder and cannot
521 /// be passed to this method.
522 ///
523 /// ```compile_fail
524 /// use std::io::Error;
525 /// use std::io::sink;
526 ///
527 /// use qubit_codec::CapacityError;
528 /// use qubit_codec::TranscodeEncodeError;
529 /// use qubit_codec::TranscodeEncodeOutput;
530 /// use qubit_codec::TranscodeProgress;
531 /// use qubit_codec::Transcoder;
532 ///
533 /// struct GenericTranscoder;
534 ///
535 /// impl Transcoder for GenericTranscoder {
536 /// type Input = u8;
537 /// type Output = u8;
538 /// type Error = TranscodeEncodeError<(), u8>;
539 ///
540 /// fn max_transcode_output_len(
541 /// &self,
542 /// input_len: usize,
543 /// ) -> Result<usize, CapacityError> {
544 /// Ok(input_len)
545 /// }
546 ///
547 /// fn reset(
548 /// &mut self,
549 /// _output: &mut [u8],
550 /// _output_index: usize,
551 /// ) -> Result<usize, Self::Error> {
552 /// Ok(0)
553 /// }
554 ///
555 /// fn transcode(
556 /// &mut self,
557 /// input: &[u8],
558 /// input_index: usize,
559 /// _output: &mut [u8],
560 /// _output_index: usize,
561 /// ) -> Result<TranscodeProgress, Self::Error> {
562 /// Ok(TranscodeProgress::complete(input.len() - input_index, 0))
563 /// }
564 ///
565 /// fn finish(
566 /// &mut self,
567 /// _output: &mut [u8],
568 /// _output_index: usize,
569 /// ) -> Result<usize, Self::Error> {
570 /// Ok(0)
571 /// }
572 /// }
573 ///
574 /// let mut output = TranscodeEncodeOutput::with_capacity(sink(), 1);
575 /// let mut transcoder = GenericTranscoder;
576 /// let mut map_error = |_| Error::other("transcode error");
577 /// let _ = output.transcode(
578 /// &mut transcoder,
579 /// &mut map_error,
580 /// &[0_u8],
581 /// 0,
582 /// 1,
583 /// );
584 /// ```
585 pub fn transcode<E, M, Value>(
586 &mut self,
587 encoder: &mut E,
588 map_error: &mut M,
589 input: &[Value],
590 input_index: usize,
591 count: usize,
592 ) -> Result<usize>
593 where
594 E: TranscodeEncoder<Input = Value, Output = O::Item>,
595 M: FnMut(E::Error) -> Error,
596 {
597 let input_end = SliceRange::checked_range_end(
598 input.len(),
599 input_index,
600 count,
601 "encode input range exceeds source buffer",
602 )?;
603 if count == 0 {
604 return Ok(0);
605 }
606 let required = encoder
607 .max_transcode_output_len(count)
608 .map_err(capacity_error_to_invalid_data)?
609 .max(1);
610 self.ensure_spare_capacity(required)?;
611 let input = &input[..input_end];
612 let mut read_total = 0;
613 while read_total < count {
614 let (units, output_index, available_output) = self.output.spare_raw_parts_mut();
615 let remaining_input = count - read_total;
616 let progress = encoder
617 .transcode(input, input_index + read_total, units, output_index)
618 .map_err(&mut *map_error)?;
619 let progress = validate_encode_progress(
620 progress,
621 input_index + read_total,
622 remaining_input,
623 output_index,
624 available_output,
625 )?;
626 let read = progress.read();
627 let written = progress.written();
628 // SAFETY: The progress bounds check above proved that the encoder
629 // initialized no more than the available spare output window.
630 unsafe {
631 self.output.advance(written);
632 }
633 read_total += read;
634 if progress.is_complete() {
635 return Ok(read_total);
636 }
637 if let TranscodeStatus::NeedOutput { required, .. } = progress.status()
638 && (read_total == count || available_output - written < required.get() || (read == 0 && written == 0))
639 {
640 return Err(Error::new(
641 ErrorKind::InvalidData,
642 "encoder output bound was insufficient",
643 ));
644 }
645 }
646 Ok(read_total)
647 }
648
649 /// Finishes the encoder and flushes the wrapped unit output.
650 ///
651 /// This method writes final units directly into the internal spare buffer,
652 /// growing it when [`Transcoder::max_finish_output_len`] exceeds the
653 /// current capacity.
654 ///
655 /// # Type Parameters
656 ///
657 /// * `E` - Transcoder producing the wrapped output unit type.
658 /// * `M` - Mapper from transcoder errors into I/O errors.
659 /// * `Value` - Source value type accepted by the transcoder.
660 ///
661 /// # Parameters
662 ///
663 /// * `encoder` - Encoder whose final units are being collected.
664 /// * `map_error` - Function mapping transcode errors into I/O errors.
665 ///
666 /// # Errors
667 ///
668 /// Returns capacity, transcode finalization, or wrapped output flush
669 /// errors.
670 ///
671 /// # Panics
672 ///
673 /// Panics when the encoder exceeds its declared finish-output bound.
674 pub fn finish<E, M, Value>(&mut self, encoder: &mut E, map_error: &mut M) -> Result<()>
675 where
676 E: Transcoder<Input = Value, Output = O::Item>,
677 M: FnMut(E::Error) -> Error,
678 {
679 self.finish_to_buffer(encoder, map_error)?;
680 self.output.flush()
681 }
682
683 /// Finishes the encoder while retaining final units in the output buffer.
684 ///
685 /// This method separates encoder finalization from output delivery. It is
686 /// useful when a caller must record successful finalization before a later
687 /// flush can fail. Call [`Self::flush`] to deliver the retained units.
688 ///
689 /// # Type Parameters
690 ///
691 /// * `E` - Transcoder producing the wrapped output unit type.
692 /// * `M` - Mapper from transcoder errors into I/O errors.
693 /// * `Value` - Source value type accepted by the transcoder.
694 ///
695 /// # Parameters
696 ///
697 /// * `encoder` - Encoder whose final units are being collected.
698 /// * `map_error` - Function mapping transcode errors into I/O errors.
699 ///
700 /// # Errors
701 ///
702 /// Returns capacity planning, allocation, or transcoder finalization
703 /// errors. It does not perform output I/O; use [`Self::finish`] to deliver
704 /// the buffered final units and flush the wrapped output.
705 ///
706 /// # Panics
707 ///
708 /// Panics when `encoder` writes more units than its declared finish bound.
709 pub fn finish_to_buffer<E, M, Value>(&mut self, encoder: &mut E, map_error: &mut M) -> Result<()>
710 where
711 E: Transcoder<Input = Value, Output = O::Item>,
712 M: FnMut(E::Error) -> Error,
713 {
714 let required = match encoder.max_finish_output_len() {
715 Ok(required) => required,
716 Err(error) => return Err(capacity_error_to_invalid_data(error)),
717 };
718 let pending = self.output.capacity() - self.output.spare_capacity();
719 let capacity = pending
720 .checked_add(required)
721 .ok_or_else(|| capacity_error_to_invalid_data(CapacityError::OutputLengthOverflow))?;
722 self.output.try_reserve_capacity(capacity).map_err(allocation_error)?;
723 let (units, output_index, available) = self.output.spare_raw_parts_mut();
724 debug_assert!(
725 available >= required,
726 "insufficient finish capacity reserved in spare output buffer",
727 );
728 let written = encoder.finish(units, output_index).map_err(&mut *map_error)?;
729 assert!(written <= required, "finish wrote beyond its bound");
730 // SAFETY: The encoder reported initialized units within the spare
731 // range that was reserved above.
732 unsafe {
733 self.output.advance(written);
734 }
735 Ok(())
736 }
737}
738
739impl<O> TranscodeEncodeOutput<O>
740where
741 O: SeekableByteOutput,
742{
743 /// Flushes pending bytes, then seeks the wrapped byte output.
744 ///
745 /// # Parameters
746 ///
747 /// * `position` - Target seek position.
748 ///
749 /// # Returns
750 ///
751 /// The new stream position reported by the wrapped output.
752 ///
753 /// # Errors
754 ///
755 /// Returns flush or seek errors from the wrapped output.
756 pub fn seek(&mut self, position: SeekFrom) -> Result<u64> {
757 self.output.seek_to(position)
758 }
759}
760
761impl<O> Write for TranscodeEncodeOutput<O>
762where
763 O: ByteOutput,
764{
765 /// Writes raw bytes through the internal buffer without encoding them.
766 ///
767 /// # Parameters
768 ///
769 /// * `input` - Bytes to append to the buffered unit output.
770 ///
771 /// # Returns
772 ///
773 /// The number of bytes accepted, which may be shorter than `input`.
774 ///
775 /// # Errors
776 ///
777 /// Propagates wrapped-output errors when buffer delivery is needed.
778 #[inline]
779 fn write(&mut self, input: &[u8]) -> Result<usize> {
780 Output::write(&mut self.output, input)
781 }
782
783 /// Writes all raw bytes through the internal buffer without encoding them.
784 ///
785 /// # Parameters
786 ///
787 /// * `input` - Bytes that must all be accepted before success.
788 ///
789 /// # Errors
790 ///
791 /// Propagates output errors and returns `WriteZero` if output stops
792 /// progressing.
793 ///
794 /// # Panics
795 ///
796 /// Panics when the wrapped output reports more bytes than supplied.
797 fn write_all(&mut self, input: &[u8]) -> Result<()> {
798 let mut written = 0;
799 while written < input.len() {
800 let count = match Output::write(&mut self.output, &input[written..]) {
801 Ok(count) => count,
802 Err(error) if error.kind() == ErrorKind::Interrupted => continue,
803 Err(error) => return Err(error),
804 };
805 if count == 0 {
806 return Err(Error::from(ErrorKind::WriteZero));
807 }
808 assert!(
809 count <= input.len() - written,
810 "Output::write returned a count beyond the input length",
811 );
812 written += count;
813 }
814 Ok(())
815 }
816
817 /// Flushes buffered bytes to the wrapped output without finishing an
818 /// encoder.
819 ///
820 /// # Errors
821 ///
822 /// Propagates wrapped-output flush errors.
823 #[inline]
824 fn flush(&mut self) -> Result<()> {
825 TranscodeEncodeOutput::flush(self)
826 }
827}
828
829impl<O> Seek for TranscodeEncodeOutput<O>
830where
831 O: SeekableByteOutput,
832{
833 /// Flushes pending bytes, then seeks the wrapped byte output.
834 ///
835 /// # Parameters
836 ///
837 /// * `position` - Target position relative to the selected seek origin.
838 ///
839 /// # Returns
840 ///
841 /// The new absolute byte position.
842 ///
843 /// # Errors
844 ///
845 /// Propagates flush or seek errors from the wrapped output.
846 #[inline]
847 fn seek(&mut self, position: SeekFrom) -> Result<u64> {
848 self.seek(position)
849 }
850}
851
852impl<O> fmt::Debug for TranscodeEncodeOutput<O>
853where
854 O: Output,
855 O::Item: Copy + Default,
856 BufferedOutput<O>: fmt::Debug,
857{
858 /// Formats the owned buffer and underlying output for diagnostics.
859 ///
860 /// # Parameters
861 ///
862 /// * `formatter` - Destination and formatting options.
863 ///
864 /// # Errors
865 ///
866 /// Returns a formatting error if the destination rejects output.
867 fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
868 formatter
869 .debug_struct("TranscodeEncodeOutput")
870 .field("output", &self.output)
871 .finish()
872 }
873}
874
875/// Wraps a streaming capacity failure as `InvalidData`, retaining its source.
876///
877/// # Parameters
878///
879/// * `error` - Capacity planning failure from a streaming transcoder.
880///
881/// # Returns
882///
883/// An owned I/O error carrying the original capacity error.
884fn capacity_error_to_invalid_data(error: CapacityError) -> Error {
885 Error::new(ErrorKind::InvalidData, error)
886}
887
888/// Preserves successful values and maps one-value failures into I/O errors.
889///
890/// # Type Parameters
891///
892/// * `T` - Successful result value.
893/// * `E` - Codec-domain error passed to the mapper.
894/// * `Value` - Source value type carried by an unencodable error.
895///
896/// # Parameters
897///
898/// * `result` - Codec lifecycle result to translate.
899/// * `map_error` - Called only for a codec-domain failure.
900///
901/// # Returns
902///
903/// The original successful value without transformation.
904///
905/// # Errors
906///
907/// Returns mapped domain errors or `InvalidInput` for bounds and domain
908/// rejection.
909fn map_encode_value_result<T, E, Value>(
910 result: CoreResult<T, TranscodeEncodeError<E, Value>>,
911 map_error: &mut dyn FnMut(E) -> Error,
912) -> Result<T> {
913 match result {
914 Ok(value) => Ok(value),
915 Err(error) => Err(map_encode_value_error(error, map_error)),
916 }
917}
918
919/// Maps domain failures through the caller and other failures to
920/// `InvalidInput`.
921///
922/// # Type Parameters
923///
924/// * `E` - Codec-domain error passed to the mapper.
925/// * `Value` - Rejected source value type, discarded during I/O translation.
926///
927/// # Parameters
928///
929/// * `error` - Encoding failure consumed by this translation.
930/// * `map_error` - Invoked only for the `Domain` variant.
931///
932/// # Returns
933///
934/// An I/O error retaining mapped domain detail or a bound/rejection message.
935#[inline(never)]
936fn map_encode_value_error<E, Value>(
937 error: TranscodeEncodeError<E, Value>,
938 map_error: &mut dyn FnMut(E) -> Error,
939) -> Error {
940 match error {
941 TranscodeEncodeError::Domain(error) => map_error(error.into_source()),
942 TranscodeEncodeError::Unencodable { .. } => Error::new(ErrorKind::InvalidInput, "codec cannot encode value"),
943 TranscodeEncodeError::Failure(_) => Error::new(ErrorKind::InvalidInput, "codec output bound overflow"),
944 }
945}