#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum RangeIndexInconsistency {
StorageCapacityOverflow { maximum_rows: usize, bits: u32 },
BlockStorageLengthMismatch { expected: usize, actual: usize },
SlotOutsideCapacity { maximum_rows: usize },
BitPositionOutsideWord { bit: u32 },
MemberCountUnrepresentable { members: u64 },
MemberCountMismatch { members: u64 },
StaleBitMembership { bit: u32 },
MemberAbsent,
StoredWordMismatch { expected: u64, actual: u64 },
}
pub(super) fn represent_members<Index: TryFrom<u64>>(
members: u64,
) -> Result<Index, RangeIndexInconsistency> {
Index::try_from(members)
.map_err(|_| RangeIndexInconsistency::MemberCountUnrepresentable { members })
}
pub(super) fn increment_members(members: u64) -> Result<u64, RangeIndexInconsistency> {
members
.checked_add(1)
.ok_or(RangeIndexInconsistency::MemberCountUnrepresentable { members })
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn member_counts_preserve_exact_narrowing_and_increment_refusals() {
for members in [0, 1, u64::from(u16::MAX), u64::from(u16::MAX) + 1, u64::MAX] {
assert_eq!(represent_members::<u64>(members), Ok(members));
assert_eq!(
represent_members::<u16>(members),
u16::try_from(members)
.map_err(|_| RangeIndexInconsistency::MemberCountUnrepresentable { members })
);
}
assert_eq!(increment_members(0), Ok(1));
assert_eq!(increment_members(42), Ok(43));
assert_eq!(increment_members(u64::MAX - 1), Ok(u64::MAX));
assert_eq!(
increment_members(u64::MAX),
Err(RangeIndexInconsistency::MemberCountUnrepresentable { members: u64::MAX })
);
}
}