use super::DropSliceMetadata;
use crate::authorisation::{PossiblyAuthorisedEntry, PriorAuthedEntryEntryPair};
use crate::defaults::default_authorised_entry;
use crate::is_bitflagged;
use crate::prelude::*;
use alloc::rc::Rc;
use bab_rs::{CHUNK_SIZE, generic::storage::units::optimal_left_skip};
use compact_u64::{cu64_decode, cu64_decode_standalone};
use frugal_async::TakeCell;
use ufotofu::{ProduceLimitError, codec_prelude::*, producer::Limit};
pub struct DropDecoder<P>
where
P: BulkProducer<Item = u8>,
{
drop_bytes: Rc<TakeCell<Option<P>>>,
entry_state: Option<AuthorisedEntry>,
chunk_offset: u64,
}
#[must_use = "A DropDecoder which produces a SliceStreamProducer cannot make progress until the SliceStreamProducer is completely consumed."]
pub struct SliceStreamProducer<P>
where
P: BulkProducer<Item = u8>,
{
slice_bytes: Option<Limit<P>>,
return_slot: Rc<TakeCell<Option<P>>>,
}
impl<P: BulkProducer<Item = u8>> SliceStreamProducer<P> {
#[cfg(feature = "dev")]
#[doc(hidden)]
pub fn new(inner: Limit<P>) -> Self {
SliceStreamProducer {
slice_bytes: Some(inner),
return_slot: Rc::new(TakeCell::new()),
}
}
}
impl<P> DropDecoder<P>
where
P: BulkProducer<Item = u8>,
{
pub fn new(drop_producer: P) -> Self {
Self {
drop_bytes: Rc::new(TakeCell::new_with(Some(drop_producer))),
entry_state: None,
chunk_offset: 0,
}
}
}
impl<P> From<P> for DropDecoder<P>
where
P: BulkProducer<Item = u8>,
{
fn from(value: P) -> Self {
DropDecoder::new(value)
}
}
impl<P> Producer for DropDecoder<P>
where
P: BulkProducer<Item = u8, Final = ()>,
{
type Item = (DropSliceMetadata, SliceStreamProducer<P>);
type Final = ();
type Error = DecodeError<(), P::Error, Blame>;
async fn produce(&mut self) -> Result<Either<Self::Item, Self::Final>, Self::Error> {
let Some(mut bytes) = self.drop_bytes.take().await else {
return Err(DecodeError::UnexpectedEndOfInput(()));
};
let header = match bytes.produce().await.map_err(DecodeError::ProducerError)? {
Left(0u8) => {
return Ok(Right(()));
}
Left(header) => header,
Right(_) => {
return Err(DecodeError::UnexpectedEndOfInput(()));
}
};
if header & 0b1100_0000 == 0b0100_0000 {
let entry_state = self
.entry_state
.take()
.unwrap_or_else(default_authorised_entry);
self.chunk_offset = 0;
let namespace_is_encoded = is_bitflagged(header, 2);
let subspace_is_encoded = is_bitflagged(header, 3);
let namespace_id = if namespace_is_encoded {
NamespaceId::decode(&mut bytes)
.await
.map_err(|err| err.map_other(|_infallbile| unreachable!()))?
} else {
entry_state.namespace_id().clone()
};
let subspace_id = if subspace_is_encoded {
SubspaceId::decode(&mut bytes)
.await
.map_err(|err| err.map_other(|_infallbile| unreachable!()))?
} else {
entry_state.subspace_id().clone()
};
let path = Path::relative_decode(entry_state.path(), &mut bytes).await?;
let timestamp = cu64_decode(header, 2, 4, &mut bytes)
.await
.map_err(|err| err.map_other(|_infallbile| unreachable!()))?;
let payload_length = cu64_decode_standalone(&mut bytes)
.await
.map_err(|err| err.map_other(|_infallbile| unreachable!()))?;
let payload_digest = PayloadDigest::decode(&mut bytes)
.await
.map_err(|err| err.map_other(|_infallbile| unreachable!()))?;
let entry = Entry::builder()
.namespace_id(namespace_id)
.subspace_id(subspace_id)
.path(path)
.timestamp(timestamp)
.payload_length(payload_length)
.payload_digest(payload_digest)
.build();
let pair = PriorAuthedEntryEntryPair::new(entry_state.clone(), entry);
let auth_token = AuthorisationToken::relative_decode(&pair, &mut bytes).await?;
let (_, entry) = pair.into_parts();
let decoded_authed_entry = PossiblyAuthorisedEntry::new(entry, auth_token)
.into_authorised_entry()
.map_err(|_| DecodeError::Other(Blame::TheirFault))?;
self.entry_state = Some(decoded_authed_entry.clone());
}
let entry_state = self
.entry_state
.take()
.ok_or(DecodeError::Other(Blame::TheirFault))?;
let payload_length = entry_state.payload_length();
let max_chunks = payload_length.div_ceil(CHUNK_SIZE as u64);
let (chunk_count, left_skip, is_multislice) = match header & 0b0000_0011 {
0b0000_0000 => (0, 0, false),
0b0000_0001 => (max_chunks, 0, false),
0b0000_0010 => {
let prefix_chunks = cu64_decode_standalone(&mut bytes)
.await
.map_err(|err| err.map_other(|_infallbile| unreachable!()))?;
(prefix_chunks, 0, false)
}
0b0000_0011 => {
match bytes
.peek(async |&next| is_bitflagged(next, 0))
.await
.map_err(DecodeError::ProducerError)?
{
Left(true) => {
let Left(slice_header) =
bytes.produce().await.map_err(DecodeError::ProducerError)?
else {
return Err(DecodeError::UnexpectedEndOfInput(()));
};
let prior_end = self.chunk_offset;
self.chunk_offset += cu64_decode(slice_header, 3, 1, &mut bytes)
.await
.map_err(|err| err.map_other(|_infallbile| unreachable!()))?;
let chunk_count = cu64_decode(slice_header, 4, 4, &mut bytes)
.await
.map_err(|err| err.map_other(|_infallbile| unreachable!()))?;
let left_skip =
optimal_left_skip(chunk_count, prior_end, self.chunk_offset);
(chunk_count, left_skip, true)
}
Left(false) => (0, 0, true), _ => return Err(DecodeError::UnexpectedEndOfInput(())),
}
}
_ => unreachable!(),
};
let metadata = DropSliceMetadata::new(
entry_state.clone(),
self.chunk_offset,
chunk_count,
left_skip,
is_multislice,
)
.map_err(|_| DecodeError::Other(Blame::TheirFault))?;
let payload = SliceStreamProducer {
slice_bytes: Some(
bytes.to_limit(
metadata
.expected_bytes()
.try_into()
.map_err(|_| DecodeError::Other(Blame::OurFault))?,
),
),
return_slot: Rc::clone(&self.drop_bytes),
};
self.chunk_offset += chunk_count;
self.entry_state = Some(entry_state);
Ok(Left((metadata, payload)))
}
async fn slurp(&mut self) -> Result<(), Self::Error> {
let Some(mut bytes) = self.drop_bytes.take().await else {
return Err(DecodeError::UnexpectedEndOfInput(()));
};
match bytes.slurp().await {
Ok(()) => self.drop_bytes.set(Some(bytes)),
Err(err) => {
self.drop_bytes.set(None);
return Err(DecodeError::ProducerError(err));
}
}
Ok(())
}
}
impl<P> Producer for SliceStreamProducer<P>
where
P: BulkProducer<Item = u8>,
{
type Item = P::Item;
type Final = ();
type Error = DecodeError<(), P::Error, Blame>;
async fn produce(&mut self) -> Result<Either<Self::Item, Self::Final>, Self::Error> {
let mut bytes = self.slice_bytes.take().expect(
"produce must not be called on a producer which has emitted an error or a final value",
);
match bytes.produce().await {
Ok(Left(byte)) => {
self.slice_bytes = Some(bytes);
Ok(Left(byte))
}
Ok(Right(_)) => {
self.return_slot.set(None);
Err(DecodeError::UnexpectedEndOfInput(()))
}
Err(err) => match err {
ProduceLimitError::Inner(err) => {
self.return_slot.set(None);
Err(DecodeError::ProducerError(err))
}
ProduceLimitError::LimitReached => {
self.return_slot.set(Some(bytes.into_inner()));
Ok(Right(()))
}
},
}
}
async fn slurp(&mut self) -> Result<(), Self::Error> {
let mut bytes = self.slice_bytes.take().expect(
"slurp must not be called on a producer which has emitted an error or a final value",
);
match bytes.slurp().await {
Ok(()) => {
self.slice_bytes = Some(bytes);
Ok(())
}
Err(err) => match err {
ProduceLimitError::Inner(err) => {
self.return_slot.set(None);
Err(DecodeError::ProducerError(err))
}
ProduceLimitError::LimitReached => unreachable!(
"slurping on a limit producer should never cause the limit to be reached"
),
},
}
}
}
impl<P> BulkProducer for SliceStreamProducer<P>
where
P: BulkProducer<Item = u8>,
{
async fn expose_items_gracefully<F, R>(
&mut self,
f: F,
) -> Result<Either<R, (F, Self::Final)>, (F, Self::Error)>
where
F: AsyncFnOnce(&[Self::Item]) -> (usize, R),
{
let mut bytes = self.slice_bytes.take().expect("producer methods must not be called on a producer which has emitted an error or a final value");
match bytes.expose_items_gracefully(f).await {
Ok(Left(returned)) => {
self.slice_bytes = Some(bytes);
Ok(Left(returned))
}
Ok(Right((f, _))) => {
self.return_slot.set(None);
Err((f, DecodeError::UnexpectedEndOfInput(())))
}
Err((f, err)) => match err {
ProduceLimitError::Inner(err) => {
self.return_slot.set(None);
Err((f, DecodeError::ProducerError(err)))
}
ProduceLimitError::LimitReached => {
self.return_slot.set(Some(bytes.into_inner()));
Ok(Right((f, ())))
}
},
}
}
}