splinter_rs/
cow.rs

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