devela/data/codec/bit/wrapper/primitives.rs
1// devela::data::codec::bit::ops::wrapper::primitives
2//
3//! Implements `Bitwise` for the integer primitives.
4//
5
6#[cfg(_bit··)]
7use crate::{
8 iif, Bitwise,
9 MismatchedBounds::{self, DataOverflow, IndexOutOfBounds, MismatchedIndices},
10};
11
12macro_rules! impl_bits_wrapper {
13 () => {
14 impl_bits_wrapper![
15 i8:"_bit_i8", i16:"_bit_i16", i32:"_bit_i32",
16 i64:"_bit_i64", i128:"_bit_i128", isize:"_bit_isize",
17 u8:"_bit_u8", u16:"_bit_u16", u32:"_bit_u32",
18 u64:"_bit_u64", u128:"_bit_u128", usize:"_bit_usize"
19 ];
20 };
21 ( $( $t:ty : $cap:literal ),+ ) => { $( impl_bits_wrapper![@$t : $cap]; )+ };
22
23 // `$t`: the primitive type
24 // $cap: the capability feature that enables the given implementation. E.g "_bit_u8".
25 (@$t:ty : $cap:literal) => {
26 /* impl traits */
27
28 #[doc = concat!["# Implementation for `", stringify!($t), "`."]]
29 #[cfg(feature = $cap )]
30 #[cfg_attr(feature = "nightly_doc", doc(cfg(feature = $cap)))]
31 impl Bitwise::<$t> {
32 /* constants */
33
34 /// The size in bits.
35 pub const BITS: u32 = <$t>::BITS;
36
37 /* new mask */
38
39 /// Returns a new bitmask of 1s from the `[start..=end]` range.
40 ///
41 /// Sets the rest of the bits to 0.
42 ///
43 /// # Panics
44 /// Panics if `start >= BITS || end >= BITS || start > end`.
45 #[doc = include_str!("../benches/mask_range.md")]
46 #[must_use]
47 pub const fn mask_range(start: u32, end: u32) -> Self {
48 debug_assert![start <= end];
49 // a mask with all bits set, from 0 to end:
50 let mask_end = iif![end == <$t>::BITS -1; !0; (1 << (end + 1)) - 1];
51 // a mask with all bits set from 0 to start - 1:
52 let mask_start = iif![start == 0; 0; (1 << start) - 1];
53 Self(mask_end - mask_start)
54 }
55 /// Returns a new bitmask of ones from the `[start..=end]` checked range.
56 ///
57 /// Sets the rest of the bits to 0.
58 ///
59 /// # Errors
60 /// Returns [`IndexOutOfBounds`] if `start >= BITS || end >= BITS` and
61 /// [`MismatchedIndices`] if `start > end`.
62 #[doc = include_str!("../benches/mask_checked_range.md")]
63 pub const fn mask_checked_range(start: u32, end: u32)
64 -> Result<Self, MismatchedBounds> {
65 if start >= <$t>::BITS {
66 Err(IndexOutOfBounds(Some(start as usize)))
67 } else if end >= <$t>::BITS {
68 Err(IndexOutOfBounds(Some(end as usize)))
69 } else if start > end {
70 Err(MismatchedIndices)
71 } else {
72 // create a mask with all bits set, from 0 to end:
73 let mask_end = iif![end == <$t>::BITS -1; !0; (1 << (end + 1)) - 1];
74 // create a mask with all bits set from 0 to start - 1:
75 let mask_start = iif![start == 0; 0; (1 << start) - 1];
76 Ok(Self(mask_end - mask_start))
77 }
78 }
79
80 /* get */
81
82 /// Gets the bits in `self` from the `[start..=end]` range.
83 ///
84 /// Sets the rest of the bits to 0.
85 /// # Panics
86 /// Panics if `start >= BITS || end >= BITS || start > end`.
87 #[must_use]
88 pub const fn get_range(self, start: u32, end: u32) -> Self {
89 Self(self.0 & Self::mask_range(start, end).0)
90 }
91
92 /// Gets the bits in `self` from the `[start..=end]` checked range.
93 ///
94 /// Sets the rest of the bits to 0.
95 /// # Errors
96 /// Returns [`IndexOutOfBounds`] if `start >= BITS || end >= BITS` and
97 /// [`MismatchedIndices`] if `start > end`.
98 pub const fn get_checked_range(self, start: u32, end: u32)
99 -> Result<Self, MismatchedBounds> {
100 match Self::mask_checked_range(start, end) {
101 Ok(mask) => Ok(Self(self.0 & mask.0)),
102 Err(e) => Err(e),
103 }
104 }
105
106 /* get value */
107
108 /// Gets the value of the bits in `self` from the `[start..=end]` range.
109 ///
110 /// Sets the rest of the bits to 0.
111 ///
112 /// The bits in the specified range are shifted rightwards so that the least
113 /// significant bit (LSB) aligns with the units place, forming the integer value.
114 /// # Panics
115 /// Panics if `start >= BITS || end >= BITS || start > end`.
116 #[must_use]
117 pub const fn get_value_range(self, start: u32, end: u32) -> Self {
118 Self((self.0 & Self::mask_range(start, end).0) >> start)
119 }
120
121 /// Gets the value of the bits in `self` from the `[start..=end]` checked range.
122 ///
123 /// Sets the rest of the bits to 0.
124 ///
125 /// The bits in the specified range are shifted rightwards so that the least
126 /// significant bit (LSB) aligns with the units place, forming the integer value.
127 /// # Errors
128 /// Returns [`IndexOutOfBounds`] if `start >= BITS || end >= BITS` and
129 /// [`MismatchedIndices`] if `start > end`.
130 pub const fn get_value_checked_range(self, start: u32, end: u32)
131 -> Result<Self, MismatchedBounds> {
132 match Self::mask_checked_range(start, end) {
133 Ok(mask) => Ok(Self((self.0 & mask.0) >> start)),
134 Err(e) => Err(e),
135 }
136 }
137
138 /* set */
139
140 /// Sets the bits in `self` to 1, from the `[start..=end]` range.
141 ///
142 /// Leaves the rest of the bits unchanged.
143 /// # Panics
144 /// Panics if `start >= BITS || end >= BITS || start > end`.
145 #[must_use]
146 pub const fn set_range(self, start: u32, end: u32) -> Self {
147 Self(self.0 | Self::mask_range(start, end).0)
148 }
149
150 /// Sets the bits in `self` to 1, from the `[start..=end]` checked range.
151 ///
152 /// Leaves the rest of the bits unchanged.
153 /// # Errors
154 /// Returns [`IndexOutOfBounds`] if `start >= BITS || end >= BITS`
155 /// and [`MismatchedIndices`] if `start > end`.
156 pub const fn set_checked_range(self, start: u32, end: u32)
157 -> Result<Self, MismatchedBounds> {
158 match Self::mask_checked_range(start, end) {
159 Ok(mask) => Ok(Self(self.0 | mask.0)),
160 Err(e) => Err(e),
161 }
162 }
163
164 /* set value */
165
166 /// Sets the given `value` into the bits from the `[start..=end]` range.
167 ///
168 /// Leaves the rest of the bits unchanged.
169 ///
170 /// The value is first masked to fit the size of the range, and then
171 /// it is inserted into the specified bit range of `self`, replacing
172 /// the existing bits in that range. The rest of the bits in `self` remain unchanged.
173 /// # Panics
174 /// Panics if `start >= BITS || end >= BITS || start > end`.
175 #[must_use]
176 pub const fn set_value_range(self, value: $t, start: u32, end: u32) -> Self {
177 let mask = Self::mask_range(start, end).0;
178 let value_shifted = (value << start) & mask;
179 Self((self.0 & !mask) | value_shifted)
180 }
181
182 /// Sets the given `value` into the bits from the `[start..=end]` checked range.
183 ///
184 /// Leaves the rest of the bits unchanged.
185 /// # Errors
186 /// Returns [`IndexOutOfBounds`] if `start >= BITS || end >= BITS`
187 /// and [`MismatchedIndices`] if `start > end`.
188 pub const fn set_value_checked_range(self, value: $t, start: u32, end: u32)
189 -> Result<Self, MismatchedBounds> {
190 match Self::mask_checked_range(start, end) {
191 Ok(mask) => {
192 let value_shifted = (value << start) & mask.0;
193 Ok(Self((self.0 & !mask.0) | value_shifted))
194 },
195 Err(e) => Err(e),
196 }
197 }
198
199 /// Sets the given checked `value` into the bits from the `[start..=end]` checked range.
200 ///
201 /// Leaves the rest of the bits unchanged.
202 /// # Errors
203 /// Returns [`IndexOutOfBounds`] if `start >= BITS || end >= BITS`,
204 /// [`MismatchedIndices`] if `start > end`, and
205 /// [`DataOverflow`] if `value` does not fit within the specified bit range.
206 pub const fn set_checked_value_checked_range(self, value: $t, start: u32, end: u32)
207 -> Result<Self, MismatchedBounds> {
208 match Self::mask_checked_range(start, end) {
209 Ok(mask) => {
210 iif![value >= (1 << (end - start));
211 return Err(DataOverflow(Some(value as usize)))];
212 let value_shifted = (value << start) & mask.0;
213 Ok(Self((self.0 & !mask.0) | value_shifted))
214 },
215 Err(e) => Err(e),
216 }
217 }
218
219 /* unset */
220
221 /// Unsets the bits in `self` to 0, from the `[start..=end]` range.
222 ///
223 /// Leaves the rest of the bits unchanged.
224 /// # Panics
225 /// Panics if `start >= BITS || end >= BITS || start > end`.
226 #[must_use]
227 pub const fn unset_range(self, start: u32, end: u32) -> Self {
228 Self(self.0 & !Self::mask_range(start, end).0)
229 }
230
231 /// Unsets the bits in `self` to 0, from the `[start..=end]` checked range.
232 ///
233 /// Leaves the rest of the bits unchanged.
234 /// # Errors
235 /// Returns [`IndexOutOfBounds`] if `start >= BITS || end >= BITS` and
236 /// [`MismatchedIndices`] if `start > end`.
237 pub const fn unset_checked_range(self, start: u32, end: u32)
238 -> Result<Self, MismatchedBounds> {
239 match Self::mask_checked_range(start, end) {
240 Ok(mask) => Ok(Self(self.0 & !mask.0)),
241 Err(e) => Err(e),
242 }
243 }
244
245 /* flip */
246
247 /// Flips the bits in `self` from the `[start..=end]` range.
248 ///
249 /// Leaves the rest of the bits unchanged.
250 /// # Panics
251 /// Panics if `start >= BITS || end >= BITS || start > end`.
252 #[must_use]
253 pub const fn flip_range(self, start: u32, end: u32) -> Self {
254 Self(self.0 ^ Self::mask_range(start, end).0)
255 }
256
257 /// Flips the bits in `self` from the `[start..=end]` checked range.
258 ///
259 /// Leaves the rest of the bits unchanged.
260 /// # Errors
261 /// Returns [`IndexOutOfBounds`] if `start >= BITS || end >= BITS` and
262 /// [`MismatchedIndices`] if `start > end`.
263 pub const fn flip_checked_range(self, start: u32, end: u32)
264 -> Result<Self, MismatchedBounds> {
265 match Self::mask_checked_range(start, end) {
266 Ok(mask) => Ok(Self(self.0 ^ mask.0)),
267 Err(e) => Err(e),
268 }
269 }
270
271 /* reverse */
272
273 /// Reverses the order of the bits in `self` from the `[start..=end]` range.
274 ///
275 /// Leaves the rest of the bits unchanged.
276 /// # Panics
277 /// Panics if `start >= BITS || end >= BITS || start > end`.
278 #[must_use]
279 pub const fn reverse_range(self, start: u32, end: u32) -> Self {
280 debug_assert![start <= end];
281 // If the entire range of bits is selected, simply reverse all bits
282 let range_bits = end - start + 1;
283 iif![range_bits == Self::BITS; return Self(self.0.reverse_bits())];
284 // Create the mask for the range and reverse its bits
285 let mask = (((1 as $t) << range_bits) - 1) << start;
286 let bits_to_rev = (self.0 & mask) >> start;
287 let rev = bits_to_rev.reverse_bits();
288 // Shift the reversed bits back to their original position
289 let rev_shifted = (rev >> (Self::BITS - range_bits)) << start;
290 // Combine with the original number, preserving bits outside the range
291 Self((self.0 & !mask) | rev_shifted)
292 }
293
294 /// Reverses the order of the bits in `self` from the `[start..=end]` checked range.
295 ///
296 /// Leaves the rest of the bits unchanged.
297 /// # Errors
298 /// Returns [`IndexOutOfBounds`] if `start >= BITS || end >= BITS` and
299 /// [`MismatchedIndices`] if `start > end`.
300 pub const fn reverse_checked_range(self, start: u32, end: u32)
301 -> Result<Self, MismatchedBounds> {
302 if start >= Self::BITS {
303 Err(IndexOutOfBounds(Some(start as usize)))
304 } else if end >= <$t>::BITS {
305 Err(IndexOutOfBounds(Some(end as usize)))
306 } else if start > end {
307 Err(MismatchedIndices)
308 } else {
309 // If the entire range of bits is selected, simply reverse all bits
310 let range_bits = end - start + 1;
311 iif![range_bits == Self::BITS; return Ok(Self(self.0.reverse_bits()))];
312 // Create the mask for the range and reverse its bits
313 let mask = (((1 as $t) << range_bits) - 1) << start;
314 let bits_to_rev = (self.0 & mask) >> start;
315 let rev = bits_to_rev.reverse_bits();
316 // Shift the reversed bits back to their original position
317 let rev_shifted = (rev >> (Self::BITS - range_bits)) << start;
318 // Combine with the original number, preserving bits outside the range
319 Ok(Self((self.0 & !mask) | rev_shifted))
320 }
321 }
322
323 /* count */
324
325 /// Counts the number of 1s in `self` from the `[start..=end]` range.
326 /// # Panics
327 /// Panics if `start >= BITS || end >= BITS || start > end`.
328 #[must_use]
329 pub const fn count_ones_range(self, start: u32, end: u32) -> u32 {
330 let masked_bits = self.0 & Self::mask_range(start, end).0;
331 masked_bits.count_ones()
332 }
333 /// Counts the number of 1s in `self` from the `[start..=end]` checked range.
334 /// # Errors
335 /// Returns [`IndexOutOfBounds`] if `start >= BITS || end >= BITS` and
336 /// [`MismatchedIndices`] if `start > end`.
337 pub const fn count_ones_checked_range(self, start: u32, end: u32)
338 -> Result<u32, MismatchedBounds> {
339 match Self::mask_checked_range(start, end) {
340 Ok(mask) => Ok((self.0 & mask.0).count_ones()),
341 Err(e) => Err(e),
342 }
343 }
344
345 /// Counts the number of 0s in `self` from the `[start..=end]` range.
346 /// # Panics
347 /// Panics if `start >= BITS || end >= BITS || start > end`.
348 #[must_use]
349 pub const fn count_zeros_range(self, start: u32, end: u32) -> u32 {
350 let mask = Self::mask_range(start, end).0;
351 let masked_bits = self.0 & mask;
352 (!masked_bits & mask).count_ones()
353 }
354
355 /// Counts the number of 0s in `self` from the `[start..=end]` checked range.
356 /// # Errors
357 /// Returns [`IndexOutOfBounds`] if `start >= BITS || end >= BITS` and
358 /// [`MismatchedIndices`] if `start > end`.
359 pub const fn count_zeros_checked_range(self, start: u32, end: u32)
360 -> Result<u32, MismatchedBounds> {
361 match Self::mask_checked_range(start, end) {
362 Ok(mask) => {
363 let masked_bits = self.0 & mask.0;
364 Ok((!masked_bits & mask.0).count_ones())
365 },
366 Err(e) => Err(e),
367 }
368 }
369
370 /* find first */
371
372 /// Finds the index of the first 1 in `self` from the `[start..=end]` range.
373 ///
374 /// Returns `None` if there are no bits set.
375 ///
376 /// The index is relative to the entire sequence of `self`, not to the given `start`.
377 /// # Panics
378 /// Panics if `start >= BITS || end >= BITS || start > end`.
379 #[must_use]
380 pub const fn find_first_one_range(self, start: u32, end: u32) -> Option<u32> {
381 let masked_bits = self.0 & Self::mask_range(start, end).0;
382 let mut idx = start;
383 while idx <= end {
384 iif![(masked_bits & (1 << idx)) != 0; return Some(idx)];
385 idx += 1;
386 }
387 None
388 }
389
390 /// Finds the index of the first 1 in `self` from the `[start..=end]` checked range.
391 ///
392 /// Returns `None` if there are no bits set.
393 ///
394 /// The index is relative to the entire sequence of `self`, not to the given `start`.
395 /// # Errors
396 /// Returns [`IndexOutOfBounds`] if `start >= BITS || end >= BITS` and
397 /// [`MismatchedIndices`] if `start > end`.
398 pub const fn find_first_one_checked_range(self, start: u32, end: u32)
399 -> Result<Option<u32>, MismatchedBounds> {
400 match Self::mask_checked_range(start, end) {
401 Ok(mask) => {
402 let masked_bits = self.0 & mask.0;
403 let mut idx = start;
404 while idx <= end {
405 iif![(masked_bits & (1 << idx)) != 0; return Ok(Some(idx))];
406 idx += 1;
407 }
408 Ok(None)
409 },
410 Err(e) => Err(e),
411 }
412 }
413
414 /// Finds the index of the first 0 in `self` from the `[start..=end]` range.
415 ///
416 /// Returns `None` if there are no bits unset.
417 ///
418 /// The index is relative to the entire sequence of `self`, not to the given `start`.
419 /// # Panics
420 /// Panics if `start >= BITS || end >= BITS || start > end`.
421 #[must_use]
422 pub const fn find_first_zero_range(self, start: u32, end: u32)
423 -> Option<u32> {
424 let masked_bits = !(self.0 & Self::mask_range(start, end).0);
425 let mut idx = start;
426 while idx <= end {
427 iif![(masked_bits & (1 << idx)) != 0; return Some(idx)];
428 idx += 1;
429 }
430 None
431 }
432
433 /// Finds the index of the first 0 in `self` from the `[start..=end]` checked range.
434 ///
435 /// Returns `None` if there are no bits unset.
436 ///
437 /// The index is relative to the entire sequence of `self`, not to the given `start`.
438 /// # Errors
439 /// Returns [`IndexOutOfBounds`] if `start >= BITS || end >= BITS` and
440 /// [`MismatchedIndices`] if `start > end`.
441 pub const fn find_first_zero_checked_range(self, start: u32, end: u32)
442 -> Result<Option<u32>, MismatchedBounds> {
443 match Self::mask_checked_range(start, end) {
444 Ok(mask) => {
445 let masked_bits = !(self.0 & mask.0);
446 let mut idx = start;
447 while idx <= end {
448 iif![(masked_bits & (1 << idx)) != 0; return Ok(Some(idx))];
449 idx += 1;
450 }
451 Ok(None)
452 },
453 Err(e) => Err(e),
454 }
455 }
456
457 /* find last */
458
459 /// Finds the index of the last 1 in `self` from the `[start..=end]` range.
460 ///
461 /// Returns `None` if there are no bits set.
462 ///
463 /// The index is relative to the entire sequence of `self`, not to the given `start`.
464 /// # Panics
465 /// Panics if `start >= BITS || end >= BITS || start > end`.
466 #[must_use]
467 pub const fn find_last_one_range(self, start: u32, end: u32) -> Option<u32> {
468 let masked_bits = self.0 & Self::mask_range(start, end).0;
469 let mut idx = end;
470 loop {
471 iif![(masked_bits & (1 << idx)) != 0; return Some(idx)];
472 iif![idx == start; break];
473 idx -= 1;
474 }
475 None
476 }
477
478 /// Finds the index of the last 1 in `self` from the `[start..=end]` checked range.
479 ///
480 /// Returns `None` if there are no bits set.
481 ///
482 /// The index is relative to the entire sequence of `self`, not to the given `start`.
483 /// # Errors
484 /// Returns [`IndexOutOfBounds`] if `start >= BITS || end >= BITS` and
485 /// [`MismatchedIndices`] if `start > end`.
486 pub const fn find_last_one_checked_range(self, start: u32, end: u32)
487 -> Result<Option<u32>, MismatchedBounds> {
488 match Self::mask_checked_range(start, end) {
489 Ok(mask) => {
490 let masked_bits = self.0 & mask.0;
491 let mut idx = end;
492 loop {
493 iif![(masked_bits & (1 << idx)) != 0; return Ok(Some(idx))];
494 iif![idx == start; break];
495 idx -= 1;
496 }
497 Ok(None)
498 },
499 Err(e) => Err(e),
500 }
501 }
502
503 /// Finds the index of the last 0 in `self` from the `[start..=end]` range.
504 ///
505 /// Returns `None` if there are no bits set.
506 ///
507 /// The index is relative to the entire sequence of `self`, not to the given `start`.
508 /// # Panics
509 /// Panics if `start >= BITS || end >= BITS || start > end`.
510 #[must_use]
511 pub const fn find_last_zero_range(self, start: u32, end: u32) -> Option<u32> {
512 let masked_bits = !(self.0 & Self::mask_range(start, end).0);
513 let mut idx = end;
514 loop {
515 iif![(masked_bits & (1 << idx)) != 0; return Some(idx)];
516 iif![idx == start; break];
517 idx -= 1;
518 }
519 None
520 }
521
522 /// Finds the index of the last 0 in `self` from the `[start..=end]` checked range.
523 ///
524 /// Returns `None` if there are no bits set.
525 ///
526 /// The index is relative to the entire sequence of `self`, not to the given `start`.
527 /// # Errors
528 /// Returns [`IndexOutOfBounds`] if `start >= BITS || end >= BITS` and
529 /// [`MismatchedIndices`] if `start > end`.
530 pub const fn find_last_zero_checked_range(self, start: u32, end: u32)
531 -> Result<Option<u32>, MismatchedBounds> {
532 match Self::mask_checked_range(start, end) {
533 Ok(mask) => {
534 let masked_bits = !(self.0 & mask.0);
535 let mut idx = end;
536 loop {
537 iif![(masked_bits & (1 << idx)) != 0; return Ok(Some(idx))];
538 iif![idx == start; break];
539 idx -= 1;
540 }
541 Ok(None)
542 },
543 Err(e) => Err(e),
544 }
545 }
546 }
547 };
548}
549impl_bits_wrapper![];