use crate::paths::{Path, path_extends_path};
#[cfg(feature = "dev")]
use arbitrary::Arbitrary;
use compact_u64::{cu64_decode_standalone, cu64_encode_standalone};
use derive_more::{Display, Error};
use ufotofu::{
codec::{Blame, DecodeError},
codec_prelude::RelativeDecodable,
codec_relative::RelativeEncodable,
};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
pub struct PrivatePathContext<const MCL: usize, const MCC: usize, const MPL: usize> {
private: Path<MCL, MCC, MPL>,
rel: Path<MCL, MCC, MPL>,
}
#[derive(Debug, Display, Error, Clone, Copy)]
#[display("private and relative paths are not related")]
pub struct ComponentsNotRelatedError;
impl<const MCL: usize, const MCC: usize, const MPL: usize> PrivatePathContext<MCL, MCC, MPL> {
pub fn new(
private: Path<MCL, MCC, MPL>,
rel: Path<MCL, MCC, MPL>,
) -> Result<Self, ComponentsNotRelatedError> {
if !private.is_related_to(&rel) {
return Err(ComponentsNotRelatedError {});
}
Ok(Self { private, rel })
}
pub unsafe fn new_unchecked(private: Path<MCL, MCC, MPL>, rel: Path<MCL, MCC, MPL>) -> Self {
Self { private, rel }
}
pub fn private(&self) -> &Path<MCL, MCC, MPL> {
&self.private
}
pub fn rel(&self) -> &Path<MCL, MCC, MPL> {
&self.rel
}
}
#[cfg(feature = "dev")]
impl<'a, const MCL: usize, const MCC: usize, const MPL: usize> Arbitrary<'a>
for PrivatePathContext<MCL, MCC, MPL>
{
fn arbitrary(u: &mut arbitrary::Unstructured<'a>) -> arbitrary::Result<Self> {
let private: Path<MCL, MCC, MPL> = Arbitrary::arbitrary(u)?;
let rel: Path<MCL, MCC, MPL> = Arbitrary::arbitrary(u)?;
if !private.is_related_to(&rel) {
return Err(arbitrary::Error::IncorrectFormat);
}
Ok(Self { private, rel })
}
}
impl<const MCL: usize, const MCC: usize, const MPL: usize>
RelativeEncodable<PrivatePathContext<MCL, MCC, MPL>> for Path<MCL, MCC, MPL>
{
async fn relative_encode<C>(
&self,
rel: &PrivatePathContext<MCL, MCC, MPL>,
consumer: &mut C,
) -> Result<(), C::Error>
where
C: ufotofu::BulkConsumer<Item = u8> + ?Sized,
{
let rel_count = rel.rel.component_count();
let private_count = rel.private.component_count();
if private_count <= rel_count {
path_extends_path::encode_path_extends_path(self, &rel.rel, consumer).await?;
} else {
let lcp = self.longest_common_prefix(&rel.private);
let lcp_len = lcp.component_count();
cu64_encode_standalone(lcp_len as u64, consumer).await?;
if lcp_len >= private_count {
path_extends_path::encode_path_extends_path(self, rel.private(), consumer).await?;
}
}
Ok(())
}
fn can_be_encoded_relative_to(&self, rel: &PrivatePathContext<MCL, MCC, MPL>) -> bool {
if !rel.rel().is_prefix_of(self) {
return false;
}
if !self.is_related_to(rel.private()) {
return false;
}
true
}
}
impl<const MCL: usize, const MCC: usize, const MPL: usize>
RelativeDecodable<PrivatePathContext<MCL, MCC, MPL>> for Path<MCL, MCC, MPL>
{
type ErrorReason = Blame;
async fn relative_decode<P>(
rel: &PrivatePathContext<MCL, MCC, MPL>,
producer: &mut P,
) -> Result<Self, ufotofu::codec::DecodeError<P::Final, P::Error, Self::ErrorReason>>
where
P: ufotofu::BulkProducer<Item = u8> + ?Sized,
Self: Sized,
{
let rel_count = rel.rel.component_count();
let private_count = rel.private.component_count();
if private_count <= rel_count {
path_extends_path::decode_path_extends_path(rel.rel(), producer).await
} else {
let private_component_count = cu64_decode_standalone(producer)
.await
.map_err(|err| err.map_other(|_| Blame::TheirFault))?;
if private_component_count < rel.rel().component_count() as u64 {
return Err(DecodeError::Other(Blame::TheirFault));
}
if private_component_count >= private_count as u64 {
path_extends_path::decode_path_extends_path(rel.private(), producer).await
} else {
let decoded = rel
.private
.create_prefix(private_component_count as usize)
.ok_or(DecodeError::Other(Blame::TheirFault))?;
Ok(decoded)
}
}
}
}