use core::fmt;
use super::ValueEncoder;
use crate::{
CapacityError,
Codec,
TranscodeEncodeErrorOf,
TranscodeFailure,
codec::assert_unit_bounds,
value::codec_value_lifecycle::{
encode_complete_value_into_reserved,
max_complete_encode_units,
},
};
pub struct CodecValueEncoder<C> {
codec: C,
}
impl<C> CodecValueEncoder<C>
where
C: Codec,
{
#[inline]
#[must_use]
pub fn new(codec: C) -> Self {
assert_unit_bounds::<C>();
Self { codec }
}
#[inline(always)]
#[must_use]
pub const fn codec(&self) -> &C {
&self.codec
}
#[inline(always)]
#[must_use]
pub fn codec_mut(&mut self) -> &mut C {
&mut self.codec
}
#[inline(always)]
#[must_use]
pub fn into_codec(self) -> C {
self.codec
}
pub fn encode_into(
&mut self,
input: &C::Value,
output: &mut Vec<C::Unit>,
) -> Result<usize, TranscodeEncodeErrorOf<C>>
where
C::Unit: Default,
{
let units = max_complete_encode_units::<C>()?;
let original_len = output.len();
let target_len = original_len
.checked_add(units)
.ok_or(CapacityError::OutputLengthOverflow)?;
output
.try_reserve(units)
.map_err(|_| TranscodeFailure::allocation_failed())?;
output.resize_with(target_len, C::Unit::default);
match encode_complete_value_into_reserved(
&mut self.codec,
input,
output,
original_len,
units,
) {
Ok(written) => {
output.truncate(original_len + written);
Ok(written)
}
Err(error) => {
output.truncate(original_len);
Err(error)
}
}
}
}
impl<C> ValueEncoder<C::Value> for CodecValueEncoder<C>
where
C: Codec,
C::Unit: Default,
{
type Output = Vec<C::Unit>;
type Error = TranscodeEncodeErrorOf<C>;
fn encode(
&mut self,
input: &C::Value,
) -> Result<Self::Output, Self::Error> {
let mut output = Vec::new();
self.encode_into(input, &mut output)?;
Ok(output)
}
}
impl<C> fmt::Debug for CodecValueEncoder<C>
where
C: Codec + fmt::Debug,
{
fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result {
formatter
.debug_struct("CodecValueEncoder")
.field("codec", &self.codec)
.finish()
}
}
impl<C> Default for CodecValueEncoder<C>
where
C: Codec + Default,
{
#[inline(always)]
fn default() -> Self {
Self::new(C::default())
}
}