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}