use core::fmt;
#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)]
pub enum TranscodeError<E> {
InvalidInputIndex {
index: usize,
len: usize,
},
InvalidOutputIndex {
index: usize,
len: usize,
},
InsufficientOutput {
output_index: usize,
required: usize,
available: usize,
},
OutputLengthOverflow,
Domain(E),
}
impl<E> TranscodeError<E> {
#[inline(always)]
pub const fn domain(error: E) -> Self {
Self::Domain(error)
}
#[inline(always)]
pub const fn invalid_input_index(index: usize, len: usize) -> Self {
Self::InvalidInputIndex { index, len }
}
#[inline(always)]
pub const fn invalid_output_index(index: usize, len: usize) -> Self {
Self::InvalidOutputIndex { index, len }
}
#[inline(always)]
pub const fn insufficient_output(
output_index: usize,
required: usize,
available: usize,
) -> Self {
Self::InsufficientOutput {
output_index,
required,
available,
}
}
#[must_use]
#[inline(always)]
pub const fn is_domain(&self) -> bool {
matches!(self, Self::Domain(_))
}
#[must_use]
#[inline(always)]
pub const fn domain_ref(&self) -> Option<&E> {
match self {
Self::Domain(error) => Some(error),
_ => None,
}
}
#[inline]
pub fn map_domain<F, T>(self, f: F) -> TranscodeError<T>
where
F: FnOnce(E) -> T,
{
match self {
Self::InvalidInputIndex { index, len } => {
TranscodeError::InvalidInputIndex { index, len }
}
Self::InvalidOutputIndex { index, len } => {
TranscodeError::InvalidOutputIndex { index, len }
}
Self::InsufficientOutput {
output_index,
required,
available,
} => TranscodeError::InsufficientOutput {
output_index,
required,
available,
},
Self::OutputLengthOverflow => TranscodeError::OutputLengthOverflow,
Self::Domain(error) => TranscodeError::Domain(f(error)),
}
}
#[inline]
pub fn ensure_input_index(
input_len: usize,
input_index: usize,
) -> Result<(), Self> {
if input_index > input_len {
return Err(Self::invalid_input_index(input_index, input_len));
}
Ok(())
}
#[inline]
pub fn ensure_output_index(
output_len: usize,
output_index: usize,
) -> Result<(), Self> {
if output_index > output_len {
return Err(Self::invalid_output_index(output_index, output_len));
}
Ok(())
}
#[inline]
pub fn ensure_transcode_indices(
input_len: usize,
input_index: usize,
output_len: usize,
output_index: usize,
) -> Result<(), Self> {
Self::ensure_input_index(input_len, input_index)?;
Self::ensure_output_index(output_len, output_index)
}
#[inline]
pub fn ensure_output_capacity(
output_len: usize,
output_index: usize,
required: usize,
) -> Result<(), Self> {
Self::ensure_output_index(output_len, output_index)?;
let available = output_len - output_index;
if available < required {
return Err(Self::insufficient_output(
output_index,
required,
available,
));
}
Ok(())
}
#[inline]
pub fn ensure_output_range(
output_len: usize,
output_index: usize,
range_len: usize,
required: usize,
) -> Result<(), Self> {
Self::ensure_output_index(output_len, output_index)?;
if !qubit_io::UncheckedSlice::range_fits(
output_len,
output_index,
range_len,
) {
return Err(Self::invalid_output_index(output_index, output_len));
}
if range_len < required {
return Err(Self::insufficient_output(
output_index,
required,
range_len,
));
}
Ok(())
}
}
impl<E> From<E> for TranscodeError<E> {
#[inline(always)]
fn from(error: E) -> Self {
Self::Domain(error)
}
}
impl<E> fmt::Display for TranscodeError<E>
where
E: fmt::Display,
{
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::InvalidInputIndex { index, len } => {
write!(f, "invalid input index {index}; input length is {len}")
}
Self::InvalidOutputIndex { index, len } => {
write!(
f,
"invalid output index {index}; output length is {len}"
)
}
Self::InsufficientOutput {
output_index,
required,
available,
} => write!(
f,
"insufficient output at index {output_index}; required {required}, available {available}"
),
Self::OutputLengthOverflow => {
f.write_str("output length arithmetic overflow")
}
Self::Domain(error) => error.fmt(f),
}
}
}
impl<E> std::error::Error for TranscodeError<E>
where
E: std::error::Error + 'static,
{
#[inline(always)]
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
match self {
Self::Domain(error) => Some(error),
_ => None,
}
}
}