willow25 0.4.0

A ready-to-use implementation of the Willow specifications.
Documentation
use bab_rs::William3Hasher;
use ufotofu::BulkProducer;
use willow_data_model::prelude as wdm;

use crate::prelude::*;

wrapper! {
    /// Builder for [`Entry`].
    EntryBuilder; wdm::EntryBuilder<MCL, MCC, MPL, NamespaceId, SubspaceId, PayloadDigest>
}

impl EntryBuilder {
    /// Sets the [namespace_id](https://willowprotocol.org/specs/data-model/index.html#entry_namespace_id) of the entry being built.
    pub fn namespace_id(&mut self, value: NamespaceId) -> &mut Self {
        self.0.namespace_id(value).into()
    }

    /// Sets the [subspace_id](https://willowprotocol.org/specs/data-model/index.html#entry_subspace_id) of the entry being built.
    pub fn subspace_id(&mut self, value: SubspaceId) -> &mut Self {
        self.0.subspace_id(value).into()
    }

    /// Sets the [path](https://willowprotocol.org/specs/data-model/index.html#entry_path) of the entry being built.
    pub fn path(&mut self, value: Path) -> &mut Self {
        self.0.path(value.into()).into()
    }

    /// Sets the [timestamp](https://willowprotocol.org/specs/data-model/index.html#entry_timestamp) of the entry being built.
    pub fn timestamp<T: Into<Timestamp>>(&mut self, value: T) -> &mut Self {
        self.0.timestamp(value).into()
    }

    /// Sets the [payload_length](https://willowprotocol.org/specs/data-model/index.html#entry_payload_length) of the entry being built.
    pub fn payload_length(&mut self, value: u64) -> &mut Self {
        self.0.payload_length(value).into()
    }

    /// Sets the [payload_digest](https://willowprotocol.org/specs/data-model/index.html#entry_payload_digest) of the entry being built.
    pub fn payload_digest(&mut self, value: PayloadDigest) -> &mut Self {
        self.0.payload_digest(value).into()
    }

    /// Sets the [timestamp](https://willowprotocol.org/specs/data-model/index.html#entry_timestamp) of the entry being built to the current time.
    ///
    /// ```
    /// use willow25::prelude::*;
    ///
    /// let entry = Entry::builder()
    ///     .now().unwrap()
    ///     .namespace_id([0; 32].into())
    ///     .subspace_id([1; 32].into())
    ///     .path(path!("/vacation/plan"))
    ///     .payload_digest([77; 32].into())
    ///     .payload_length(17)
    ///     .build().unwrap();
    ///
    /// assert!(entry.timestamp() > 814673376414009.into());
    /// // 814673376414009 is the timestamp for 26.10.2025 afternoon-ish in Berlin.
    /// ```
    #[cfg(feature = "std")]
    pub fn now(&mut self) -> Result<&mut Self, HifitimeError> {
        self.0.now().map(From::from)
    }

    /// Sets the [payload_length](https://willowprotocol.org/specs/data-model/index.html#entry_payload_length) and [payload_digest](https://willowprotocol.org/specs/data-model/index.html#entry_payload_digest) of the entry being built to those of the given [Payload](https://willowprotocol.org/specs/data-model/index.html#Payload).
    ///
    /// ```
    /// use willow25::prelude::*;
    ///
    /// let entry = Entry::builder()
    ///     .namespace_id([0; 32].into())
    ///     .subspace_id([1; 32].into())
    ///     .path(path!("/vacation/plan"))
    ///     .timestamp(12345)
    ///     .payload(b"See all the sights!")
    ///     .build().unwrap();
    ///
    /// assert_eq!(*entry.payload_digest(), [
    ///     30, 72, 189, 217, 105, 47, 66, 151,
    ///     107, 162, 70, 193, 110, 66, 169, 91,
    ///     102, 134, 136, 3, 177, 198, 63, 147,
    ///     147, 222, 117, 245, 149, 243, 155, 150,
    /// ].into());
    /// assert_eq!(entry.payload_length(), 19);
    /// ```
    pub fn payload<Payload: AsRef<[u8]>>(&mut self, payload: Payload) -> &mut Self {
        let new = self;

        new.0
            .payload::<Payload, William3Hasher, bab_rs::William3Digest>(payload);

        new
    }

    /// Sets the [payload_length](https://willowprotocol.org/specs/data-model/index.html#entry_payload_length) and [payload_digest](https://willowprotocol.org/specs/data-model/index.html#entry_payload_digest) of the entry being built to those of the payload given by the producer.
    ///
    /// ```
    /// use willow25::prelude::*;
    /// use ufotofu::producer::clone_from_slice;
    ///
    /// # pollster::block_on(async {
    /// let mut producer = clone_from_slice(b"See all the sights!");
    ///
    /// let entry = Entry::builder()
    ///     .namespace_id([0; 32].into())
    ///     .subspace_id([1; 32].into())
    ///     .path(path!("/vacation/plan"))
    ///     .timestamp(12345)
    ///     .payload_async(&mut producer).await.unwrap()
    ///     .build().unwrap();
    ///
    /// assert_eq!(*entry.payload_digest(), [
    ///     30, 72, 189, 217, 105, 47, 66, 151,
    ///     107, 162, 70, 193, 110, 66, 169, 91,
    ///     102, 134, 136, 3, 177, 198, 63, 147,
    ///     147, 222, 117, 245, 149, 243, 155, 150,
    /// ].into());
    /// assert_eq!(entry.payload_length(), 19);
    /// # })
    /// ```
    pub async fn payload_async<P>(
        &mut self,
        payload_producer: &mut P,
    ) -> Result<&mut Self, P::Error>
    where
        P: BulkProducer<Item = u8, Final = ()>,
    {
        let new = self;

        new.0
            .payload_async::<P, William3Hasher, bab_rs::William3Digest>(payload_producer)
            .await?;

        Ok(new)
    }

    /// Builds the [`Entry`].
    ///
    /// Calling this method multiple times will cause a panic.
    pub fn build(&mut self) -> Result<Entry, EntryBuilderError> {
        self.0.build().map(From::from)
    }
}