use core::fmt::Debug;
#[cfg(feature = "dev")]
use arbitrary::Arbitrary;
use compact_u64::{cu64_decode_canonic_standalone, cu64_decode_standalone};
use ufotofu::codec_prelude::*;
use crate::{groupings::Coordinatelike, prelude::*};
#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
#[cfg_attr(feature = "dev", derive(Arbitrary))]
pub struct Entry<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD> {
pub(crate) namespace_id: N,
pub(crate) subspace_id: S,
pub(crate) path: Path<MCL, MCC, MPL>,
pub(crate) timestamp: Timestamp,
pub(crate) payload_length: u64,
pub(crate) payload_digest: PD,
}
impl<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD>
Entry<MCL, MCC, MPL, N, S, PD>
{
pub fn builder() -> EntryBuilder<MCL, MCC, MPL, N, S, PD> {
EntryBuilder::create_empty()
}
pub fn prefilled_builder<E>(source: &E) -> EntryBuilder<MCL, MCC, MPL, N, S, PD>
where
E: Entrylike<MCL, MCC, MPL, N, S, PD> + ?Sized,
N: Clone,
S: Clone,
PD: Clone,
{
let mut builder = Self::builder();
builder
.namespace_id(source.wdm_namespace_id().clone())
.subspace_id(source.wdm_subspace_id().clone())
.path(source.wdm_path().clone())
.timestamp(source.wdm_timestamp())
.payload_digest(source.wdm_payload_digest().clone())
.payload_length(source.wdm_payload_length());
builder
}
pub fn from_entrylike<E>(entrylike_to_clone: &E) -> Self
where
E: Entrylike<MCL, MCC, MPL, N, S, PD> + ?Sized,
N: Clone,
S: Clone,
PD: Clone,
{
Self::prefilled_builder(entrylike_to_clone).build().unwrap()
}
pub fn into_authorised_entry<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: self,
authorisation_token,
}
.into_authorised_entry().expect("AuthorisationToken::new_for_entry must produce an authorisation token that authorises the entry"))
}
}
impl<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD> Keylike<MCL, MCC, MPL, S>
for Entry<MCL, MCC, MPL, N, S, PD>
{
fn wdm_subspace_id(&self) -> &S {
&self.subspace_id
}
fn wdm_path(&self) -> &Path<MCL, MCC, MPL> {
&self.path
}
}
impl<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD>
Coordinatelike<MCL, MCC, MPL, S> for Entry<MCL, MCC, MPL, N, S, PD>
{
fn wdm_timestamp(&self) -> Timestamp {
self.timestamp
}
}
impl<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD> Namespaced<N>
for Entry<MCL, MCC, MPL, N, S, PD>
{
fn wdm_namespace_id(&self) -> &N {
&self.namespace_id
}
}
impl<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD>
Entrylike<MCL, MCC, MPL, N, S, PD> for Entry<MCL, MCC, MPL, N, S, PD>
{
fn wdm_payload_length(&self) -> u64 {
self.payload_length
}
fn wdm_payload_digest(&self) -> &PD {
&self.payload_digest
}
}
impl<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD> Encodable
for Entry<MCL, MCC, MPL, N, S, PD>
where
N: Encodable,
S: Encodable,
PD: Encodable,
{
async fn encode<C>(&self, consumer: &mut C) -> Result<(), C::Error>
where
C: BulkConsumer<Item = u8> + ?Sized,
{
self.wdm_encode_entry(consumer).await
}
}
impl<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD> EncodableKnownLength
for Entry<MCL, MCC, MPL, N, S, PD>
where
N: EncodableKnownLength,
S: EncodableKnownLength,
PD: EncodableKnownLength,
{
fn len_of_encoding(&self) -> usize {
self.wdm_length_of_entry_encoding()
}
}
impl<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD> Decodable
for Entry<MCL, MCC, MPL, N, S, PD>
where
N: DecodableCanonic<ErrorReason: Into<Blame>, ErrorCanonic: Into<Blame>>,
S: DecodableCanonic<ErrorReason: Into<Blame>, ErrorCanonic: Into<Blame>>,
PD: DecodableCanonic<ErrorReason: Into<Blame>, ErrorCanonic: Into<Blame>>,
{
type ErrorReason = Blame;
async fn decode<P>(
producer: &mut P,
) -> Result<Self, DecodeError<P::Final, P::Error, Self::ErrorReason>>
where
P: BulkProducer<Item = u8> + ?Sized,
Self: Sized,
{
Ok(Self {
namespace_id: producer
.produce_decoded_canonic()
.await
.map_err(|err| err.map_other(Into::into))?,
subspace_id: producer
.produce_decoded_canonic()
.await
.map_err(|err| err.map_other(Into::into))?,
path: producer.produce_decoded().await?,
timestamp: cu64_decode_standalone(producer)
.await
.map_err(|err| err.map_other(|_| unreachable!()))?
.into(),
payload_length: cu64_decode_standalone(producer)
.await
.map_err(|err| err.map_other(|_| unreachable!()))?,
payload_digest: producer
.produce_decoded_canonic()
.await
.map_err(|err| err.map_other(Into::into))?,
})
}
}
impl<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD> DecodableCanonic
for Entry<MCL, MCC, MPL, N, S, PD>
where
N: DecodableCanonic<ErrorReason: Into<Blame>, ErrorCanonic: Into<Blame>>,
S: DecodableCanonic<ErrorReason: Into<Blame>, ErrorCanonic: Into<Blame>>,
PD: DecodableCanonic<ErrorReason: Into<Blame>, ErrorCanonic: Into<Blame>>,
{
type ErrorCanonic = Blame;
async fn decode_canonic<P>(
producer: &mut P,
) -> Result<Self, DecodeError<P::Final, P::Error, Self::ErrorCanonic>>
where
P: BulkProducer<Item = u8> + ?Sized,
Self: Sized,
{
Ok(Self {
namespace_id: producer
.produce_decoded_canonic()
.await
.map_err(|err| err.map_other(Into::into))?,
subspace_id: producer
.produce_decoded_canonic()
.await
.map_err(|err| err.map_other(Into::into))?,
path: producer.produce_decoded_canonic().await?,
timestamp: cu64_decode_canonic_standalone(producer)
.await
.map_err(|err| err.map_other(|_| unreachable!()))?
.into(),
payload_length: cu64_decode_canonic_standalone(producer)
.await
.map_err(|err| err.map_other(|_| unreachable!()))?,
payload_digest: producer
.produce_decoded_canonic()
.await
.map_err(|err| err.map_other(Into::into))?,
})
}
}