willow_data_model/entry/
entry.rs

1#[cfg(feature = "dev")]
2use arbitrary::Arbitrary;
3
4use crate::{groupings::Coordinatelike, prelude::*};
5
6/// The metadata associated with each Willow [Payload](https://willowprotocol.org/specs/data-model/index.html#Payload) string.
7///
8/// [Entries](https://willowprotocol.org/specs/data-model/index.html#Entry) are the central concept in Willow. In order to make any bytestring of data accessible to Willow, you need to create an Entry describing its metadata. Specifically, an Entry consists of
9///
10/// - a [namespace_id](https://willowprotocol.org/specs/data-model/index.html#entry_namespace_id) (roughly, this addresses a universe of Willow data, fully independent from all data (i.e., Entries) of different namespace ids) of type `N`,
11/// - a [subspace_id](https://willowprotocol.org/specs/data-model/index.html#entry_subspace_id) (roughly, a fully indendent part of a namespace, typically subspaces correspond to individual users) of type `S`,
12/// - a [path](https://willowprotocol.org/specs/data-model/index.html#entry_path) (roughly, a file-system-like way of arranging payloads hierarchically within a subspace) of type [`Path`],
13/// - a [timestamp](https://willowprotocol.org/specs/data-model/index.html#entry_timestamp) (newer Entries can overwrite certain older Entries),
14/// - a [payload_length](https://willowprotocol.org/specs/data-model/index.html#entry_payload_length) (the length of the payload string), and
15/// - a [payload_digest](https://willowprotocol.org/specs/data-model/index.html#entry_payload_digest) (a secure hash of the payload string being inserted into Willow).
16///
17/// To access these six fields, use the methods of the [`Entrylike`] trait (which [`Entry`] implements). The [`EntrylikeExt`] trait provides additional helper methods, for example, methods to check which Entries can delete which other Entries.
18///
19/// To create Entries, use the [`Entry::builder`] or [`Entry::prefilled_builder`] functions.
20///
21/// # Example
22///
23/// ```
24/// use willow_data_model::prelude::*;
25///
26/// let entry = Entry::builder()
27///     .namespace_id("family")
28///     .subspace_id("alfie")
29///     .path(Path::<4, 4, 4>::new())
30///     .timestamp(12345)
31///     .payload_digest("some_hash")
32///     .payload_length(17)
33///     .build().unwrap();
34///
35/// assert_eq!(*entry.wdm_subspace_id(), "alfie");
36///
37/// let newer = Entry::prefilled_builder(&entry).timestamp(99999).build().unwrap();
38/// assert!(newer.wdm_prunes(&entry));
39/// ```
40///
41/// [Spec definition](https://willowprotocol.org/specs/data-model/index.html#Entry).
42#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Hash)]
43#[cfg_attr(feature = "dev", derive(Arbitrary))]
44pub struct Entry<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD> {
45    pub(crate) namespace_id: N,
46    pub(crate) subspace_id: S,
47    pub(crate) path: Path<MCL, MCC, MPL>,
48    pub(crate) timestamp: Timestamp,
49    pub(crate) payload_length: u64,
50    pub(crate) payload_digest: PD,
51}
52
53impl<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD>
54    Entry<MCL, MCC, MPL, N, S, PD>
55{
56    /// Creates a builder for [`Entry`].
57    ///
58    /// # Examples
59    ///
60    /// ```
61    /// use willow_data_model::prelude::*;
62    ///
63    /// // Supplying incomplete data errors.
64    /// assert!(
65    ///     Entry::builder()
66    ///     .path(Path::<4, 4, 4>::new())
67    ///     .namespace_id("family")
68    ///     .subspace_id("alfie")
69    ///     .payload_digest("some_hash")
70    ///     // timestamp and payload_length are missing!
71    ///     .build().is_err()
72    /// );
73    ///
74    /// // Supplying all necessary data yields an entry.
75    /// let entry = Entry::builder()
76    ///     .namespace_id("family")
77    ///     .subspace_id("alfie")
78    ///     .path(Path::<4, 4, 4>::new())
79    ///     .timestamp(12345)
80    ///     .payload_digest("some_hash")
81    ///     .payload_length(17)
82    ///     .build().unwrap();
83    ///
84    /// assert_eq!(*entry.wdm_subspace_id(), "alfie");
85    /// ```
86    pub fn builder() -> EntryBuilder<MCL, MCC, MPL, N, S, PD> {
87        EntryBuilder::create_empty()
88    }
89
90    /// Creates a builder which is prefilled with the data from some other entry.
91    ///
92    /// Use this function to create modified copies of entries.
93    ///
94    /// # Examples
95    ///
96    /// ```
97    /// use willow_data_model::prelude::*;
98    ///
99    /// // Supplying all necessary data yields an entry.
100    /// let first_entry = Entry::builder()
101    ///     .namespace_id("family")
102    ///     .subspace_id("alfie")
103    ///     .path(Path::<4, 4, 4>::new())
104    ///     .timestamp(12345)
105    ///     .payload_digest("some_hash")
106    ///     .payload_length(17)
107    ///     .build().unwrap();
108    ///
109    /// assert_eq!(*first_entry.wdm_payload_digest(), "some_hash");
110    ///
111    /// let second_entry = Entry::prefilled_builder(&first_entry)
112    ///     .timestamp(67890)
113    ///     .payload_digest("another_hash")
114    ///     .payload_length(4)
115    ///     .build().unwrap();
116    ///
117    /// assert_eq!(*second_entry.wdm_payload_digest(), "another_hash");
118    /// ```
119    pub fn prefilled_builder<E>(source: &E) -> EntryBuilder<MCL, MCC, MPL, N, S, PD>
120    where
121        E: Entrylike<MCL, MCC, MPL, N, S, PD>,
122        N: Clone,
123        S: Clone,
124        PD: Clone,
125    {
126        let mut builder = Self::builder();
127
128        builder
129            .namespace_id(source.wdm_namespace_id().clone())
130            .subspace_id(source.wdm_subspace_id().clone())
131            .path(source.wdm_path().clone())
132            .timestamp(source.wdm_timestamp())
133            .payload_digest(source.wdm_payload_digest().clone())
134            .payload_length(source.wdm_payload_length());
135
136        builder
137    }
138}
139
140impl<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD> Keylike<MCL, MCC, MPL, S>
141    for Entry<MCL, MCC, MPL, N, S, PD>
142{
143    fn wdm_subspace_id(&self) -> &S {
144        &self.subspace_id
145    }
146
147    fn wdm_path(&self) -> &Path<MCL, MCC, MPL> {
148        &self.path
149    }
150}
151
152impl<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD>
153    Coordinatelike<MCL, MCC, MPL, S> for Entry<MCL, MCC, MPL, N, S, PD>
154{
155    fn wdm_timestamp(&self) -> Timestamp {
156        self.timestamp
157    }
158}
159
160impl<const MCL: usize, const MCC: usize, const MPL: usize, N, S, PD>
161    Entrylike<MCL, MCC, MPL, N, S, PD> for Entry<MCL, MCC, MPL, N, S, PD>
162{
163    fn wdm_namespace_id(&self) -> &N {
164        &self.namespace_id
165    }
166
167    fn wdm_payload_length(&self) -> u64 {
168        self.payload_length
169    }
170
171    fn wdm_payload_digest(&self) -> &PD {
172        &self.payload_digest
173    }
174}