use core::cmp::Ordering;
use compact_u64::{cu64_encode_standalone, cu64_len_of_encoding};
use ufotofu::codec_prelude::*;
use crate::{authorisation::PossiblyAuthorisedEntry, prelude::*};
pub trait Entrylike: Coordinatelike + Namespaced {
fn payload_length(&self) -> u64;
fn payload_digest(&self) -> &PayloadDigest;
}
pub trait EntrylikeExt: Entrylike {
fn entry_eq<OtherEntry>(&self, other: &OtherEntry) -> bool
where
OtherEntry: Entrylike,
{
self.namespace_id() == other.namespace_id()
&& self.coordinate_eq(other)
&& self.payload_digest() == other.payload_digest()
&& self.payload_length() == other.payload_length()
}
fn entry_ne<OtherEntry>(&self, other: &OtherEntry) -> bool
where
OtherEntry: Entrylike,
{
self.namespace_id() != other.namespace_id()
|| self.coordinate_ne(other)
|| self.payload_digest() != other.payload_digest()
|| self.payload_length() != other.payload_length()
}
fn cmp_recency<OtherEntry>(&self, other: &OtherEntry) -> Ordering
where
OtherEntry: Entrylike,
{
self.timestamp().cmp(&other.timestamp()).then_with(|| {
self.payload_digest()
.cmp(other.payload_digest())
.then_with(|| self.payload_length().cmp(&other.payload_length()))
})
}
fn is_newer_than<OtherEntry>(&self, other: &OtherEntry) -> bool
where
OtherEntry: Entrylike,
{
self.cmp_recency(other) == Ordering::Greater
}
fn is_older_than<OtherEntry>(&self, other: &OtherEntry) -> bool
where
OtherEntry: Entrylike,
{
self.cmp_recency(other) == Ordering::Less
}
fn prunes<OtherEntry>(&self, other: &OtherEntry) -> bool
where
OtherEntry: Entrylike,
{
self.is_newer_than(other)
&& self.namespace_id() == other.namespace_id()
&& self.subspace_id() == other.subspace_id()
&& self.path().is_prefix_of(other.path())
}
fn is_pruned_by<OtherEntry>(&self, other: &OtherEntry) -> bool
where
OtherEntry: Entrylike,
Self: Sized,
{
other.prunes(self)
}
fn authorise(
&self,
write_capability: &WriteCapability,
secret: &SubspaceSecret,
) -> Result<AuthorisedEntry, DoesNotAuthorise> {
let authorisation_token =
AuthorisationToken::new_for_entry(self, write_capability, secret)?;
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 encode_entry<C>(&self, consumer: &mut C) -> Result<(), C::Error>
where
C: BulkConsumer<Item = u8> + ?Sized,
{
consumer.consume_encoded(self.namespace_id()).await?;
consumer.consume_encoded(self.subspace_id()).await?;
consumer.consume_encoded(self.path()).await?;
cu64_encode_standalone(u64::from(self.timestamp()), consumer).await?;
cu64_encode_standalone(self.payload_length(), consumer).await?;
consumer.consume_encoded(self.payload_digest()).await?;
Ok(())
}
fn length_of_entry_encoding(&self) -> usize {
self.namespace_id().len_of_encoding()
+ self.subspace_id().len_of_encoding()
+ self.path().len_of_encoding()
+ 1
+ cu64_len_of_encoding(8, u64::from(self.timestamp()))
+ 1
+ cu64_len_of_encoding(8, self.payload_length())
+ self.payload_digest().len_of_encoding()
}
}
impl<E> EntrylikeExt for E where E: Entrylike + ?Sized {}