splinter_rs/cow.rs
1use std::{fmt::Debug, ops::Deref};
2
3use bytes::{BufMut, Bytes};
4use culprit::Culprit;
5use either::Either;
6
7use crate::{
8 Encodable, PartitionRead, PartitionWrite, Splinter, SplinterRef,
9 codec::{DecodeErr, encoder::Encoder},
10 level::High,
11};
12
13/// A clone-on-write splinter that can hold either a reference or an owned value.
14///
15/// `CowSplinter` is an enum that can contain either a [`SplinterRef<B>`] (for zero-copy
16/// read-only access) or an owned [`Splinter`] (for mutable operations). It automatically
17/// converts from read-only to owned when mutation is needed, providing an efficient
18/// way to work with splinter data that might come from different sources.
19///
20/// This is particularly useful when you want to:
21/// - Start with serialized/borrowed data for read-only operations
22/// - Potentially modify the data later
23/// - Avoid unnecessary copying until mutation is actually needed
24/// - Or work with a collection of Splinters which may or may not be owned
25///
26/// # Examples
27///
28/// Starting with a reference and converting to owned when needed:
29///
30/// ```
31/// use splinter_rs::{Splinter, CowSplinter, PartitionWrite, PartitionRead, Encodable};
32///
33/// // Create a CowSplinter from a reference
34/// let original = Splinter::from_iter([100, 200]);
35/// let splinter_ref = original.encode_to_splinter_ref();
36/// let mut cow = CowSplinter::from_ref(splinter_ref);
37///
38/// // Read operations work on the reference
39/// assert_eq!(cow.cardinality(), 2);
40///
41/// // First write operation converts to owned
42/// cow.insert(300); // This triggers clone-on-write
43/// assert_eq!(cow.cardinality(), 3);
44/// ```
45///
46/// Creating from different sources:
47///
48/// ```
49/// use splinter_rs::{Splinter, CowSplinter, PartitionWrite, PartitionRead, Encodable};
50/// use bytes::Bytes;
51///
52/// // From owned splinter
53/// let owned = Splinter::EMPTY;
54/// let cow1: CowSplinter<Bytes> = CowSplinter::from_owned(owned);
55///
56/// // From iterator
57/// let cow2 = CowSplinter::<Bytes>::from_iter([1u32, 2, 3]);
58///
59/// // From bytes
60/// let bytes = cow2.encode_to_bytes();
61/// let cow3 = CowSplinter::from_bytes(bytes).unwrap();
62/// ```
63#[derive(Clone)]
64pub enum CowSplinter<B> {
65 /// Contains a zero-copy reference to serialized data
66 Ref(SplinterRef<B>),
67 /// Contains an owned, mutable splinter
68 Owned(Splinter),
69}
70
71impl<B> Default for CowSplinter<B> {
72 fn default() -> Self {
73 Self::Owned(Splinter::EMPTY)
74 }
75}
76
77impl<B: Deref<Target = [u8]>> Debug for CowSplinter<B> {
78 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
79 match self {
80 CowSplinter::Ref(splinter_ref) => f
81 .debug_tuple("CowSplinter::Ref")
82 .field(splinter_ref)
83 .finish(),
84 CowSplinter::Owned(splinter) => {
85 f.debug_tuple("CowSplinter::Owned").field(splinter).finish()
86 }
87 }
88 }
89}
90
91impl<B, K: Into<u32>> FromIterator<K> for CowSplinter<B>
92where
93 B: Deref<Target = [u8]>,
94{
95 fn from_iter<I: IntoIterator<Item = K>>(iter: I) -> Self {
96 Self::Owned(Splinter::from_iter(iter.into_iter().map(|k| k.into())))
97 }
98}
99
100impl<B> From<Splinter> for CowSplinter<B> {
101 fn from(splinter: Splinter) -> Self {
102 Self::Owned(splinter)
103 }
104}
105
106impl<B> From<SplinterRef<B>> for CowSplinter<B> {
107 fn from(splinter_ref: SplinterRef<B>) -> Self {
108 Self::Ref(splinter_ref)
109 }
110}
111
112impl<B: Deref<Target = [u8]>> From<CowSplinter<B>> for Splinter {
113 fn from(cow_splinter: CowSplinter<B>) -> Self {
114 cow_splinter.into_owned()
115 }
116}
117
118impl From<CowSplinter<Bytes>> for SplinterRef<Bytes> {
119 fn from(cow: CowSplinter<Bytes>) -> Self {
120 match cow {
121 CowSplinter::Ref(splinter_ref) => splinter_ref,
122 CowSplinter::Owned(splinter) => splinter.encode_to_splinter_ref(),
123 }
124 }
125}
126
127impl<B> CowSplinter<B> {
128 /// Creates a `CowSplinter` from an owned [`Splinter`].
129 ///
130 /// # Examples
131 ///
132 /// ```
133 /// use splinter_rs::{Splinter, CowSplinter, PartitionRead, Encodable};
134 ///
135 /// let splinter = Splinter::from_iter([42]);
136 /// let cow: CowSplinter<Vec<u8>> = CowSplinter::from_owned(splinter);
137 /// assert!(cow.contains(42));
138 /// ```
139 pub fn from_owned(splinter: Splinter) -> Self {
140 splinter.into()
141 }
142
143 /// Creates a `CowSplinter` from a [`SplinterRef`].
144 ///
145 /// # Examples
146 ///
147 /// ```
148 /// use splinter_rs::{Splinter, CowSplinter, PartitionWrite, PartitionRead, Encodable};
149 ///
150 /// let mut splinter = Splinter::EMPTY;
151 /// splinter.insert(42);
152 /// let splinter_ref = splinter.encode_to_splinter_ref();
153 ///
154 /// let cow = CowSplinter::from_ref(splinter_ref);
155 /// assert!(cow.contains(42));
156 /// ```
157 pub fn from_ref(splinter: SplinterRef<B>) -> Self {
158 splinter.into()
159 }
160}
161
162impl<B: Deref<Target = [u8]>> CowSplinter<B> {
163 /// Creates a `CowSplinter` from raw bytes, validating the format.
164 ///
165 /// This is equivalent to creating a `SplinterRef` from the bytes and wrapping
166 /// it in a `CowSplinter::Ref`. All the same validation rules apply.
167 ///
168 /// # Errors
169 ///
170 /// Returns the same errors as [`SplinterRef::from_bytes`].
171 ///
172 /// # Examples
173 ///
174 /// ```
175 /// use splinter_rs::{Splinter, CowSplinter, PartitionWrite, PartitionRead, Encodable};
176 ///
177 /// let mut splinter = Splinter::EMPTY;
178 /// splinter.insert(42);
179 /// let bytes = splinter.encode_to_bytes();
180 ///
181 /// let cow = CowSplinter::from_bytes(bytes).unwrap();
182 /// assert!(cow.contains(42));
183 /// ```
184 pub fn from_bytes(data: B) -> Result<Self, Culprit<DecodeErr>> {
185 Ok(Self::Ref(SplinterRef::from_bytes(data)?))
186 }
187
188 /// Converts this `CowSplinter` into an owned [`Splinter`].
189 ///
190 /// If this is already an owned splinter, it returns it directly.
191 /// If this is a reference, it deserializes the data into a new owned splinter.
192 ///
193 /// # Examples
194 ///
195 /// ```
196 /// use splinter_rs::{Splinter, CowSplinter, PartitionWrite, PartitionRead, Encodable};
197 ///
198 /// let mut original = Splinter::EMPTY;
199 /// original.insert(100);
200 /// let splinter_ref = original.encode_to_splinter_ref();
201 /// let cow = CowSplinter::from_ref(splinter_ref);
202 ///
203 /// let owned = cow.into_owned();
204 /// assert_eq!(owned.cardinality(), 1);
205 /// assert!(owned.contains(100));
206 /// ```
207 pub fn into_owned(self) -> Splinter {
208 match self {
209 Self::Ref(splinter_ref) => splinter_ref.decode_to_splinter(),
210 Self::Owned(splinter) => splinter,
211 }
212 }
213
214 /// Returns a mutable reference to the underlying [`Splinter`].
215 ///
216 /// This method implements the "clone-on-write" behavior: if the current value
217 /// is a `Ref`, it will be converted to `Owned` by deserializing the data.
218 /// Subsequent calls will return the same mutable reference without additional
219 /// conversions.
220 ///
221 /// # Examples
222 ///
223 /// ```
224 /// use splinter_rs::{Splinter, CowSplinter, PartitionWrite, PartitionRead, Encodable};
225 ///
226 /// let mut original = Splinter::EMPTY;
227 /// original.insert(100);
228 /// let splinter_ref = original.encode_to_splinter_ref();
229 /// let mut cow = CowSplinter::from_ref(splinter_ref);
230 ///
231 /// // This triggers the clone-on-write conversion
232 /// let mutable_ref = cow.to_mut();
233 /// mutable_ref.insert(200);
234 ///
235 /// assert_eq!(cow.cardinality(), 2);
236 /// ```
237 pub fn to_mut(&mut self) -> &mut Splinter {
238 match *self {
239 Self::Ref(ref splinter_ref) => {
240 *self = Self::Owned(splinter_ref.decode_to_splinter());
241 match *self {
242 Self::Ref(..) => unreachable!(),
243 Self::Owned(ref mut owned) => owned,
244 }
245 }
246 Self::Owned(ref mut owned) => owned,
247 }
248 }
249}
250
251impl CowSplinter<Bytes> {
252 /// Returns the serialized bytes representation of this splinter.
253 ///
254 /// For the `Ref` variant, this clones the underlying `Bytes` (which is efficient
255 /// due to reference counting). For the `Owned` variant, this encodes the splinter
256 /// to bytes.
257 ///
258 /// # Examples
259 ///
260 /// ```
261 /// use splinter_rs::{Splinter, CowSplinter, PartitionWrite, PartitionRead, Encodable};
262 ///
263 /// let mut splinter = Splinter::EMPTY;
264 /// splinter.insert(42);
265 /// let cow = CowSplinter::from_owned(splinter);
266 ///
267 /// let bytes = cow.encode_to_bytes();
268 /// assert!(!bytes.is_empty());
269 /// ```
270 pub fn encode_to_bytes(&self) -> Bytes {
271 match self {
272 CowSplinter::Ref(splinter_ref) => splinter_ref.encode_to_bytes(),
273 CowSplinter::Owned(splinter) => splinter.encode_to_bytes(),
274 }
275 }
276}
277
278impl<B: Deref<Target = [u8]>> Encodable for CowSplinter<B> {
279 fn encoded_size(&self) -> usize {
280 match self {
281 CowSplinter::Ref(splinter_ref) => splinter_ref.encoded_size(),
282 CowSplinter::Owned(splinter) => splinter.encoded_size(),
283 }
284 }
285
286 fn encode<T: BufMut>(&self, encoder: &mut Encoder<T>) {
287 match self {
288 CowSplinter::Ref(splinter_ref) => splinter_ref.encode(encoder),
289 CowSplinter::Owned(splinter) => splinter.encode(encoder),
290 }
291 }
292}
293
294impl<B: Deref<Target = [u8]>> PartitionRead<High> for CowSplinter<B> {
295 fn cardinality(&self) -> usize {
296 match self {
297 CowSplinter::Ref(splinter_ref) => splinter_ref.cardinality(),
298 CowSplinter::Owned(splinter) => splinter.cardinality(),
299 }
300 }
301
302 fn is_empty(&self) -> bool {
303 match self {
304 CowSplinter::Ref(splinter_ref) => splinter_ref.is_empty(),
305 CowSplinter::Owned(splinter) => splinter.is_empty(),
306 }
307 }
308
309 fn contains(&self, value: u32) -> bool {
310 match self {
311 CowSplinter::Ref(splinter_ref) => splinter_ref.contains(value),
312 CowSplinter::Owned(splinter) => splinter.contains(value),
313 }
314 }
315
316 fn rank(&self, value: u32) -> usize {
317 match self {
318 CowSplinter::Ref(splinter_ref) => splinter_ref.rank(value),
319 CowSplinter::Owned(splinter) => splinter.rank(value),
320 }
321 }
322
323 fn select(&self, idx: usize) -> Option<u32> {
324 match self {
325 CowSplinter::Ref(splinter_ref) => splinter_ref.select(idx),
326 CowSplinter::Owned(splinter) => splinter.select(idx),
327 }
328 }
329
330 fn last(&self) -> Option<u32> {
331 match self {
332 CowSplinter::Ref(splinter_ref) => splinter_ref.last(),
333 CowSplinter::Owned(splinter) => splinter.last(),
334 }
335 }
336
337 fn iter(&self) -> impl Iterator<Item = u32> {
338 match self {
339 CowSplinter::Ref(splinter_ref) => Either::Left(splinter_ref.iter()),
340 CowSplinter::Owned(splinter) => Either::Right(splinter.iter()),
341 }
342 }
343}
344
345impl<B: Deref<Target = [u8]>> PartitionWrite<High> for CowSplinter<B> {
346 fn insert(&mut self, value: u32) -> bool {
347 self.to_mut().insert(value)
348 }
349
350 fn remove(&mut self, value: u32) -> bool {
351 self.to_mut().remove(value)
352 }
353}
354
355impl<B: Deref<Target = [u8]>, B2: Deref<Target = [u8]>> PartialEq<CowSplinter<B2>>
356 for CowSplinter<B>
357{
358 fn eq(&self, other: &CowSplinter<B2>) -> bool {
359 use CowSplinter::*;
360 match (self, other) {
361 (Ref(l), Ref(r)) => l == r,
362 (Ref(l), Owned(r)) => l == r,
363 (Owned(l), Ref(r)) => l == r,
364 (Owned(l), Owned(r)) => l == r,
365 }
366 }
367}