qubit_codec/value/codec_value_encoder.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//! Value encoder adapter backed by a low-level codec.
9
10use super::ValueEncoder;
11use crate::{
12 Codec,
13 CodecEncodeError,
14 CodecValueExt,
15 codec::assert_unit_bounds,
16};
17
18/// Encodes one borrowed value into owned units by using a [`Codec`].
19///
20/// `CodecValueEncoder` is the default bridge from the low-level unchecked
21/// [`Codec`] contract to the convenience-layer [`ValueEncoder`] contract. Each
22/// call emits stream-start output through [`Codec::encode_reset`], then encodes
23/// one value through [`Codec::encode`], and returns the owned output truncated
24/// to the units actually written.
25///
26/// # Type Parameters
27///
28/// - `C`: Low-level codec used to encode one value.
29#[derive(Clone, Copy, Debug, Default, Eq, Hash, PartialEq)]
30pub struct CodecValueEncoder<C> {
31 /// Low-level codec used for one-value encoding.
32 codec: C,
33}
34
35impl<C> CodecValueEncoder<C>
36where
37 C: Codec,
38{
39 /// Creates an encoder backed by `codec`.
40 ///
41 /// # Parameters
42 ///
43 /// - `codec`: Low-level codec used to encode one value.
44 ///
45 /// # Returns
46 ///
47 /// Returns a value encoder adapter for the supplied codec.
48 ///
49 /// # Panics
50 ///
51 /// Panics when the supplied codec violates the
52 /// [`Codec::min_units_per_value`] / [`Codec::max_units_per_value`] ordering
53 /// invariant. Validating once at construction lets the hot encode path
54 /// skip the check.
55 #[must_use]
56 #[inline]
57 pub fn new(codec: C) -> Self {
58 assert_unit_bounds::<C>(&codec);
59 Self { codec }
60 }
61}
62
63impl<C> ValueEncoder<C::Value> for CodecValueEncoder<C>
64where
65 C: Codec,
66{
67 type Output = Vec<C::Unit>;
68 type Error = CodecEncodeError<C::EncodeError>;
69
70 /// Encodes one borrowed value into owned units.
71 ///
72 /// # Parameters
73 ///
74 /// - `input`: Value to encode.
75 ///
76 /// # Returns
77 ///
78 /// Returns stream-start output followed by the units written for `input`.
79 ///
80 /// # Errors
81 ///
82 /// Returns the wrapped codec's encode error when reset output or `input`
83 /// cannot be represented.
84 ///
85 /// # Panics
86 ///
87 /// Panics when the wrapped codec reports more reset output than
88 /// [`Codec::max_encode_reset_units`] or a value width different from
89 /// [`Codec::encode_len`].
90 fn encode(
91 &mut self,
92 input: &C::Value,
93 ) -> Result<Self::Output, Self::Error> {
94 if !self.codec.can_encode_value(input) {
95 return Err(CodecEncodeError::unencodable_value(0));
96 }
97 let units = self
98 .codec
99 .max_encode_reset_units()
100 .checked_add(self.codec.encode_len(input).get())
101 .ok_or_else(CodecEncodeError::output_length_overflow)?;
102 let mut output = vec![C::Unit::default(); units];
103 let written =
104 self.codec.encode_value_with_reset(input, &mut output, 0)?;
105 output.truncate(written);
106 Ok(output)
107 }
108}