use thiserror::Error;
#[derive(Clone, Copy, Debug, Eq, Error, Hash, PartialEq)]
pub enum CodecDecodeError<E> {
#[error("codec decode error at input index {input_index}: {source}")]
Decode {
#[source]
source: E,
input_index: usize,
},
#[error("codec decode reset error: {source}")]
DecodeReset {
#[source]
source: E,
},
#[error("codec decode flush error: {source}")]
DecodeFlush {
#[source]
source: E,
},
#[error(
"incomplete input at index {input_index}: required {required_total} units, available {available}"
)]
Incomplete {
input_index: usize,
required_total: usize,
available: usize,
},
#[error(
"trailing input after decoded value: consumed {consumed} units, remaining {remaining}"
)]
TrailingInput {
consumed: usize,
remaining: usize,
},
}
impl<E> CodecDecodeError<E> {
#[inline(always)]
#[must_use]
pub const fn decode(source: E, input_index: usize) -> Self {
Self::Decode {
source,
input_index,
}
}
#[inline(always)]
#[must_use]
pub const fn decode_reset(source: E) -> Self {
Self::DecodeReset { source }
}
#[inline(always)]
#[must_use]
pub const fn decode_flush(source: E) -> Self {
Self::DecodeFlush { source }
}
#[inline(always)]
#[must_use]
pub const fn incomplete(
input_index: usize,
required_total: usize,
available: usize,
) -> Self {
Self::Incomplete {
input_index,
required_total,
available,
}
}
#[inline(always)]
#[must_use]
pub const fn trailing_input(consumed: usize, remaining: usize) -> Self {
Self::TrailingInput {
consumed,
remaining,
}
}
#[inline(always)]
#[must_use]
pub fn into_source(self) -> Option<E> {
match self {
Self::Decode { source, .. }
| Self::DecodeReset { source }
| Self::DecodeFlush { source } => Some(source),
Self::Incomplete { .. } | Self::TrailingInput { .. } => None,
}
}
#[inline(always)]
#[must_use]
pub const fn is_incomplete(&self) -> bool {
matches!(self, Self::Incomplete { .. })
}
#[inline]
#[must_use]
pub fn needed_additional(&self) -> Option<core::num::NonZeroUsize> {
match *self {
Self::Incomplete {
required_total,
available,
..
} => {
let needed = required_total.saturating_sub(available);
core::num::NonZeroUsize::new(needed)
}
_ => None,
}
}
#[inline]
pub fn ensure_min_input(
input_len: usize,
input_index: usize,
min_required: usize,
) -> Result<(), Self> {
let available = input_len.saturating_sub(input_index);
if available < min_required {
return Err(Self::incomplete(input_index, min_required, available));
}
Ok(())
}
#[inline]
pub fn ensure_no_trailing_input(
consumed: usize,
total: usize,
) -> Result<(), Self> {
let remaining = total.saturating_sub(consumed);
if remaining != 0 {
return Err(Self::trailing_input(consumed, remaining));
}
Ok(())
}
}