willow_data_model/entry/
builder.rs

1use anyhash::Hasher;
2
3use crate::prelude::*;
4
5/// A builder for [`Entry`].
6///
7/// See [`Entry::builder`] and [`Entry::prefilled_builder`].
8pub struct EntryBuilder<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD> {
9    namespace_id: Option<N>,
10    subspace_id: Option<S>,
11    path: Option<Path<MCL, MCC, MPL>>,
12    timestamp: Option<Timestamp>,
13    payload_length: Option<u64>,
14    payload_digest: Option<PD>,
15}
16
17impl<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD>
18    EntryBuilder<MCL, MCC, MPL, N, S, PD>
19{
20    pub(crate) fn create_empty() -> Self {
21        Self {
22            namespace_id: None,
23            subspace_id: None,
24            path: None,
25            timestamp: None,
26            payload_length: None,
27            payload_digest: None,
28        }
29    }
30
31    /// Sets the [namespace_id](https://willowprotocol.org/specs/data-model/index.html#entry_namespace_id) of the entry being built.
32    pub fn namespace_id(&mut self, value: N) -> &mut Self {
33        let new = self;
34        new.namespace_id = Some(value);
35        new
36    }
37
38    /// Sets the [subspace_id](https://willowprotocol.org/specs/data-model/index.html#entry_subspace_id) of the entry being built.
39    pub fn subspace_id(&mut self, value: S) -> &mut Self {
40        let new = self;
41        new.subspace_id = Some(value);
42        new
43    }
44
45    /// Sets the [path](https://willowprotocol.org/specs/data-model/index.html#entry_path) of the entry being built.
46    pub fn path(&mut self, value: Path<MCL, MCC, MPL>) -> &mut Self {
47        let new = self;
48        new.path = Some(value);
49        new
50    }
51
52    /// Sets the [timestamp](https://willowprotocol.org/specs/data-model/index.html#entry_timestamp) of the entry being built.
53    pub fn timestamp<T: Into<Timestamp>>(&mut self, value: T) -> &mut Self {
54        let new = self;
55        new.timestamp = Some(value.into());
56        new
57    }
58
59    /// Sets the [payload_length](https://willowprotocol.org/specs/data-model/index.html#entry_payload_length) of the entry being built.
60    pub fn payload_length(&mut self, value: u64) -> &mut Self {
61        let new = self;
62        new.payload_length = Some(value);
63        new
64    }
65
66    /// Sets the [payload_digest](https://willowprotocol.org/specs/data-model/index.html#entry_payload_digest) of the entry being built.
67    pub fn payload_digest(&mut self, value: PD) -> &mut Self {
68        let new = self;
69        new.payload_digest = Some(value);
70        new
71    }
72
73    /// 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).
74    ///
75    /// The type parameter `H` is the type of the [`Hasher`] which hashes the payload into a payload digest (of type `Digest: Into<PD>`). Its [`Default`] impl provides the initial state of the hasher.
76    pub fn payload<Payload: AsRef<[u8]>, H, Digest>(&mut self, payload: Payload) -> &mut Self
77    where
78        H: Default + Hasher<Digest>,
79        Digest: Into<PD>,
80    {
81        let new = self;
82
83        let mut hasher = H::default();
84        hasher.write(payload.as_ref());
85
86        new.payload_digest = Some(hasher.finish().into());
87        new.payload_length = Some(payload.as_ref().len() as u64);
88
89        new
90    }
91
92    /// Sets the [timestamp](https://willowprotocol.org/specs/data-model/index.html#entry_timestamp) of the entry being built to the current time.
93    #[cfg(feature = "std")]
94    pub fn now(&mut self) -> Result<&mut Self, HifitimeError> {
95        let new = self;
96
97        new.timestamp = Some(Timestamp::now()?);
98
99        Ok(new)
100    }
101
102    /// Builds the [`Entry`].
103    ///
104    /// Calling this method multiple times will cause a panic.
105    pub fn build(&mut self) -> Result<Entry<MCL, MCC, MPL, N, S, PD>, EntryBuilderError> {
106        Ok(Entry {
107            namespace_id: self
108                .namespace_id
109                .take()
110                .ok_or(EntryBuilderError::MissingNamespaceId)?,
111            subspace_id: self
112                .subspace_id
113                .take()
114                .ok_or(EntryBuilderError::MissingSubespaceId)?,
115            path: self.path.take().ok_or(EntryBuilderError::MissingPath)?,
116            timestamp: self
117                .timestamp
118                .take()
119                .ok_or(EntryBuilderError::MissingTimestamp)?,
120            payload_length: self
121                .payload_length
122                .take()
123                .ok_or(EntryBuilderError::MissingPayloadLength)?,
124            payload_digest: self
125                .payload_digest
126                .take()
127                .ok_or(EntryBuilderError::MissingPayloadDigest)?,
128        })
129    }
130}
131
132/// Everything that can go wrong when trying to build an [`Entry`].
133#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Hash)]
134pub enum EntryBuilderError {
135    /// The builder was not configured with a namespace id.
136    MissingNamespaceId,
137    /// The builder was not configured with a subspace id.
138    MissingSubespaceId,
139    /// The builder was not configured with a path.
140    MissingPath,
141    /// The builder was not configured with a timestamp.
142    MissingTimestamp,
143    /// The builder was not configured with a payload length.
144    MissingPayloadLength,
145    /// The builder was not configured with a payload digest.
146    MissingPayloadDigest,
147}