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