use core::num::NonZeroUsize;
use crate::{
CapacityError,
Codec,
CodecDecodeError,
CodecEncodeError,
};
pub trait CodecValueExt: Codec {
#[inline(always)]
#[must_use = "capacity planning can fail on overflow"]
fn max_encode_value_units(&self) -> Result<usize, CapacityError> {
self.max_encode_reset_units()
.checked_add(self.max_units_per_value().get())
.ok_or(CapacityError::OutputLengthOverflow)
}
fn encode_value_with_reset(
&mut self,
value: &Self::Value,
output: &mut [Self::Unit],
output_index: usize,
) -> Result<usize, CodecEncodeError<Self::EncodeError>> {
if !self.can_encode_value(value) {
return Err(CodecEncodeError::unencodable_value(0));
}
let reset_units = self.max_encode_reset_units();
let value_units = self.encode_len(value).get();
let required = reset_units
.checked_add(value_units)
.ok_or_else(CodecEncodeError::output_length_overflow)?;
CodecEncodeError::ensure_output_capacity(
output.len(),
output_index,
required,
)?;
let reset_written = unsafe {
self.encode_reset(output, output_index)
}
.map_err(|error| CodecEncodeError::encode(error, 0))?;
assert!(
reset_written <= reset_units,
"Codec::encode_reset wrote beyond its reset bound",
);
let value_written = unsafe {
self.encode(value, output, output_index + reset_written)
}
.map_err(|error| CodecEncodeError::encode(error, 0))?
.get();
assert!(
value_written == value_units,
"Codec::encode wrote a different length than Codec::encode_len",
);
Ok(reset_written + value_written)
}
fn decode_value_with_flush(
&mut self,
input: &[Self::Unit],
input_index: usize,
flush_output: &mut [Self::Value],
flush_output_index: usize,
) -> Result<
(Self::Value, NonZeroUsize, usize),
CodecDecodeError<Self::DecodeError>,
> {
CodecDecodeError::ensure_input_index(input.len(), input_index)?;
let min_units = self.min_units_per_value().get();
CodecDecodeError::ensure_min_input(
input.len(),
input_index,
min_units,
)?;
let flush_cap = self.max_decode_flush_values();
CodecDecodeError::ensure_output_capacity(
flush_output.len(),
flush_output_index,
flush_cap,
)?;
let (value, consumed) = unsafe {
self.decode(input, input_index)
}
.map_err(|error| CodecDecodeError::decode(error, input_index))?;
let available = input.len() - input_index;
assert!(
consumed.get() <= available,
"Codec::decode consumed beyond available input",
);
let flushed = unsafe {
self.decode_flush(flush_output, flush_output_index)
}
.map_err(|error| {
CodecDecodeError::decode(error, input_index + consumed.get())
})?;
assert!(
flushed <= flush_cap,
"Codec::decode_flush wrote beyond its flush bound",
);
Ok((value, consumed, flushed))
}
fn decode_exact_value_with_flush(
&mut self,
input: &[Self::Unit],
flush_output: &mut [Self::Value],
flush_output_index: usize,
) -> Result<(Self::Value, usize), CodecDecodeError<Self::DecodeError>> {
let min_units = self.min_units_per_value().get();
CodecDecodeError::ensure_min_input(input.len(), 0, min_units)?;
let flush_cap = self.max_decode_flush_values();
CodecDecodeError::ensure_output_capacity(
flush_output.len(),
flush_output_index,
flush_cap,
)?;
let (value, consumed) = unsafe {
self.decode(input, 0)
}
.map_err(|error| CodecDecodeError::decode(error, 0))?;
assert!(
consumed.get() <= input.len(),
"Codec::decode consumed beyond available input",
);
CodecDecodeError::ensure_no_trailing_input(
consumed.get(),
input.len(),
)?;
let flushed = unsafe {
self.decode_flush(flush_output, flush_output_index)
}
.map_err(|error| CodecDecodeError::decode(error, consumed.get()))?;
assert!(
flushed <= flush_cap,
"Codec::decode_flush wrote beyond its flush bound",
);
Ok((value, flushed))
}
}
impl<C> CodecValueExt for C where C: Codec + ?Sized {}