pipecircuit 0.0.23

Correct. Robust. Fast. Portable. Pick four.
Documentation
#[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 })
        );
    }
}