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}