use super::super::internal::{
convert_error_of::ConvertErrorOf,
convert_progress_result::ConvertProgressResult,
convert_state::ConvertState,
convert_step_result::ConvertStepResult,
encode_step::EncodeStep,
pending_encode_step::PendingEncodeStep,
pending_value::PendingValue,
pending_value_slot::PendingValueSlot,
};
use super::{
transcode_decode_engine::TranscodeDecodeEngine,
transcode_encode_engine::TranscodeEncodeEngine,
};
use crate::codec::assert_unit_bounds;
use crate::{
CapacityError,
Codec,
EncodeContext,
TranscodeConvertHooks,
TranscodeError,
};
#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub struct TranscodeConvertEngine<D, E, H>
where
D: Codec,
E: Codec<Value = D::Value>,
H: TranscodeConvertHooks<D, E>,
{
decode_engine: TranscodeDecodeEngine<D, H::DecodeHooks>,
encode_engine: TranscodeEncodeEngine<E, H::EncodeHooks>,
hooks: H,
pending: PendingValueSlot<D::Value>,
}
impl<D, E, H> TranscodeConvertEngine<D, E, H>
where
D: Codec,
E: Codec<Value = D::Value>,
H: TranscodeConvertHooks<D, E>,
{
#[must_use]
#[inline]
pub fn new(decoder: D, encoder: E, hooks: H) -> Self {
assert_unit_bounds::<D>(&decoder);
assert_unit_bounds::<E>(&encoder);
let decode_hooks = hooks.create_decode_hooks(&decoder, &encoder);
let encode_hooks = hooks.create_encode_hooks(&decoder, &encoder);
Self::from_parts(decoder, encoder, hooks, decode_hooks, encode_hooks)
}
#[inline]
pub fn from_parts(
decoder: D,
encoder: E,
hooks: H,
decode_hooks: H::DecodeHooks,
encode_hooks: H::EncodeHooks,
) -> Self {
Self {
decode_engine: TranscodeDecodeEngine::new(decoder, decode_hooks),
encode_engine: TranscodeEncodeEngine::new(encoder, encode_hooks),
hooks,
pending: PendingValueSlot::empty(),
}
}
#[must_use = "capacity planning can fail on overflow"]
pub fn max_output_len(
&self,
input_len: usize,
) -> Result<usize, CapacityError> {
let pending_units = self.pending_output_len()?;
let decoded_values = self.decode_engine.max_output_len(input_len)?;
let converted_units =
self.encode_engine.max_output_len(decoded_values)?;
converted_units
.checked_add(pending_units)
.ok_or(CapacityError::OutputLengthOverflow)
}
#[must_use = "capacity planning can fail on overflow"]
pub fn max_reset_output_len(&self) -> Result<usize, CapacityError> {
Ok(self.encode_engine.max_reset_output_len())
}
#[must_use = "capacity planning can fail on overflow"]
pub fn max_finish_output_len(&self) -> Result<usize, CapacityError> {
let pending_units = self.pending_output_len()?;
let decoder_finish_values =
self.decode_engine.max_finish_output_len()?;
let decoder_finish_units =
self.encode_engine.max_output_len(decoder_finish_values)?;
let encoder_finish_units = self.encode_engine.max_finish_output_len();
let pending_and_decoder = pending_units
.checked_add(decoder_finish_units)
.ok_or(CapacityError::OutputLengthOverflow)?;
pending_and_decoder
.checked_add(encoder_finish_units)
.ok_or(CapacityError::OutputLengthOverflow)
}
pub fn transcode(
&mut self,
input: &[D::Unit],
input_index: usize,
output: &mut [E::Unit],
output_index: usize,
) -> ConvertProgressResult<D, E, H> {
TranscodeError::ensure_transcode_indices(
input.len(),
input_index,
output.len(),
output_index,
)?;
let mut state =
ConvertState::new(input, input_index, output, output_index);
if let Some(progress) = self.drain_pending(&mut state)? {
return Ok(progress);
}
while state.has_input() {
let previous_read = state.read();
if let Some(progress) = self.convert_next(&mut state)? {
return Ok(progress);
}
debug_assert!(
state.read() > previous_read,
"TranscodeConvertEngine conversion step must consume input or stop",
);
}
Ok(state.complete_progress())
}
pub fn finish(
&mut self,
output: &mut [E::Unit],
output_index: usize,
) -> Result<usize, ConvertErrorOf<D, E, H>>
where
D::Value: Default,
{
let required = self
.max_finish_output_len()
.map_err(|_| TranscodeError::OutputLengthOverflow)?;
TranscodeError::ensure_output_capacity(
output.len(),
output_index,
required,
)?;
let empty_input: &[D::Unit] = &[];
let mut state = ConvertState::new(empty_input, 0, output, output_index);
if self.drain_pending(&mut state)?.is_some() {
unreachable!(
"converter finish bound must reserve space for pending values"
);
}
self.drain_decoder_finish(&mut state)?;
let output_cursor = state.output_cursor();
let written = self
.encode_engine
.finish(state.output_mut(), output_cursor)
.map_err(|error| {
error.map_domain(|domain| self.hooks.map_encode_error(domain))
})?;
state.advance_output(written);
Ok(state.written())
}
pub fn reset(
&mut self,
output: &mut [E::Unit],
output_index: usize,
) -> Result<usize, ConvertErrorOf<D, E, H>> {
let required = self
.max_reset_output_len()
.map_err(|_| TranscodeError::OutputLengthOverflow)?;
TranscodeError::ensure_output_capacity(
output.len(),
output_index,
required,
)?;
self.pending.clear();
self.hooks.reset();
self.decode_engine.reset(&mut [], 0).map_err(|error| {
error.map_domain(|domain| self.hooks.map_decode_error(domain))
})?;
self.encode_engine
.reset(output, output_index)
.map_err(|error| {
error.map_domain(|domain| self.hooks.map_encode_error(domain))
})
}
#[inline(always)]
fn convert_next(
&mut self,
state: &mut ConvertState<'_, D::Unit, E::Unit>,
) -> ConvertStepResult<D, E, H> {
let step = self
.decode_engine
.decode_step(state.input(), state.decode_context())
.map_err(|error| {
error.map_domain(|domain| self.hooks.map_decode_error(domain))
})?;
step.apply_to_convert_state(state, |pending, state| {
self.encode_pending(pending, state)
})
}
#[inline(always)]
fn pending_output_len(&self) -> Result<usize, CapacityError> {
self.pending.max_output_len(&self.encode_engine)
}
#[inline(always)]
fn drain_pending(
&mut self,
state: &mut ConvertState<'_, D::Unit, E::Unit>,
) -> ConvertStepResult<D, E, H> {
let Some(pending) = self.pending.take() else {
return Ok(None);
};
self.encode_pending(pending, state)
}
fn drain_decoder_finish(
&mut self,
state: &mut ConvertState<'_, D::Unit, E::Unit>,
) -> Result<(), ConvertErrorOf<D, E, H>>
where
D::Value: Default,
{
let value_count = self
.decode_engine
.max_finish_output_len()
.map_err(|_| TranscodeError::OutputLengthOverflow)?;
let mut decoded: Vec<D::Value> =
(0..value_count).map(|_| D::Value::default()).collect();
let written =
self.decode_engine
.finish(&mut decoded, 0)
.map_err(|error| {
error.map_domain(|domain| {
self.hooks.map_decode_error(domain)
})
})?;
for value in decoded.into_iter().take(written) {
let pending = PendingValue::new(value, 0);
if self.encode_pending(pending, state)?.is_some() {
unreachable!(
"converter finish bound must reserve space for decode finish values"
);
}
}
Ok(())
}
fn encode_pending(
&mut self,
pending: PendingValue<D::Value>,
state: &mut ConvertState<'_, D::Unit, E::Unit>,
) -> ConvertStepResult<D, E, H> {
let input_index = pending.input_index();
let output_index = state.output_cursor();
let context = EncodeContext {
input_value: pending.value(),
input_index,
output: state.output_mut(),
output_index,
};
let step =
self.encode_engine.encode_step(context).map_err(|error| {
error.map_domain(|domain| self.hooks.map_encode_error(domain))
})?;
let step = match step {
EncodeStep::Written { written } => {
PendingEncodeStep::written(written)
}
EncodeStep::NeedOutput {
additional,
available,
} => PendingEncodeStep::need_output(pending, additional, available),
};
Ok(self.pending.apply_pending_encode_step(step, state))
}
}
impl<D, E, H> Default for TranscodeConvertEngine<D, E, H>
where
D: Codec + Default,
E: Codec<Value = D::Value> + Default,
H: TranscodeConvertHooks<D, E> + Default,
{
#[inline(always)]
fn default() -> Self {
Self::new(D::default(), E::default(), H::default())
}
}