Skip to content

Commit

Permalink
Add SAFETY comments
Browse files Browse the repository at this point in the history
  • Loading branch information
meithecatte committed Mar 24, 2022
1 parent 6efe566 commit 4dca6d7
Showing 1 changed file with 18 additions and 1 deletion.
19 changes: 18 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -401,6 +401,8 @@ macro_rules! make_bitflags {
$(
n |= $enum::$variant as <$enum as $crate::_internal::RawBitFlags>::Numeric;
)*
// SAFETY: The value has been created from numeric values of the underlying
// enum, so only valid bits are set.
unsafe { $crate::BitFlags::<$enum>::from_bits_unchecked_c(
n, $crate::BitFlags::CONST_TOKEN) }
}
Expand Down Expand Up @@ -460,6 +462,8 @@ where
#[must_use]
#[inline(always)]
pub fn from_bits_truncate(bits: T::Numeric) -> Self {
// SAFETY: We're truncating out all the invalid bits, so the remaining
// ones must be valid.
unsafe { BitFlags::from_bits_unchecked(bits & T::ALL_BITS) }
}

Expand All @@ -486,6 +490,7 @@ where
#[must_use]
#[inline(always)]
pub fn from_flag(flag: T) -> Self {
// SAFETY: A value of the underlying enum is valid by definition.
unsafe { Self::from_bits_unchecked(flag.bits()) }
}

Expand Down Expand Up @@ -586,6 +591,8 @@ where
#[inline(always)]
pub fn exactly_one(self) -> Option<T> {
if self.val.is_power_of_two() {
// SAFETY: By the invariant of the BitFlags type, all bits are valid
// in isolation for the underlying enum.
Some(unsafe { core::mem::transmute_copy(&self.val) })
} else {
None
Expand Down Expand Up @@ -677,6 +684,10 @@ where
if self.rest.is_empty() {
None
} else {
// SAFETY: `flag` will be a single bit, because
// x & -x = x & (~x + 1), and the increment causes only one 0 -> 1 transition.
// The invariant of `from_bits_unchecked` is satisfied, because bits & x
// is a subset of bits, which we know are the valid bits.
unsafe {
let bits = self.rest.bits();
let flag: T::Numeric = bits & bits.wrapping_neg();
Expand Down Expand Up @@ -867,6 +878,8 @@ where
type Output = BitFlags<T>;
#[inline(always)]
fn bitor(self, other: B) -> BitFlags<T> {
// SAFETY: The two operands are known to be composed of valid bits,
// and 0 | 0 = 0 in the columns of the invalid bits.
unsafe { BitFlags::from_bits_unchecked(self.bits() | other.into().bits()) }
}
}
Expand All @@ -879,6 +892,8 @@ where
type Output = BitFlags<T>;
#[inline(always)]
fn bitand(self, other: B) -> BitFlags<T> {
// SAFETY: The two operands are known to be composed of valid bits,
// and 0 & 0 = 0 in the columns of the invalid bits.
unsafe { BitFlags::from_bits_unchecked(self.bits() & other.into().bits()) }
}
}
Expand All @@ -891,6 +906,8 @@ where
type Output = BitFlags<T>;
#[inline(always)]
fn bitxor(self, other: B) -> BitFlags<T> {
// SAFETY: The two operands are known to be composed of valid bits,
// and 0 ^ 0 = 0 in the columns of the invalid bits.
unsafe { BitFlags::from_bits_unchecked(self.bits() ^ other.into().bits()) }
}
}
Expand Down Expand Up @@ -934,7 +951,7 @@ where
type Output = BitFlags<T>;
#[inline(always)]
fn not(self) -> BitFlags<T> {
unsafe { BitFlags::from_bits_unchecked(!self.bits() & T::ALL_BITS) }
BitFlags::from_bits_truncate(!self.bits())
}
}

Expand Down

0 comments on commit 4dca6d7

Please sign in to comment.