Skip to main content

osom_lib_primitives/power_of_two/
power_of_two_64.rs

1use core::convert::Infallible;
2
3use osom_lib_reprc::macros::reprc;
4use osom_lib_try_clone::TryClone;
5
6use super::PowerOfTwoError;
7
8/// Represents a power of two, as a 64-bit value, which includes zero.
9#[derive(Debug, PartialEq, Eq, Hash, Clone, Copy)]
10#[reprc]
11#[repr(transparent)]
12#[must_use]
13pub struct PowerOfTwo64 {
14    value: u64,
15}
16
17impl PowerOfTwo64 {
18    /// Represents [`PowerOfTwo64`] zero.
19    pub const ZERO: Self = unsafe { Self::new_unchecked(0) };
20
21    /// Creates a new [`PowerOfTwo64`] from a 64-bit value.
22    ///
23    /// # Safety
24    ///
25    /// This function does not validate `value`. It is up to the
26    /// caller to ensure that its value is a power of two.
27    #[inline(always)]
28    pub const unsafe fn new_unchecked(value: u64) -> Self {
29        Self { value }
30    }
31
32    /// Creates a new [`PowerOfTwo64`] from a 64-bit value.
33    ///
34    /// # Errors
35    ///
36    /// Returns [`PowerOfTwoError::NotAPowerOfTwo`] if `value` is not a power of two.
37    #[inline(always)]
38    pub const fn new(value: u64) -> Result<Self, PowerOfTwoError> {
39        if value == 0 || value.is_power_of_two() {
40            Ok(unsafe { Self::new_unchecked(value) })
41        } else {
42            Err(PowerOfTwoError::NotAPowerOfTwo)
43        }
44    }
45
46    /// Returns the next power of two.
47    ///
48    /// # Panics
49    ///
50    /// Panics in debug mode if the next power of two is greater than [`u64::MAX`].
51    /// In release mode it wraps to zero.
52    #[inline(always)]
53    pub fn next(self) -> Self {
54        debug_assert!(self.value < (u64::MAX >> 1));
55        let result = core::hint::select_unpredictable(self.value == 0, 1, self.value << 1);
56        Self { value: result }
57    }
58
59    /// Returns the underlying value of the [`PowerOfTwo64`].
60    #[inline(always)]
61    #[must_use]
62    pub const fn value(self) -> u64 {
63        self.value
64    }
65
66    /// Returns the underlying value as `usize`.
67    ///
68    /// # Panics
69    ///
70    /// Panics if `usize` is smaller than `u32`.
71    #[inline(always)]
72    #[must_use]
73    pub const fn as_usize(self) -> usize {
74        #[allow(clippy::cast_possible_truncation)]
75        {
76            assert!(size_of::<usize>() >= size_of::<u64>(), "usize is smaller than u64");
77            self.value as usize
78        }
79    }
80}
81
82impl core::fmt::Display for PowerOfTwo64 {
83    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
84        self.value.fmt(f)
85    }
86}
87
88impl TryClone for PowerOfTwo64 {
89    type Error = Infallible;
90    fn try_clone(&self) -> Result<Self, Self::Error> {
91        Ok(*self)
92    }
93}