croaring/bitmap/
serialization.rs

1use super::{Bitmap, BitmapView};
2use crate::serialization::{Frozen, Native, Portable};
3
4use core::ffi::{c_char, c_void};
5
6/// Trait for different formats of bitmap serialization
7pub trait Serializer: crate::sealed::Sealed {
8    /// The required alignment for the serialized data
9    #[doc(hidden)]
10    const REQUIRED_ALIGNMENT: usize = 1;
11
12    /// Serialize a bitmap into bytes, using the provided vec buffer to store the serialized data
13    ///
14    /// Note that some serializers ([Frozen]) may require that the bitmap is aligned specially,
15    /// this method will ensure that the returned slice of bytes is aligned correctly, by adding
16    /// additional padding before the serialized data if required.
17    ///
18    /// The contents of the provided vec buffer will not be overwritten: only new data will be
19    /// appended to the end of the buffer. If the buffer has enough capacity, and the current
20    /// end of the buffer is correctly aligned, then no additional allocations will be performed.
21    #[doc(hidden)]
22    #[cfg(feature = "alloc")]
23    fn serialize_into_vec<'a>(bitmap: &Bitmap, dst: &'a mut alloc::vec::Vec<u8>) -> &'a mut [u8] {
24        let len = Self::get_serialized_size_in_bytes(bitmap);
25        let spare_capacity =
26            crate::serialization::get_aligned_spare_capacity(dst, Self::REQUIRED_ALIGNMENT, len);
27        let data_start;
28        unsafe {
29            Self::raw_serialize(bitmap, spare_capacity.as_mut_ptr().cast::<c_char>());
30            data_start = dst.len();
31            let total_len = data_start.checked_add(len).unwrap();
32            dst.set_len(total_len);
33        }
34
35        &mut dst[data_start..]
36    }
37
38    #[doc(hidden)]
39    fn try_serialize_into_aligned<'a>(bitmap: &Bitmap, dst: &'a mut [u8]) -> Option<&'a mut [u8]> {
40        let offset = dst.as_ptr().align_offset(Self::REQUIRED_ALIGNMENT);
41        let offset_dst = dst.get_mut(offset..)?;
42        let len = Self::try_serialize_into(bitmap, offset_dst)?;
43        Some(&mut dst[offset..offset + len])
44    }
45
46    /// Serialize a bitmap into bytes, using the provided buffer to store the serialized data
47    ///
48    /// This method does not require the buffer to be aligned, and will return `None` if the buffer
49    /// is not large enough to store the serialized data.
50    ///
51    /// This is a niche method, and is not recommended for general use. The
52    /// [`Bitmap::serialize_into_vec`]/[`Bitmap::try_serialize_into`] methods should usually be used
53    /// instead of this method.
54    fn try_serialize_into(bitmap: &Bitmap, dst: &mut [u8]) -> Option<usize> {
55        let required_len = Self::get_serialized_size_in_bytes(bitmap);
56        if dst.len() < required_len {
57            return None;
58        }
59        unsafe {
60            Self::raw_serialize(bitmap, dst.as_mut_ptr().cast::<c_char>());
61        }
62        Some(required_len)
63    }
64
65    /// Get the number of bytes required to serialize this bitmap
66    ///
67    /// This does not include any additional padding which may be required to align the bitmap
68    #[doc(hidden)]
69    fn get_serialized_size_in_bytes(bitmap: &Bitmap) -> usize;
70
71    #[doc(hidden)]
72    unsafe fn raw_serialize(bitmap: &Bitmap, dst: *mut c_char);
73}
74
75/// Trait for different formats of bitmap deserialization
76pub trait Deserializer: crate::sealed::Sealed {
77    /// Try to deserialize a bitmap from the beginning of the provided buffer
78    ///
79    /// The [`Bitmap::try_deserialize`] method should usually be used instead of this method
80    /// directly.
81    ///
82    /// If the buffer starts with the serialized representation of a bitmap, then
83    /// this method will return a new bitmap containing the deserialized data.
84    ///
85    /// If the buffer does not start with a serialized bitmap (or contains an invalidly
86    /// truncated bitmap), then this method will return `None`.
87    ///
88    /// To determine how many bytes were consumed from the buffer, use the
89    /// [`Serializer::get_serialized_size_in_bytes`] method on the returned bitmap.
90    #[doc(hidden)]
91    fn try_deserialize(buffer: &[u8]) -> Option<Bitmap>;
92
93    /// Deserialize a bitmap from the beginning of the provided buffer
94    ///
95    /// # Safety
96    ///
97    /// Unlike its safe counterpart ([`Self::try_deserialize`]) this function assumes the data is
98    /// valid, passing data which does not contain/start with a bitmap serialized with this format
99    /// will result in undefined behavior.
100    #[doc(hidden)]
101    unsafe fn try_deserialize_unchecked(buffer: &[u8]) -> Bitmap;
102}
103
104/// Trait for different formats of bitmap deserialization into a view without copying
105pub trait ViewDeserializer: crate::sealed::Sealed {
106    /// Create a bitmap view using the passed data
107    ///
108    /// # Safety
109    /// * `data` must be the result of serializing a roaring bitmap in this format.
110    /// * Its beginning must be aligned properly for this format.
111    /// * data.len() must be equal exactly to the size of the serialized bitmap.
112    ///
113    /// See [`BitmapView::deserialize`] for examples.
114    #[doc(hidden)]
115    unsafe fn deserialize_view(data: &[u8]) -> BitmapView<'_>;
116}
117
118impl crate::sealed::Sealed for Portable {}
119impl Serializer for Portable {
120    /// Computes the serialized size in bytes of the Bitmap in portable format.
121    /// See [`Bitmap::get_serialized_size_in_bytes`] for examples.
122    #[doc(alias = "roaring_bitmap_portable_size_in_bytes")]
123    fn get_serialized_size_in_bytes(bitmap: &Bitmap) -> usize {
124        unsafe { ffi::roaring_bitmap_portable_size_in_bytes(&bitmap.bitmap) }
125    }
126
127    unsafe fn raw_serialize(bitmap: &Bitmap, dst: *mut c_char) {
128        unsafe {
129            ffi::roaring_bitmap_portable_serialize(&bitmap.bitmap, dst);
130        }
131    }
132}
133
134impl Deserializer for Portable {
135    /// Given a serialized bitmap as slice of bytes in portable format, returns a `Bitmap` instance.
136    /// See [`Bitmap::try_deserialize`] for examples.
137    #[doc(alias = "roaring_bitmap_portable_deserialize_safe")]
138    fn try_deserialize(buffer: &[u8]) -> Option<Bitmap> {
139        unsafe {
140            let bitmap = ffi::roaring_bitmap_portable_deserialize_safe(
141                buffer.as_ptr().cast::<c_char>(),
142                buffer.len(),
143            );
144
145            if bitmap.is_null() {
146                return None;
147            }
148
149            let bitmap = Bitmap::take_heap(bitmap);
150            if bitmap.internal_validate().is_ok() {
151                Some(bitmap)
152            } else {
153                None
154            }
155        }
156    }
157
158    #[doc(alias = "roaring_bitmap_portable_deserialize")]
159    unsafe fn try_deserialize_unchecked(buffer: &[u8]) -> Bitmap {
160        let bitmap = ffi::roaring_bitmap_portable_deserialize(buffer.as_ptr().cast::<c_char>());
161        Bitmap::take_heap(bitmap)
162    }
163}
164
165impl ViewDeserializer for Portable {
166    /// Read bitmap from a serialized buffer
167    ///
168    /// This is meant to be compatible with the Java and Go versions
169    ///
170    /// # Safety
171    /// * `data` must be the result of serializing a roaring bitmap in portable mode
172    ///   (following `https://github.com/RoaringBitmap/RoaringFormatSpec`), for example, with
173    ///   [`Bitmap::serialize`]
174    /// * Using this function (or the returned bitmap in any way) may execute unaligned memory accesses
175    ///
176    #[doc(alias = "roaring_bitmap_portable_deserialize_frozen")]
177    unsafe fn deserialize_view(data: &[u8]) -> BitmapView<'_> {
178        // portable_deserialize_size does some amount of checks, and returns zero if data cannot be valid
179        debug_assert_ne!(
180            ffi::roaring_bitmap_portable_deserialize_size(data.as_ptr().cast(), data.len()),
181            0,
182        );
183        let roaring = ffi::roaring_bitmap_portable_deserialize_frozen(data.as_ptr().cast());
184        BitmapView::take_heap(roaring)
185    }
186}
187
188impl crate::sealed::Sealed for Native {}
189impl Serializer for Native {
190    /// Computes the serialized size in bytes of the Bitmap in native format.
191    /// See [`Bitmap::get_serialized_size_in_bytes`] for examples.
192    #[doc(alias = "roaring_bitmap_size_in_bytes")]
193    fn get_serialized_size_in_bytes(bitmap: &Bitmap) -> usize {
194        unsafe { ffi::roaring_bitmap_size_in_bytes(&bitmap.bitmap) }
195    }
196
197    unsafe fn raw_serialize(bitmap: &Bitmap, dst: *mut c_char) {
198        unsafe {
199            ffi::roaring_bitmap_serialize(&bitmap.bitmap, dst);
200        }
201    }
202}
203
204impl Deserializer for Native {
205    /// Given a serialized bitmap as slice of bytes in native format, returns a `Bitmap` instance.
206    /// See [`Bitmap::try_deserialize`] for examples.
207    #[doc(alias = "roaring_bitmap_deserialize_safe")]
208    fn try_deserialize(buffer: &[u8]) -> Option<Bitmap> {
209        unsafe {
210            let bitmap = ffi::roaring_bitmap_deserialize_safe(
211                buffer.as_ptr().cast::<c_void>(),
212                buffer.len(),
213            );
214
215            if bitmap.is_null() {
216                return None;
217            }
218            let bitmap = Bitmap::take_heap(bitmap);
219            if bitmap.internal_validate().is_ok() {
220                Some(bitmap)
221            } else {
222                None
223            }
224        }
225    }
226
227    #[doc(alias = "roaring_bitmap_deserialize")]
228    unsafe fn try_deserialize_unchecked(buffer: &[u8]) -> Bitmap {
229        let bitmap = ffi::roaring_bitmap_deserialize(buffer.as_ptr().cast::<c_void>());
230        Bitmap::take_heap(bitmap)
231    }
232}
233
234impl crate::sealed::Sealed for Frozen {}
235impl Serializer for Frozen {
236    // Defer to the innate const on Frozen
237    const REQUIRED_ALIGNMENT: usize = Self::REQUIRED_ALIGNMENT;
238
239    /// Computes the serialized size in bytes of the Bitmap in frozen format.
240    /// See [`Bitmap::get_serialized_size_in_bytes`] for examples.
241    #[doc(alias = "roaring_bitmap_frozen_size_in_bytes")]
242    fn get_serialized_size_in_bytes(bitmap: &Bitmap) -> usize {
243        unsafe { ffi::roaring_bitmap_frozen_size_in_bytes(&bitmap.bitmap) }
244    }
245
246    unsafe fn raw_serialize(bitmap: &Bitmap, dst: *mut c_char) {
247        unsafe {
248            ffi::roaring_bitmap_frozen_serialize(&bitmap.bitmap, dst);
249        }
250    }
251}
252
253impl ViewDeserializer for Frozen {
254    /// Create a frozen bitmap view using the passed data
255    ///
256    /// # Safety
257    /// * `data` must be the result of serializing a roaring bitmap in frozen mode
258    ///   (in c with `roaring_bitmap_frozen_serialize`, or via [`Bitmap::try_serialize_into::<Frozen>`]).
259    /// * Its beginning must be aligned by 32 bytes.
260    /// * data.len() must be equal exactly to the size of the frozen bitmap.
261    ///
262    /// See [`BitmapView::deserialize`] for examples.
263    unsafe fn deserialize_view(data: &[u8]) -> BitmapView<'_> {
264        assert_eq!(data.as_ptr() as usize % Self::REQUIRED_ALIGNMENT, 0);
265
266        let roaring = ffi::roaring_bitmap_frozen_view(data.as_ptr().cast(), data.len());
267        BitmapView::take_heap(roaring)
268    }
269}