use crate::CapacityError;
use crate::Codec;
use crate::TranscodeDecodeError;
use crate::TranscodeDecodeErrorOf;
use crate::TranscodeEncodeError;
use crate::TranscodeEncodeErrorOf;
use crate::TranscodeFailure;
use crate::codec::assert_unit_bounds;
#[inline]
pub(crate) fn max_complete_encode_units<C>() -> Result<usize, CapacityError>
where
C: Codec,
{
assert_unit_bounds::<C>();
C::MAX_ENCODE_RESET_UNITS
.checked_add(C::MAX_ENCODE_UNITS_PER_VALUE)
.and_then(|units| units.checked_add(C::MAX_ENCODE_FINISH_UNITS))
.ok_or(CapacityError::OutputLengthOverflow)
}
pub(crate) fn encode_complete_value_into_reserved<C>(
codec: &mut C,
value: &C::Value,
output: &mut [C::Unit],
output_index: usize,
reserved: usize,
) -> Result<usize, TranscodeEncodeErrorOf<C>>
where
C: Codec,
{
assert!(
output
.len()
.checked_sub(output_index)
.is_some_and(|available| available >= reserved),
"complete encode output was not reserved",
);
let reset_written = unsafe {
codec.encode_reset(output, output_index)
}
.map_err(TranscodeEncodeError::domain_reset)?;
assert!(
reset_written <= C::MAX_ENCODE_RESET_UNITS,
"Codec::encode_reset wrote beyond its reset bound",
);
if !codec.can_encode_value(value) {
return Err(TranscodeEncodeError::unencodable_without_context(0));
}
let value_units = codec.encode_len(value);
assert!(
value_units <= C::MAX_ENCODE_UNITS_PER_VALUE,
"Codec::encode_len exceeded Codec::MAX_ENCODE_UNITS_PER_VALUE",
);
let value_and_finish = value_units
.checked_add(C::MAX_ENCODE_FINISH_UNITS)
.ok_or(CapacityError::OutputLengthOverflow)?;
let value_index = output_index + reset_written;
TranscodeFailure::ensure_output_capacity(output.len(), value_index, value_and_finish)?;
let value_written = unsafe {
codec.encode(value, output, value_index)
}
.map_err(|error| TranscodeEncodeError::domain_main(error, 0))?;
assert!(
value_written == value_units,
"Codec::encode wrote a different length than Codec::encode_len",
);
let finish_index = value_index + value_written;
let finish_written = unsafe {
codec.encode_finish(output, finish_index)
}
.map_err(TranscodeEncodeError::domain_finish)?;
assert!(
finish_written <= C::MAX_ENCODE_FINISH_UNITS,
"Codec::encode_finish wrote beyond its finish bound",
);
Ok(reset_written + value_written + finish_written)
}
pub(crate) fn decode_exact_complete_value<C>(
codec: &mut C,
input: &[C::Unit],
reset_output: &mut [C::Value],
finish_output: &mut [C::Value],
) -> Result<(C::Value, usize, usize), TranscodeDecodeErrorOf<C>>
where
C: Codec,
{
assert_unit_bounds::<C>();
TranscodeFailure::ensure_output_capacity(reset_output.len(), 0, C::MAX_DECODE_RESET_VALUES)?;
TranscodeFailure::ensure_output_capacity(finish_output.len(), 0, C::MAX_DECODE_FINISH_VALUES)?;
let reset_written = unsafe {
codec.decode_reset(reset_output, 0)
}
.map_err(TranscodeDecodeError::domain_reset)?;
assert!(
reset_written <= C::MAX_DECODE_RESET_VALUES,
"Codec::decode_reset wrote beyond its reset bound",
);
TranscodeFailure::ensure_min_input(input.len(), 0, C::MIN_UNITS_PER_VALUE)?;
let (value, consumed) = unsafe {
codec.decode_eof(input, 0)
}
.map_err(|failure| TranscodeDecodeError::from_decode_failure(failure, 0, input.len()))?;
assert!(
consumed.get() <= input.len(),
"Codec::decode consumed beyond available input",
);
assert!(
consumed.get() <= C::MAX_DECODE_UNITS_PER_VALUE,
"Codec::decode consumed beyond Codec::MAX_DECODE_UNITS_PER_VALUE",
);
TranscodeFailure::ensure_no_trailing_input(consumed.get(), input.len())?;
let finish_written = unsafe {
codec.decode_finish(finish_output, 0)
}
.map_err(TranscodeDecodeError::domain_finish)?;
assert!(
finish_written <= C::MAX_DECODE_FINISH_VALUES,
"Codec::decode_finish wrote beyond its finish bound",
);
Ok((value, reset_written, finish_written))
}