/rust/registry/src/index.crates.io-1949cf8c6b5b557f/roaring-0.11.3/src/bitmap/serialization.rs
Line | Count | Source |
1 | | use crate::bitmap::container::{Container, ARRAY_LIMIT}; |
2 | | use crate::bitmap::store::{ |
3 | | ArrayStore, BitmapStore, Interval, Store, BITMAP_BYTES, BITMAP_LENGTH, RUN_ELEMENT_BYTES, |
4 | | RUN_NUM_BYTES, |
5 | | }; |
6 | | use crate::RoaringBitmap; |
7 | | use bytemuck::cast_slice_mut; |
8 | | use byteorder::{LittleEndian, ReadBytesExt, WriteBytesExt}; |
9 | | use core::convert::Infallible; |
10 | | use std::error::Error; |
11 | | use std::io; |
12 | | |
13 | | use super::store::IntervalStore; |
14 | | |
15 | | pub(crate) const SERIAL_COOKIE_NO_RUNCONTAINER: u32 = 12346; |
16 | | pub(crate) const SERIAL_COOKIE: u16 = 12347; |
17 | | pub(crate) const NO_OFFSET_THRESHOLD: usize = 4; |
18 | | |
19 | | // Sizes of header structures |
20 | | pub(crate) const COOKIE_BYTES: usize = 4; |
21 | | pub(crate) const SIZE_BYTES: usize = 4; |
22 | | pub(crate) const DESCRIPTION_BYTES: usize = 4; |
23 | | pub(crate) const OFFSET_BYTES: usize = 4; |
24 | | |
25 | | impl RoaringBitmap { |
26 | | /// Return the size in bytes of the serialized output. |
27 | | /// This is compatible with the official C/C++, Java and Go implementations. |
28 | | /// |
29 | | /// # Examples |
30 | | /// |
31 | | /// ```rust |
32 | | /// use roaring::RoaringBitmap; |
33 | | /// |
34 | | /// let rb1: RoaringBitmap = (1..4).collect(); |
35 | | /// let mut bytes = Vec::with_capacity(rb1.serialized_size()); |
36 | | /// rb1.serialize_into(&mut bytes).unwrap(); |
37 | | /// let rb2 = RoaringBitmap::deserialize_from(&bytes[..]).unwrap(); |
38 | | /// |
39 | | /// assert_eq!(rb1, rb2); |
40 | | /// ``` |
41 | 0 | pub fn serialized_size(&self) -> usize { |
42 | 0 | let mut has_run_containers = false; |
43 | 0 | let size = self.containers.len(); |
44 | 0 | let container_sizes: usize = self |
45 | 0 | .containers |
46 | 0 | .iter() |
47 | 0 | .map(|container| match container.store { |
48 | 0 | Store::Array(ref values) => values.byte_size(), |
49 | 0 | Store::Bitmap(..) => BITMAP_BYTES, |
50 | 0 | Store::Run(ref intervals) => { |
51 | 0 | has_run_containers = true; |
52 | 0 | intervals.byte_size() |
53 | | } |
54 | 0 | }) |
55 | 0 | .sum(); |
56 | | |
57 | | // header + container sizes |
58 | 0 | header_size(size, has_run_containers) + container_sizes |
59 | 0 | } |
60 | | |
61 | | /// Serialize this bitmap into [the standard Roaring on-disk format][format]. |
62 | | /// This is compatible with the official C/C++, Java and Go implementations. |
63 | | /// |
64 | | /// [format]: https://github.com/RoaringBitmap/RoaringFormatSpec |
65 | | /// |
66 | | /// # Examples |
67 | | /// |
68 | | /// ```rust |
69 | | /// use roaring::RoaringBitmap; |
70 | | /// |
71 | | /// let rb1: RoaringBitmap = (1..4).collect(); |
72 | | /// let mut bytes = vec![]; |
73 | | /// rb1.serialize_into(&mut bytes).unwrap(); |
74 | | /// let rb2 = RoaringBitmap::deserialize_from(&bytes[..]).unwrap(); |
75 | | /// |
76 | | /// assert_eq!(rb1, rb2); |
77 | | /// ``` |
78 | 0 | pub fn serialize_into<W: io::Write>(&self, mut writer: W) -> io::Result<()> { |
79 | 0 | let has_run_containers = self.containers.iter().any(|c| matches!(c.store, Store::Run(_))); Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::serialize_into::<&mut alloc::vec::Vec<u8>>::{closure#0}Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::serialize_into::<&mut &mut alloc::vec::Vec<u8>>::{closure#0}Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::serialize_into::<_>::{closure#0} |
80 | 0 | let size = self.containers.len(); |
81 | | |
82 | | // Depending on if run containers are present or not write the appropriate header |
83 | 0 | if has_run_containers { |
84 | | // The new format stores the container count in the most significant bits of the header |
85 | 0 | let cookie = SERIAL_COOKIE as u32 | ((size as u32 - 1) << 16); |
86 | 0 | writer.write_u32::<LittleEndian>(cookie)?; |
87 | | // It is then followed by a bitset indicating which containers are run containers |
88 | 0 | let run_container_bitmap_size = size.div_ceil(8); |
89 | 0 | let mut run_container_bitmap = vec![0; run_container_bitmap_size]; |
90 | 0 | for (i, container) in self.containers.iter().enumerate() { |
91 | 0 | if let Store::Run(_) = container.store { |
92 | 0 | run_container_bitmap[i / 8] |= 1 << (i % 8); |
93 | 0 | } |
94 | | } |
95 | 0 | writer.write_all(&run_container_bitmap)?; |
96 | | } else { |
97 | | // Write old format, cookie followed by container count |
98 | 0 | writer.write_u32::<LittleEndian>(SERIAL_COOKIE_NO_RUNCONTAINER)?; |
99 | 0 | writer.write_u32::<LittleEndian>(size as u32)?; |
100 | | } |
101 | | |
102 | | // Write the container descriptions |
103 | 0 | for container in &self.containers { |
104 | 0 | writer.write_u16::<LittleEndian>(container.key)?; |
105 | 0 | writer.write_u16::<LittleEndian>((container.len() - 1) as u16)?; |
106 | | } |
107 | | |
108 | 0 | let mut offset = header_size(size, has_run_containers) as u32; |
109 | 0 | let has_offsets = if has_run_containers { size >= OFFSET_BYTES } else { true }; |
110 | 0 | if has_offsets { |
111 | 0 | for container in &self.containers { |
112 | 0 | writer.write_u32::<LittleEndian>(offset)?; |
113 | 0 | match container.store { |
114 | 0 | Store::Array(ref values) => { |
115 | 0 | offset += values.len() as u32 * 2; |
116 | 0 | } |
117 | 0 | Store::Bitmap(..) => { |
118 | 0 | offset += 8 * 1024; |
119 | 0 | } |
120 | 0 | Store::Run(ref intervals) => { |
121 | 0 | offset += (RUN_NUM_BYTES |
122 | 0 | + (intervals.run_amount() as usize * RUN_ELEMENT_BYTES)) |
123 | 0 | as u32; |
124 | 0 | } |
125 | | } |
126 | | } |
127 | 0 | } |
128 | | |
129 | 0 | for container in &self.containers { |
130 | 0 | match container.store { |
131 | 0 | Store::Array(ref values) => { |
132 | 0 | for &value in values.iter() { |
133 | 0 | writer.write_u16::<LittleEndian>(value)?; |
134 | | } |
135 | | } |
136 | 0 | Store::Bitmap(ref bits) => { |
137 | 0 | for &value in bits.as_array() { |
138 | 0 | writer.write_u64::<LittleEndian>(value)?; |
139 | | } |
140 | | } |
141 | 0 | Store::Run(ref intervals) => { |
142 | 0 | writer.write_u16::<LittleEndian>(intervals.run_amount() as u16)?; |
143 | 0 | for iv in intervals.iter_intervals() { |
144 | 0 | writer.write_u16::<LittleEndian>(iv.start())?; |
145 | 0 | writer.write_u16::<LittleEndian>(iv.end() - iv.start())?; |
146 | | } |
147 | | } |
148 | | } |
149 | | } |
150 | | |
151 | 0 | Ok(()) |
152 | 0 | } Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::serialize_into::<&mut alloc::vec::Vec<u8>> Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::serialize_into::<&mut &mut alloc::vec::Vec<u8>> Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::serialize_into::<_> |
153 | | |
154 | | /// Deserialize a bitmap into memory from [the standard Roaring on-disk |
155 | | /// format][format]. This is compatible with the official C/C++, Java and |
156 | | /// Go implementations. This method checks that all of the internal values |
157 | | /// are valid. If deserializing from a trusted source consider |
158 | | /// [RoaringBitmap::deserialize_unchecked_from] |
159 | | /// |
160 | | /// [format]: https://github.com/RoaringBitmap/RoaringFormatSpec |
161 | | /// |
162 | | /// # Examples |
163 | | /// |
164 | | /// ```rust |
165 | | /// use roaring::RoaringBitmap; |
166 | | /// |
167 | | /// let rb1: RoaringBitmap = (1..4).collect(); |
168 | | /// let mut bytes = vec![]; |
169 | | /// rb1.serialize_into(&mut bytes).unwrap(); |
170 | | /// let rb2 = RoaringBitmap::deserialize_from(&bytes[..]).unwrap(); |
171 | | /// |
172 | | /// assert_eq!(rb1, rb2); |
173 | | /// ``` |
174 | 0 | pub fn deserialize_from<R: io::Read>(reader: R) -> io::Result<RoaringBitmap> { |
175 | 0 | RoaringBitmap::deserialize_from_impl(reader, ArrayStore::try_from, BitmapStore::try_from) |
176 | 0 | } Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from::<&mut &mut &[u8]> Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from::<&mut &[u8]> Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from::<_> |
177 | | |
178 | | /// Deserialize a bitmap into memory from [the standard Roaring on-disk |
179 | | /// format][format]. This is compatible with the official C/C++, Java and |
180 | | /// Go implementations. This method is memory safe but will not check if |
181 | | /// the data is a valid bitmap. |
182 | | /// |
183 | | /// [format]: https://github.com/RoaringBitmap/RoaringFormatSpec |
184 | | /// |
185 | | /// # Examples |
186 | | /// |
187 | | /// ```rust |
188 | | /// use roaring::RoaringBitmap; |
189 | | /// |
190 | | /// let rb1: RoaringBitmap = (1..4).collect(); |
191 | | /// let mut bytes = vec![]; |
192 | | /// rb1.serialize_into(&mut bytes).unwrap(); |
193 | | /// let rb2 = RoaringBitmap::deserialize_unchecked_from(&bytes[..]).unwrap(); |
194 | | /// |
195 | | /// assert_eq!(rb1, rb2); |
196 | | /// ``` |
197 | 0 | pub fn deserialize_unchecked_from<R: io::Read>(reader: R) -> io::Result<RoaringBitmap> { |
198 | 0 | RoaringBitmap::deserialize_from_impl::<R, _, Infallible, _, Infallible>( |
199 | 0 | reader, |
200 | 0 | |values| Ok(ArrayStore::from_vec_unchecked(values)), |
201 | 0 | |len, values| Ok(BitmapStore::from_unchecked(len, values)), |
202 | | ) |
203 | 0 | } |
204 | | |
205 | 0 | fn deserialize_from_impl<R, A, AErr, B, BErr>( |
206 | 0 | mut reader: R, |
207 | 0 | a: A, |
208 | 0 | b: B, |
209 | 0 | ) -> io::Result<RoaringBitmap> |
210 | 0 | where |
211 | 0 | R: io::Read, |
212 | 0 | A: Fn(Vec<u16>) -> Result<ArrayStore, AErr>, |
213 | 0 | AErr: Error + Send + Sync + 'static, |
214 | 0 | B: Fn(u64, Box<[u64; 1024]>) -> Result<BitmapStore, BErr>, |
215 | 0 | BErr: Error + Send + Sync + 'static, |
216 | | { |
217 | | // First read the cookie to determine which version of the format we are reading |
218 | 0 | let (size, has_offsets, has_run_containers) = { |
219 | 0 | let cookie = reader.read_u32::<LittleEndian>()?; |
220 | 0 | if cookie == SERIAL_COOKIE_NO_RUNCONTAINER { |
221 | 0 | (reader.read_u32::<LittleEndian>()? as usize, true, false) |
222 | 0 | } else if (cookie as u16) == SERIAL_COOKIE { |
223 | 0 | let size = ((cookie >> 16) + 1) as usize; |
224 | 0 | (size, size >= NO_OFFSET_THRESHOLD, true) |
225 | | } else { |
226 | 0 | return Err(io::Error::other("unknown cookie value")); |
227 | | } |
228 | | }; |
229 | | |
230 | | // Read the run container bitmap if necessary |
231 | 0 | let run_container_bitmap = if has_run_containers { |
232 | 0 | let mut bitmap = vec![0u8; size.div_ceil(8)]; |
233 | 0 | reader.read_exact(&mut bitmap)?; |
234 | 0 | Some(bitmap) |
235 | | } else { |
236 | 0 | None |
237 | | }; |
238 | | |
239 | 0 | if size > u16::MAX as usize + 1 { |
240 | 0 | return Err(io::Error::other("size is greater than supported")); |
241 | 0 | } |
242 | | |
243 | | // Read the container descriptions |
244 | 0 | let mut description_bytes = vec![0u8; size * DESCRIPTION_BYTES]; |
245 | 0 | reader.read_exact(&mut description_bytes)?; |
246 | 0 | let mut description_bytes = &description_bytes[..]; |
247 | | |
248 | 0 | if has_offsets { |
249 | 0 | let mut offsets = vec![0u8; size * OFFSET_BYTES]; |
250 | 0 | reader.read_exact(&mut offsets)?; |
251 | 0 | drop(offsets); // Not useful when deserializing into memory |
252 | 0 | } |
253 | | |
254 | 0 | let mut containers = Vec::with_capacity(size); |
255 | | |
256 | 0 | let mut last_key = None::<u16>; |
257 | | // Read each container |
258 | 0 | for i in 0..size { |
259 | 0 | let key = description_bytes.read_u16::<LittleEndian>()?; |
260 | 0 | if let Some(last_key) = last_key.replace(key) { |
261 | 0 | if key <= last_key { |
262 | 0 | return Err(io::Error::new( |
263 | 0 | io::ErrorKind::InvalidData, |
264 | 0 | "container keys are not sorted", |
265 | 0 | )); |
266 | 0 | } |
267 | 0 | } |
268 | 0 | let cardinality = u64::from(description_bytes.read_u16::<LittleEndian>()?) + 1; |
269 | | |
270 | | // If the run container bitmap is present, check if this container is a run container |
271 | 0 | let is_run_container = |
272 | 0 | run_container_bitmap.as_ref().is_some_and(|bm| bm[i / 8] & (1 << (i % 8)) != 0); Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<&mut &mut &[u8], <roaring::bitmap::store::array_store::ArrayStore as core::convert::TryFrom<alloc::vec::Vec<u16>>>::try_from, roaring::bitmap::store::array_store::Error, <roaring::bitmap::store::bitmap_store::BitmapStore>::try_from, roaring::bitmap::store::bitmap_store::Error>::{closure#0}Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<&mut &[u8], <roaring::bitmap::store::array_store::ArrayStore as core::convert::TryFrom<alloc::vec::Vec<u16>>>::try_from, roaring::bitmap::store::array_store::Error, <roaring::bitmap::store::bitmap_store::BitmapStore>::try_from, roaring::bitmap::store::bitmap_store::Error>::{closure#0}Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<_, _, _, _, _>::{closure#0} |
273 | | |
274 | 0 | let store = if is_run_container { |
275 | 0 | let runs = reader.read_u16::<LittleEndian>()?; |
276 | 0 | if runs == 0 { |
277 | 0 | return Err(io::Error::new( |
278 | 0 | io::ErrorKind::InvalidData, |
279 | 0 | "run container with zero runs", |
280 | 0 | )); |
281 | 0 | } |
282 | 0 | let mut intervals = vec![[0, 0]; runs as usize]; |
283 | 0 | reader.read_exact(cast_slice_mut(&mut intervals))?; |
284 | 0 | intervals.iter_mut().for_each(|[s, len]| { |
285 | 0 | *s = u16::from_le(*s); |
286 | 0 | *len = u16::from_le(*len); |
287 | 0 | }); Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<&mut &mut &[u8], <roaring::bitmap::store::array_store::ArrayStore as core::convert::TryFrom<alloc::vec::Vec<u16>>>::try_from, roaring::bitmap::store::array_store::Error, <roaring::bitmap::store::bitmap_store::BitmapStore>::try_from, roaring::bitmap::store::bitmap_store::Error>::{closure#1}Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<&mut &[u8], <roaring::bitmap::store::array_store::ArrayStore as core::convert::TryFrom<alloc::vec::Vec<u16>>>::try_from, roaring::bitmap::store::array_store::Error, <roaring::bitmap::store::bitmap_store::BitmapStore>::try_from, roaring::bitmap::store::bitmap_store::Error>::{closure#1}Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<_, _, _, _, _>::{closure#1} |
288 | | |
289 | 0 | let mut last_end = None::<u16>; |
290 | 0 | let store = IntervalStore::from_vec_unchecked( |
291 | 0 | intervals |
292 | 0 | .into_iter() |
293 | 0 | .map(|[s, len]| -> Result<Interval, io::ErrorKind> { |
294 | 0 | let end = s.checked_add(len).ok_or(io::ErrorKind::InvalidData)?; |
295 | 0 | if let Some(last_end) = last_end.replace(end) { |
296 | 0 | if s <= last_end.saturating_add(1) { |
297 | | // Range overlaps or would be contiguous with the previous range |
298 | 0 | return Err(io::ErrorKind::InvalidData); |
299 | 0 | } |
300 | 0 | } |
301 | 0 | Ok(Interval::new_unchecked(s, end)) |
302 | 0 | }) Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<&mut &mut &[u8], <roaring::bitmap::store::array_store::ArrayStore as core::convert::TryFrom<alloc::vec::Vec<u16>>>::try_from, roaring::bitmap::store::array_store::Error, <roaring::bitmap::store::bitmap_store::BitmapStore>::try_from, roaring::bitmap::store::bitmap_store::Error>::{closure#2}Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<&mut &[u8], <roaring::bitmap::store::array_store::ArrayStore as core::convert::TryFrom<alloc::vec::Vec<u16>>>::try_from, roaring::bitmap::store::array_store::Error, <roaring::bitmap::store::bitmap_store::BitmapStore>::try_from, roaring::bitmap::store::bitmap_store::Error>::{closure#2}Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<_, _, _, _, _>::{closure#2} |
303 | 0 | .collect::<Result<_, _>>()?, |
304 | | ); |
305 | 0 | Store::Run(store) |
306 | 0 | } else if cardinality <= ARRAY_LIMIT { |
307 | 0 | let mut values = vec![0; cardinality as usize]; |
308 | 0 | reader.read_exact(cast_slice_mut(&mut values))?; |
309 | 0 | values.iter_mut().for_each(|n| *n = u16::from_le(*n)); Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<&mut &mut &[u8], <roaring::bitmap::store::array_store::ArrayStore as core::convert::TryFrom<alloc::vec::Vec<u16>>>::try_from, roaring::bitmap::store::array_store::Error, <roaring::bitmap::store::bitmap_store::BitmapStore>::try_from, roaring::bitmap::store::bitmap_store::Error>::{closure#3}Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<&mut &[u8], <roaring::bitmap::store::array_store::ArrayStore as core::convert::TryFrom<alloc::vec::Vec<u16>>>::try_from, roaring::bitmap::store::array_store::Error, <roaring::bitmap::store::bitmap_store::BitmapStore>::try_from, roaring::bitmap::store::bitmap_store::Error>::{closure#3}Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<_, _, _, _, _>::{closure#3} |
310 | 0 | let array = a(values).map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<&mut &mut &[u8], <roaring::bitmap::store::array_store::ArrayStore as core::convert::TryFrom<alloc::vec::Vec<u16>>>::try_from, roaring::bitmap::store::array_store::Error, <roaring::bitmap::store::bitmap_store::BitmapStore>::try_from, roaring::bitmap::store::bitmap_store::Error>::{closure#4}Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<&mut &[u8], <roaring::bitmap::store::array_store::ArrayStore as core::convert::TryFrom<alloc::vec::Vec<u16>>>::try_from, roaring::bitmap::store::array_store::Error, <roaring::bitmap::store::bitmap_store::BitmapStore>::try_from, roaring::bitmap::store::bitmap_store::Error>::{closure#4}Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<_, _, _, _, _>::{closure#4} |
311 | 0 | Store::Array(array) |
312 | | } else { |
313 | 0 | let mut values = Box::new([0; BITMAP_LENGTH]); |
314 | 0 | reader.read_exact(cast_slice_mut(&mut values[..]))?; |
315 | 0 | values.iter_mut().for_each(|n| *n = u64::from_le(*n)); Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<&mut &mut &[u8], <roaring::bitmap::store::array_store::ArrayStore as core::convert::TryFrom<alloc::vec::Vec<u16>>>::try_from, roaring::bitmap::store::array_store::Error, <roaring::bitmap::store::bitmap_store::BitmapStore>::try_from, roaring::bitmap::store::bitmap_store::Error>::{closure#5}Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<&mut &[u8], <roaring::bitmap::store::array_store::ArrayStore as core::convert::TryFrom<alloc::vec::Vec<u16>>>::try_from, roaring::bitmap::store::array_store::Error, <roaring::bitmap::store::bitmap_store::BitmapStore>::try_from, roaring::bitmap::store::bitmap_store::Error>::{closure#5}Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<_, _, _, _, _>::{closure#5} |
316 | 0 | let bitmap = b(cardinality, values) |
317 | 0 | .map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?; Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<&mut &mut &[u8], <roaring::bitmap::store::array_store::ArrayStore as core::convert::TryFrom<alloc::vec::Vec<u16>>>::try_from, roaring::bitmap::store::array_store::Error, <roaring::bitmap::store::bitmap_store::BitmapStore>::try_from, roaring::bitmap::store::bitmap_store::Error>::{closure#6}Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<&mut &[u8], <roaring::bitmap::store::array_store::ArrayStore as core::convert::TryFrom<alloc::vec::Vec<u16>>>::try_from, roaring::bitmap::store::array_store::Error, <roaring::bitmap::store::bitmap_store::BitmapStore>::try_from, roaring::bitmap::store::bitmap_store::Error>::{closure#6}Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<_, _, _, _, _>::{closure#6} |
318 | 0 | Store::Bitmap(bitmap) |
319 | | }; |
320 | | |
321 | 0 | containers.push(Container { key, store }); |
322 | | } |
323 | | |
324 | 0 | Ok(RoaringBitmap { containers }) |
325 | 0 | } Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<&mut &mut &[u8], <roaring::bitmap::store::array_store::ArrayStore as core::convert::TryFrom<alloc::vec::Vec<u16>>>::try_from, roaring::bitmap::store::array_store::Error, <roaring::bitmap::store::bitmap_store::BitmapStore>::try_from, roaring::bitmap::store::bitmap_store::Error> Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<&mut &[u8], <roaring::bitmap::store::array_store::ArrayStore as core::convert::TryFrom<alloc::vec::Vec<u16>>>::try_from, roaring::bitmap::store::array_store::Error, <roaring::bitmap::store::bitmap_store::BitmapStore>::try_from, roaring::bitmap::store::bitmap_store::Error> Unexecuted instantiation: <roaring::bitmap::RoaringBitmap>::deserialize_from_impl::<_, _, _, _, _> |
326 | | } |
327 | | |
328 | 0 | fn header_size(size: usize, has_run_containers: bool) -> usize { |
329 | 0 | if has_run_containers { |
330 | | // New format encodes the size (number of containers) into the 4 byte cookie |
331 | | // Additionally a bitmap is included marking which containers are run containers |
332 | 0 | let run_container_bitmap_size = size.div_ceil(8); |
333 | | // New format conditionally includes offsets if there are 4 or more containers |
334 | 0 | if size >= NO_OFFSET_THRESHOLD { |
335 | 0 | COOKIE_BYTES + ((DESCRIPTION_BYTES + OFFSET_BYTES) * size) + run_container_bitmap_size |
336 | | } else { |
337 | 0 | COOKIE_BYTES + (DESCRIPTION_BYTES * size) + run_container_bitmap_size |
338 | | } |
339 | | } else { |
340 | | // Old format encodes cookie followed by container count |
341 | | // It also always includes the offsets |
342 | 0 | COOKIE_BYTES + SIZE_BYTES + ((DESCRIPTION_BYTES + OFFSET_BYTES) * size) |
343 | | } |
344 | 0 | } |
345 | | |
346 | | #[cfg(test)] |
347 | | mod test { |
348 | | use crate::{bitmap::store::BITMAP_LENGTH, RoaringBitmap}; |
349 | | use proptest::prelude::*; |
350 | | |
351 | | proptest! { |
352 | | #[test] |
353 | | fn test_serialization( |
354 | | bitmap in RoaringBitmap::arbitrary(), |
355 | | ) { |
356 | | let mut buffer = Vec::new(); |
357 | | bitmap.serialize_into(&mut buffer).unwrap(); |
358 | | prop_assert_eq!(bitmap, RoaringBitmap::deserialize_from(buffer.as_slice()).unwrap()); |
359 | | } |
360 | | } |
361 | | |
362 | | #[test] |
363 | | fn test_from_lsb0_bytes() { |
364 | | const CONTAINER_OFFSET: u32 = u64::BITS * BITMAP_LENGTH as u32; |
365 | | const CONTAINER_OFFSET_IN_BYTES: u32 = CONTAINER_OFFSET / 8; |
366 | | let mut bytes = vec![0xff; CONTAINER_OFFSET_IN_BYTES as usize]; |
367 | | bytes.extend([0x00; CONTAINER_OFFSET_IN_BYTES as usize]); |
368 | | bytes.extend([0b00000001, 0b00000010, 0b00000011, 0b00000100]); |
369 | | |
370 | | let offset = 32; |
371 | | let rb = RoaringBitmap::from_lsb0_bytes(offset, &bytes); |
372 | | for i in 0..offset { |
373 | | assert!(!rb.contains(i), "{i} should not be in the bitmap"); |
374 | | } |
375 | | for i in offset..offset + CONTAINER_OFFSET { |
376 | | assert!(rb.contains(i), "{i} should be in the bitmap"); |
377 | | } |
378 | | for i in offset + CONTAINER_OFFSET..offset + CONTAINER_OFFSET * 2 { |
379 | | assert!(!rb.contains(i), "{i} should not be in the bitmap"); |
380 | | } |
381 | | for bit in [0, 9, 16, 17, 26] { |
382 | | let i = bit + offset + CONTAINER_OFFSET * 2; |
383 | | assert!(rb.contains(i), "{i} should be in the bitmap"); |
384 | | } |
385 | | |
386 | | assert_eq!(rb.len(), CONTAINER_OFFSET as u64 + 5); |
387 | | |
388 | | // Ensure the empty container is not created |
389 | | let mut bytes = vec![0x00u8; CONTAINER_OFFSET_IN_BYTES as usize]; |
390 | | bytes.extend([0xff]); |
391 | | let rb = RoaringBitmap::from_lsb0_bytes(0, &bytes); |
392 | | assert_eq!(rb.min(), Some(CONTAINER_OFFSET)); |
393 | | |
394 | | let rb = RoaringBitmap::from_lsb0_bytes(8, &bytes); |
395 | | assert_eq!(rb.min(), Some(CONTAINER_OFFSET + 8)); |
396 | | |
397 | | // Ensure we can set the last byte in an array container |
398 | | let bytes = [0x80]; |
399 | | let rb = RoaringBitmap::from_lsb0_bytes(0xFFFFFFF8, &bytes); |
400 | | assert_eq!(rb.len(), 1); |
401 | | assert!(rb.contains(u32::MAX)); |
402 | | |
403 | | // Ensure we can set the last byte in a bitmap container |
404 | | let bytes = vec![0xFF; 0x1_0000 / 8]; |
405 | | let rb = RoaringBitmap::from_lsb0_bytes(0xFFFF0000, &bytes); |
406 | | assert_eq!(rb.len(), 0x1_0000); |
407 | | assert!(rb.contains(u32::MAX)); |
408 | | } |
409 | | |
410 | | #[test] |
411 | | fn test_from_lsb0_bytes_not_multiple_of_8() { |
412 | | const CONTAINER_OFFSET: u32 = u64::BITS * BITMAP_LENGTH as u32; |
413 | | const CONTAINER_OFFSET_IN_BYTES: u32 = CONTAINER_OFFSET / 8; |
414 | | |
415 | | let mut bytes = vec![0b0101_1001]; |
416 | | bytes.extend([0x00; CONTAINER_OFFSET_IN_BYTES as usize]); |
417 | | bytes.extend([0b00000001, 0b00000010, 0b00000011, 0b00000100]); |
418 | | |
419 | | let mut indices = vec![0, 3, 4, 6]; |
420 | | indices.extend([0, 9, 16, 17, 26].map(|i| 8 + CONTAINER_OFFSET + i)); |
421 | | |
422 | | for offset in 0..8 { |
423 | | let rb = RoaringBitmap::from_lsb0_bytes(offset, &bytes); |
424 | | for i in indices.iter().map(|&i| i + offset) { |
425 | | assert!(rb.contains(i), "{i} should be in the bitmap"); |
426 | | } |
427 | | } |
428 | | } |
429 | | |
430 | | #[test] |
431 | | #[should_panic(expected = "<= 2^32")] |
432 | | fn test_from_lsb0_bytes_overflow() { |
433 | | let bytes = [0x01, 0x01]; |
434 | | RoaringBitmap::from_lsb0_bytes(u32::MAX - 7, &bytes); |
435 | | } |
436 | | |
437 | | #[test] |
438 | | fn test_deserialize_overflow_s_plus_len() { |
439 | | let data = vec![59, 48, 0, 0, 255, 130, 254, 59, 48, 2, 0, 41, 255, 255, 166, 197, 4, 0, 2]; |
440 | | let res = RoaringBitmap::deserialize_from(data.as_slice()); |
441 | | assert!(res.is_err()); |
442 | | } |
443 | | } |