zrx_stream/stream/value/delta.rs
1// Copyright (c) 2025-2026 Zensical and contributors
2
3// SPDX-License-Identifier: MIT
4// All contributions are certified under the DCO
5
6// Permission is hereby granted, free of charge, to any person obtaining a copy
7// of this software and associated documentation files (the "Software"), to
8// deal in the Software without restriction, including without limitation the
9// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
10// sell copies of the Software, and to permit persons to whom the Software is
11// furnished to do so, subject to the following conditions:
12
13// The above copyright notice and this permission notice shall be included in
14// all copies or substantial portions of the Software.
15
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18// FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE
19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22// IN THE SOFTWARE.
23
24// ----------------------------------------------------------------------------
25
26//! Delta of items.
27
28use std::slice::Iter;
29use std::vec::IntoIter;
30
31use zrx_scheduler::effect::Item;
32use zrx_scheduler::{Id, Value};
33
34// ----------------------------------------------------------------------------
35// Structs
36// ----------------------------------------------------------------------------
37
38/// Delta of items.
39///
40/// This data type represents a collection of items that can include insertions
41/// and deletions (if [`Option`] is [`None`]), which we call deltas. Deltas are
42/// the means of differentially passing changes through a stream. They must be
43/// applied to a store to manifest the changes they represent.
44///
45/// Note that deltas are assumed to always only contain unique items, meaning
46/// there are no two items with the same identifier in a delta. This invariant
47/// must be checked with unit tests (which we provide for our operators), but
48/// is not enforced at runtime for performance reasons. Differential semantics
49/// still hold if this invariant is violated, but performance might be impacted
50/// due to unnecessary re-computations.
51///
52/// # Examples
53///
54/// ```
55/// use zrx_scheduler::effect::Item;
56/// use zrx_stream::value::Delta;
57///
58/// // Create delta of items
59/// let delta = Delta::from([
60/// Item::new("a", Some(1)),
61/// Item::new("b", Some(2)),
62/// Item::new("c", Some(3)),
63/// ]);
64/// ```
65#[derive(Clone, Debug)]
66pub struct Delta<I, T> {
67 /// Vector of items.
68 inner: Vec<Item<I, Option<T>>>,
69}
70
71// ----------------------------------------------------------------------------
72// Implementations
73// ----------------------------------------------------------------------------
74
75impl<I, T> Delta<I, T> {
76 /// Creates an iterator over the delta of items.
77 ///
78 /// # Examples
79 ///
80 /// ```
81 /// use zrx_scheduler::effect::Item;
82 /// use zrx_stream::value::Delta;
83 ///
84 /// // Create delta of items
85 /// let delta = Delta::from([
86 /// Item::new("a", Some(1)),
87 /// Item::new("b", Some(2)),
88 /// Item::new("c", Some(3)),
89 /// ]);
90 ///
91 /// // Create iterator over items
92 /// for item in delta.iter() {
93 /// println!("{item:?}");
94 /// }
95 /// ```
96 #[inline]
97 pub fn iter(&self) -> Iter<'_, Item<I, Option<T>>> {
98 self.inner.iter()
99 }
100}
101
102// ----------------------------------------------------------------------------
103// Trait implementations
104// ----------------------------------------------------------------------------
105
106impl<I, T> Value for Delta<I, T>
107where
108 I: Id,
109 T: Value,
110{
111}
112
113// ----------------------------------------------------------------------------
114
115impl<I, T, U, const N: usize> From<[U; N]> for Delta<I, T>
116where
117 U: Into<Item<I, Option<T>>>,
118{
119 /// Creates a delta of items from a slice of items.
120 ///
121 /// # Examples
122 ///
123 /// ```
124 /// use zrx_scheduler::effect::Item;
125 /// use zrx_stream::value::Delta;
126 ///
127 /// // Create delta of items
128 /// let delta = Delta::from([
129 /// Item::new("a", Some(1)),
130 /// Item::new("b", Some(2)),
131 /// Item::new("c", Some(3)),
132 /// ]);
133 /// ```
134 #[inline]
135 fn from(value: [U; N]) -> Self {
136 Self::from_iter(value)
137 }
138}
139
140// ----------------------------------------------------------------------------
141
142impl<I, T, U> FromIterator<U> for Delta<I, T>
143where
144 U: Into<Item<I, Option<T>>>,
145{
146 /// Creates a delta of items from an iterator.
147 ///
148 /// # Examples
149 ///
150 /// ```
151 /// use zrx_scheduler::effect::Item;
152 /// use zrx_stream::value::Delta;
153 ///
154 /// // Create delta of items
155 /// let delta = Delta::from_iter([
156 /// Item::new("a", Some(1)),
157 /// Item::new("b", Some(2)),
158 /// Item::new("c", Some(3)),
159 /// ]);
160 /// ```
161 #[inline]
162 fn from_iter<V>(iter: V) -> Self
163 where
164 V: IntoIterator<Item = U>,
165 {
166 Self {
167 inner: iter.into_iter().map(Into::into).collect(),
168 }
169 }
170}
171
172impl<I, T> IntoIterator for Delta<I, T> {
173 type Item = Item<I, Option<T>>;
174 type IntoIter = IntoIter<Self::Item>;
175
176 /// Creates an iterator over the delta of items.
177 ///
178 /// # Examples
179 ///
180 /// ```
181 /// use zrx_scheduler::effect::Item;
182 /// use zrx_stream::value::Delta;
183 ///
184 /// // Create delta of items
185 /// let delta = Delta::from([
186 /// Item::new("a", Some(1)),
187 /// Item::new("b", Some(2)),
188 /// Item::new("c", Some(3)),
189 /// ]);
190 ///
191 /// // Create iterator over items
192 /// for item in delta {
193 /// println!("{item:?}");
194 /// }
195 /// ```
196 #[inline]
197 fn into_iter(self) -> Self::IntoIter {
198 self.inner.into_iter()
199 }
200}
201
202impl<'a, I, T> IntoIterator for &'a Delta<I, T> {
203 type Item = &'a Item<I, Option<T>>;
204 type IntoIter = Iter<'a, Item<I, Option<T>>>;
205
206 /// Creates an iterator over the delta of items.
207 ///
208 /// # Examples
209 ///
210 /// ```
211 /// use zrx_scheduler::effect::Item;
212 /// use zrx_stream::value::Delta;
213 ///
214 /// // Create delta of items
215 /// let delta = Delta::from([
216 /// Item::new("a", Some(1)),
217 /// Item::new("b", Some(2)),
218 /// Item::new("c", Some(3)),
219 /// ]);
220 ///
221 /// // Create iterator over items
222 /// for item in &delta {
223 /// println!("{item:?}");
224 /// }
225 /// ```
226 #[inline]
227 fn into_iter(self) -> Self::IntoIter {
228 self.inner.iter()
229 }
230}
231
232// ----------------------------------------------------------------------------
233
234impl<I, T> Default for Delta<I, T> {
235 /// Creates an empty delta of items.
236 ///
237 /// # Examples
238 ///
239 /// ```
240 /// use zrx_stream::value::Delta;
241 ///
242 /// // Create empty delta of items
243 /// let delta = Delta::default();
244 /// # let _: Delta<(), ()> = delta;
245 /// ```
246 #[inline]
247 fn default() -> Self {
248 Self { inner: Vec::default() }
249 }
250}