use core::num::NonZeroUsize;
use super::super::TranscodeContractError;
use super::super::TranscodeStatus;
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
#[must_use]
pub struct TranscodeProgress {
status: TranscodeStatus,
read: usize,
written: usize,
}
impl TranscodeProgress {
#[inline]
pub const fn new(status: TranscodeStatus, read: usize, written: usize) -> Self {
Self { status, read, written }
}
#[inline]
pub const fn complete(read: usize, written: usize) -> Self {
Self::new(TranscodeStatus::Complete, read, written)
}
#[inline]
pub const fn need_input(required: NonZeroUsize, read: usize, written: usize) -> Self {
Self::new(TranscodeStatus::need_input(required), read, written)
}
#[inline]
pub const fn need_output(required: NonZeroUsize, read: usize, written: usize) -> Self {
Self::new(TranscodeStatus::need_output(required), read, written)
}
#[inline]
pub const fn status(self) -> TranscodeStatus {
self.status
}
#[inline]
#[must_use]
pub const fn is_complete(self) -> bool {
matches!(self.status, TranscodeStatus::Complete)
}
#[inline]
#[must_use]
pub const fn is_need_input(self) -> bool {
matches!(self.status, TranscodeStatus::NeedInput { .. })
}
#[inline]
#[must_use]
pub const fn is_need_output(self) -> bool {
matches!(self.status, TranscodeStatus::NeedOutput { .. })
}
#[inline]
#[must_use]
pub const fn read(self) -> usize {
self.read
}
#[inline]
#[must_use]
pub const fn written(self) -> usize {
self.written
}
pub fn validate(
&self,
input_index: usize,
available_input: usize,
output_index: usize,
available_output: usize,
) -> Result<(), TranscodeContractError> {
if self.read > available_input {
return Err(TranscodeContractError::OverRead {
read: self.read,
available: available_input,
});
}
if self.written > available_output {
return Err(TranscodeContractError::OverWritten {
written: self.written,
available: available_output,
});
}
input_index
.checked_add(self.read)
.ok_or(TranscodeContractError::ProgressIndexOverflow {
index: input_index,
advanced: self.read,
})?;
output_index
.checked_add(self.written)
.ok_or(TranscodeContractError::ProgressIndexOverflow {
index: output_index,
advanced: self.written,
})?;
match self.status {
TranscodeStatus::Complete => {
if self.read != available_input {
return Err(TranscodeContractError::CompleteWithRemainingInput {
read: self.read,
available: available_input,
});
}
Ok(())
}
TranscodeStatus::NeedInput { required } => {
let available = available_input - self.read;
if required.get() <= available {
return Err(TranscodeContractError::SatisfiedNeed {
required: required.get(),
available,
});
}
Ok(())
}
TranscodeStatus::NeedOutput { required } => {
let available = available_output - self.written;
if required.get() <= available {
return Err(TranscodeContractError::SatisfiedNeed {
required: required.get(),
available,
});
}
Ok(())
}
}
}
}