smol_bitmap/
ser.rs

1//! Serialization of `SmolBitmap`.
2
3use core::{ptr, slice};
4
5use alloc::{borrow::Cow, vec::Vec};
6
7use crate::{SmolBitmap, storage::SmolBitmapBuilder};
8
9impl SmolBitmap {
10    /// Converts the bitmap to a byte slice in native-endian order.
11    ///
12    /// This method provides a view of the bitmap's internal representation
13    /// as a slice of bytes. The byte order is native-endian, meaning it
14    /// matches the endianness of the host system.
15    ///
16    /// # Safety
17    ///
18    /// The returned slice is valid as long as the bitmap is not modified.
19    /// Modifying the bitmap while holding a reference to this slice may
20    /// lead to undefined behavior.
21    ///
22    /// # Examples
23    ///
24    /// ```
25    /// use smol_bitmap::SmolBitmap;
26    ///
27    /// let mut bitmap = SmolBitmap::new();
28    /// bitmap.insert(0);
29    /// let bytes = bitmap.to_ne_bytes();
30    /// assert_eq!(bytes[0], 0b00000001);
31    /// ```
32    #[inline(always)]
33    #[must_use]
34    pub const fn to_ne_bytes(&self) -> &[u8] {
35        let slice = self.as_slice_rtrim();
36        unsafe { slice::from_raw_parts(slice.as_ptr().cast::<u8>(), slice.len() * 8) }
37    }
38
39    /// Constructs a bitmap from a byte slice in native-endian order.
40    ///
41    /// This method reads bytes in native-endian order and constructs a
42    /// [`SmolBitmap`] from them. Any remaining bytes that do not form a
43    /// complete word are returned as a separate slice.
44    ///
45    /// # Safety
46    ///
47    /// The input byte slice must be properly aligned and sized to match
48    /// the internal representation of the bitmap. Misalignment or incorrect
49    /// sizing may lead to undefined behavior.
50    #[inline(always)]
51    #[must_use]
52    pub fn from_ne_bytes(bytes: &[u8]) -> (Self, &[u8]) {
53        let (words, rest) = bytes.as_chunks::<8>();
54        let mut builder = SmolBitmapBuilder::with_capacity(words.len());
55        unsafe {
56            ptr::copy_nonoverlapping(
57                words.as_ptr().cast::<u8>(),
58                builder.as_mut_ptr().cast::<u8>(),
59                words.len() * 8,
60            );
61            builder.set_len(words.len());
62        }
63        (builder.into(), rest)
64    }
65}
66
67#[cfg(target_endian = "little")]
68impl SmolBitmap {
69    /// Converts the bitmap to little-endian bytes.
70    ///
71    /// # Examples
72    ///
73    /// ```
74    /// use smol_bitmap::SmolBitmap;
75    ///
76    /// let mut bitmap = SmolBitmap::new();
77    /// bitmap.insert(0);
78    /// bitmap.insert(7);
79    /// bitmap.insert(8);
80    ///
81    /// let bytes = bitmap.to_le_bytes();
82    /// assert_eq!(bytes[0], 0b10000001); // bits 0 and 7
83    /// assert_eq!(bytes[1], 0b00000001); // bit 8
84    /// ```
85    #[must_use]
86    pub const fn to_le_bytes(&self) -> Cow<'_, [u8]> {
87        Cow::Borrowed(self.to_ne_bytes())
88    }
89
90    /// Constructs a bitmap from little-endian bytes.
91    ///
92    /// # Examples
93    ///
94    /// ```
95    /// use smol_bitmap::SmolBitmap;
96    ///
97    /// let bytes = [0b10000001, 0b00000001, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
98    /// let (bitmap, _rest) = SmolBitmap::from_le_bytes(&bytes);
99    ///
100    /// assert!(bitmap.get(0)); // bit 0 from byte 0
101    /// assert!(bitmap.get(7)); // bit 7 from byte 0
102    /// assert!(bitmap.get(8)); // bit 0 from byte 1
103    /// ```
104    #[must_use]
105    pub fn from_le_bytes(bytes: &[u8]) -> (Self, &[u8]) {
106        Self::from_ne_bytes(bytes)
107    }
108
109    /// Converts the bitmap to big-endian bytes.
110    ///
111    /// # Examples
112    ///
113    /// ```
114    /// use smol_bitmap::SmolBitmap;
115    ///
116    /// let mut bitmap = SmolBitmap::new();
117    /// bitmap.insert(0);
118    /// bitmap.insert(7);
119    ///
120    /// let bytes = bitmap.to_be_bytes();
121    /// // Big-endian representation
122    /// ```
123    #[must_use]
124    pub fn to_be_bytes(&self) -> Cow<'_, [u8]> {
125        let slice = self.as_slice_rtrim();
126        let mut bytes = Vec::with_capacity(slice.len() * 8);
127        bytes.extend(slice.iter().flat_map(|&word| word.to_be_bytes()));
128        Cow::Owned(bytes)
129    }
130
131    /// Constructs a bitmap from big-endian bytes.
132    ///
133    /// # Examples
134    ///
135    /// ```
136    /// use smol_bitmap::SmolBitmap;
137    ///
138    /// let bytes = vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00]; // Big-endian representation
139    /// let (bitmap, _rest) = SmolBitmap::from_be_bytes(&bytes);
140    ///
141    /// assert!(bitmap.get(8)); // The high bit of the first byte
142    /// ```
143    #[must_use]
144    pub fn from_be_bytes(bytes: &[u8]) -> (Self, &[u8]) {
145        let (words, rest) = bytes.as_chunks::<8>();
146        let builder = words
147            .iter()
148            .map(|&w| u64::from_be_bytes(w))
149            .collect::<SmolBitmapBuilder>();
150        (builder.into(), rest)
151    }
152}
153
154#[cfg(target_endian = "big")]
155impl SmolBitmap {
156    /// Converts the bitmap to big-endian bytes.
157    ///
158    /// # Examples
159    ///
160    /// ```
161    /// use smol_bitmap::SmolBitmap;
162    ///
163    /// let mut bitmap = SmolBitmap::new();
164    /// bitmap.insert(0);
165    /// bitmap.insert(7);
166    ///
167    /// let bytes = bitmap.to_be_bytes();
168    /// // Big-endian representation
169    /// ```
170    #[must_use]
171    pub const fn to_be_bytes(&self) -> Cow<'_, [u8]> {
172        Cow::Borrowed(self.to_ne_bytes())
173    }
174
175    /// Constructs a bitmap from big-endian bytes.
176    ///
177    /// # Examples
178    ///
179    /// ```
180    /// use smol_bitmap::SmolBitmap;
181    ///
182    /// let bytes = vec![0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00]; // Big-endian representation
183    /// let (bitmap, _rest) = SmolBitmap::from_be_bytes(&bytes);
184    ///
185    /// assert!(bitmap.get(8)); // The high bit of the first byte
186    /// ```
187    #[must_use]
188    pub fn from_be_bytes(bytes: &[u8]) -> (Self, &[u8]) {
189        Self::from_ne_bytes(bytes)
190    }
191
192    /// Converts the bitmap to little-endian bytes.
193    ///
194    /// # Examples
195    ///
196    /// ```
197    /// use smol_bitmap::SmolBitmap;
198    ///
199    /// let mut bitmap = SmolBitmap::new();
200    /// bitmap.insert(0);
201    /// bitmap.insert(7);
202    /// bitmap.insert(8);
203    ///
204    /// let bytes = bitmap.to_le_bytes();
205    /// assert_eq!(bytes[0], 0b10000001); // bits 0 and 7
206    /// assert_eq!(bytes[1], 0b00000001); // bit 8
207    /// ```
208    #[must_use]
209    pub fn to_le_bytes(&self) -> Cow<'_, [u8]> {
210        let slice = self.as_slice_rtrim();
211        let mut bytes = Vec::with_capacity(slice.len() * 8);
212        bytes.extend(slice.iter().flat_map(|&word| word.to_le_bytes()));
213        Cow::Owned(bytes)
214    }
215
216    /// Constructs a bitmap from little-endian bytes.
217    ///
218    /// # Examples
219    ///
220    /// ```
221    /// use smol_bitmap::SmolBitmap;
222    ///
223    /// let bytes = [0b10000001, 0b00000001, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00];
224    /// let (bitmap, _rest) = SmolBitmap::from_le_bytes(&bytes);
225    ///
226    /// assert!(bitmap.get(0)); // bit 0 from byte 0
227    /// assert!(bitmap.get(7)); // bit 7 from byte 0
228    /// assert!(bitmap.get(8)); // bit 0 from byte 1
229    /// ```
230    #[must_use]
231    pub fn from_le_bytes(bytes: &[u8]) -> (Self, &[u8]) {
232        let (words, rest) = bytes.as_chunks::<8>();
233        let builder = words
234            .iter()
235            .map(|&w| u64::from_le_bytes(w))
236            .collect::<SmolBitmapBuilder>();
237        (builder.into(), rest)
238    }
239}