croaring/
serialization.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
/// The `Portable` format is meant to be compatible with other roaring bitmap libraries, such as Go or Java.
///
/// Note despite the name, it is not fully portable: it depends on native endianness.
///
/// It's defined here: <https://github.com/RoaringBitmap/RoaringFormatSpec>
pub enum Portable {}

/// The `Native` format format can sometimes be more space efficient than [`Portable`],
///
/// e.g. when the data is sparse. It's not compatible with Java and Go implementations.
/// Use [`Portable`] for that purpose.
pub enum Native {}

/// The `Frozen` format imitates memory layout of the underlying C library.
///
/// This reduces amount of allocations and copying required during deserialization, though
/// `Portable` offers comparable performance.
///
/// Note that because frozen serialization format imitates C memory layout
/// of `roaring_bitmap_t`, it is not fixed. It is different on big/little endian
/// platforms and can be changed in future.
pub enum Frozen {}

impl Frozen {
    /// The frozen format requires bitmaps are aligned to 32 bytes.
    pub const REQUIRED_ALIGNMENT: usize = 32;
}

mod private {
    use crate::{Native, Portable};

    #[allow(unused)]
    pub trait NoAlign: crate::sealed::Sealed {}
    impl NoAlign for Native {}
    impl NoAlign for Portable {}
}

#[allow(unused)]
pub(crate) use private::NoAlign;

/// The `JvmLegacy` format is meant to be compatible with the original Java implementation of `Roaring64NavigableMap`
///
/// It is used only for [Treemap][crate::Treemap]s, not bitmaps.
///
/// See <https://github.com/RoaringBitmap/RoaringBitmap/blob/2669c4f5a49ee7da5ff4cd70e18ee5520018d6a5/RoaringBitmap/src/main/java/org/roaringbitmap/longlong/Roaring64NavigableMap.java#L1215-L1238>
pub enum JvmLegacy {}

#[cfg(feature = "alloc")]
pub(crate) fn get_aligned_spare_capacity(
    dst: &mut alloc::vec::Vec<u8>,
    align: usize,
    required_len: usize,
) -> &mut [core::mem::MaybeUninit<u8>] {
    let max_padding = align - 1;
    let extra_align_required =
        |v: &mut alloc::vec::Vec<u8>| v.spare_capacity_mut().as_ptr().align_offset(align);
    let mut extra_offset = extra_align_required(dst);
    if dst.spare_capacity_mut().len() < required_len + extra_offset {
        dst.reserve(required_len.checked_add(max_padding).unwrap());
        // Need to recompute offset after reserve, as the buffer may have been reallocated and
        // the end of the buffer may be somewhere else
        extra_offset = extra_align_required(dst);
    }
    let mut data_start = dst.len();
    if extra_offset != 0 {
        data_start = data_start.checked_add(extra_offset).unwrap();
        // we must initialize up to offset
        dst.resize(data_start, 0);
    }
    debug_assert_eq!(dst.len(), data_start);
    let spare_capacity = dst.spare_capacity_mut();
    debug_assert!(spare_capacity.len() >= required_len);
    debug_assert_eq!(spare_capacity.as_ptr().align_offset(align), 0);

    &mut spare_capacity[..required_len]
}