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