use core::cmp::Ordering;
use core::fmt::Debug;
use compact_u64::{cu64_encode_standalone, cu64_len_of_encoding};
use ufotofu::codec_prelude::*;
use crate::prelude::*;
pub trait Entrylike<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD>:
Coordinatelike<MCL, MCC, MPL, S> + Namespaced<N>
{
fn wdm_payload_length(&self) -> u64;
fn wdm_payload_digest(&self) -> &PD;
}
pub trait EntrylikeExt<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD>:
Entrylike<MCL, MCC, MPL, N, S, PD> + CoordinatelikeExt<MCL, MCC, MPL, S>
{
fn wdm_entry_eq<OtherEntry>(&self, other: &OtherEntry) -> bool
where
OtherEntry: Entrylike<MCL, MCC, MPL, N, S, PD>,
N: PartialEq,
S: PartialEq,
PD: PartialEq,
{
self.wdm_namespace_id() == other.wdm_namespace_id()
&& self.wdm_coordinate_eq(other)
&& self.wdm_payload_digest() == other.wdm_payload_digest()
&& self.wdm_payload_length() == other.wdm_payload_length()
}
fn wdm_entry_ne<OtherEntry>(&self, other: &OtherEntry) -> bool
where
OtherEntry: Entrylike<MCL, MCC, MPL, N, S, PD>,
N: PartialEq,
S: PartialEq,
PD: PartialEq,
{
self.wdm_namespace_id() != other.wdm_namespace_id()
|| self.wdm_coordinate_ne(other)
|| self.wdm_payload_digest() != other.wdm_payload_digest()
|| self.wdm_payload_length() != other.wdm_payload_length()
}
fn wdm_cmp_recency<OtherEntry>(&self, other: &OtherEntry) -> Ordering
where
OtherEntry: Entrylike<MCL, MCC, MPL, N, S, PD>,
PD: Ord,
{
self.wdm_timestamp()
.cmp(&other.wdm_timestamp())
.then_with(|| {
self.wdm_payload_digest()
.cmp(other.wdm_payload_digest())
.then_with(|| self.wdm_payload_length().cmp(&other.wdm_payload_length()))
})
}
fn wdm_is_newer_than<OtherEntry>(&self, other: &OtherEntry) -> bool
where
OtherEntry: Entrylike<MCL, MCC, MPL, N, S, PD>,
PD: Ord,
{
self.wdm_cmp_recency(other) == Ordering::Greater
}
fn wdm_is_older_than<OtherEntry>(&self, other: &OtherEntry) -> bool
where
OtherEntry: Entrylike<MCL, MCC, MPL, N, S, PD>,
PD: Ord,
{
self.wdm_cmp_recency(other) == Ordering::Less
}
fn wdm_prunes<OtherEntry>(&self, other: &OtherEntry) -> bool
where
OtherEntry: Entrylike<MCL, MCC, MPL, N, S, PD>,
N: PartialEq,
S: PartialEq,
PD: Ord,
{
self.wdm_is_newer_than(other)
&& self.wdm_namespace_id() == other.wdm_namespace_id()
&& self.wdm_subspace_id() == other.wdm_subspace_id()
&& self.wdm_path().is_prefix_of(other.wdm_path())
}
fn wdm_is_pruned_by<OtherEntry>(&self, other: &OtherEntry) -> bool
where
OtherEntry: Entrylike<MCL, MCC, MPL, N, S, PD>,
N: PartialEq,
S: PartialEq,
PD: Ord,
Self: Sized,
{
other.wdm_prunes(self)
}
fn wdm_authorise<AT>(
&self,
ingredients: &AT::Ingredients,
) -> Result<AuthorisedEntry<MCL, MCC, MPL, N, S, PD, AT>, AT::CreationError>
where
AT: AuthorisationToken<MCL, MCC, MPL, N, S, PD> + Debug,
N: Clone + Debug,
S: Clone + Debug,
PD: Clone + Debug,
{
let authorisation_token = AuthorisationToken::new_for_entry(self, ingredients)?;
Ok(PossiblyAuthorisedEntry {
entry: Entry::from_entrylike(self),
authorisation_token,
}
.into_authorised_entry().expect("`AuthorisationToken::new_for_entry` must produce an authorisation token that authorises the entry"))
}
async fn wdm_encode_entry<C>(&self, consumer: &mut C) -> Result<(), C::Error>
where
C: BulkConsumer<Item = u8> + ?Sized,
N: Encodable,
S: Encodable,
PD: Encodable,
{
consumer.consume_encoded(self.wdm_namespace_id()).await?;
consumer.consume_encoded(self.wdm_subspace_id()).await?;
consumer.consume_encoded(self.wdm_path()).await?;
cu64_encode_standalone(u64::from(self.wdm_timestamp()), consumer).await?;
cu64_encode_standalone(self.wdm_payload_length(), consumer).await?;
consumer.consume_encoded(self.wdm_payload_digest()).await?;
Ok(())
}
fn wdm_length_of_entry_encoding(&self) -> usize
where
N: EncodableKnownLength,
S: EncodableKnownLength,
PD: EncodableKnownLength,
{
self.wdm_namespace_id().len_of_encoding()
+ self.wdm_subspace_id().len_of_encoding()
+ self.wdm_path().len_of_encoding()
+ 1
+ cu64_len_of_encoding(8, u64::from(self.wdm_timestamp()))
+ 1
+ cu64_len_of_encoding(8, self.wdm_payload_length())
+ self.wdm_payload_digest().len_of_encoding()
}
}
impl<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD, E>
EntrylikeExt<MCL, MCC, MPL, N, S, PD> for E
where
E: Entrylike<MCL, MCC, MPL, N, S, PD> + ?Sized,
{
}