use core::num::NonZeroUsize;
use super::super::{
decode_context::DecodeContext,
encode_outcome::EncodeOutcome,
transcode_progress::TranscodeProgress,
};
use super::transcode_state::TranscodeState;
use super::{
decode_step::DecodeStep,
pending_value::PendingValue,
};
pub(crate) struct ConvertState<'a, Input, Output> {
state: TranscodeState<'a, Input, Output>,
}
impl<'a, Input, Output> ConvertState<'a, Input, Output> {
#[inline(always)]
#[must_use]
pub(crate) fn new(
input: &'a [Input],
input_index: usize,
output: &'a mut [Output],
output_index: usize,
) -> Self {
Self {
state: TranscodeState::new(
input,
input_index,
output,
output_index,
),
}
}
#[inline(always)]
#[must_use]
pub(crate) fn input(&self) -> &[Input] {
self.state.input()
}
#[inline(always)]
pub(crate) fn output_mut(&mut self) -> &mut [Output] {
self.state.output_mut()
}
#[inline(always)]
#[must_use]
pub(crate) fn output_cursor(&self) -> usize {
self.state.output_cursor()
}
#[inline(always)]
#[must_use]
pub(crate) fn has_input(&self) -> bool {
self.state.has_input()
}
#[inline(always)]
#[must_use]
pub(crate) fn available_input(&self) -> usize {
self.state.available_input()
}
#[inline(always)]
#[must_use]
pub(crate) fn available_output(&self) -> usize {
self.state.available_output()
}
#[inline(always)]
#[must_use]
pub(crate) fn decode_context(&self) -> DecodeContext {
DecodeContext::new(
self.state.input_start(),
self.state.input_cursor(),
self.state.output_start(),
self.state.output_cursor(),
self.available_input(),
)
}
#[inline(always)]
pub(crate) fn advance_input(&mut self, read: usize) {
assert!(
read <= self.available_input(),
"conversion step read beyond input"
);
self.state.advance_input(read);
}
#[inline(always)]
pub(crate) fn advance_output(&mut self, written: usize) {
assert!(
written <= self.available_output(),
"conversion step wrote beyond output",
);
self.state.advance_output(written);
}
#[inline(always)]
#[must_use]
pub(crate) fn read(&self) -> usize {
self.state.read()
}
#[inline(always)]
#[must_use]
pub(crate) fn written(&self) -> usize {
self.state.written()
}
#[inline(always)]
#[must_use]
pub(crate) fn complete_progress(&self) -> TranscodeProgress {
self.state.complete_progress()
}
#[inline(always)]
#[must_use]
pub(crate) fn need_input_progress(
&self,
required: NonZeroUsize,
available: usize,
) -> TranscodeProgress {
self.state.need_input_progress(required, available)
}
#[inline(always)]
#[must_use]
pub(crate) fn need_output_progress(
&self,
required: NonZeroUsize,
available: usize,
) -> TranscodeProgress {
self.state.need_output_progress(required, available)
}
#[inline]
pub(crate) fn apply_decode_step<Value, Error, F>(
&mut self,
step: DecodeStep<Value>,
mut encode: F,
) -> Result<Option<TranscodeProgress>, Error>
where
F: FnMut(
PendingValue<Value>,
&mut ConvertState<'_, Input, Output>,
) -> Result<Option<TranscodeProgress>, Error>,
{
match step {
DecodeStep::Decoded {
value,
consumed,
input_index,
} => {
self.advance_input(consumed.get());
encode(PendingValue::new(value, input_index), self)
}
DecodeStep::Skipped { consumed } => {
self.advance_input(consumed.get());
Ok(None)
}
DecodeStep::NeedInput {
required,
available,
} => Ok(Some(self.need_input_progress(required, available))),
}
}
#[inline]
#[must_use]
pub(crate) fn apply_encode_outcome(
&mut self,
outcome: EncodeOutcome,
) -> Option<TranscodeProgress> {
match outcome {
EncodeOutcome::Consumed { written } => {
self.advance_output(written);
None
}
EncodeOutcome::NeedOutput { required } => {
let available = self.available_output();
assert!(
required.get() > available,
"EncodeOutcome::NeedOutput required capacity must exceed available output",
);
Some(self.need_output_progress(required, available))
}
}
}
}