pub const WRAP_33BIT: u64 = 1 << 33;
pub const WRAP_33BIT_HALF: u64 = WRAP_33BIT / 2;
#[must_use]
pub fn unwrap_delta(prev_unwrapped: i128, prev_raw: u64, raw: u64) -> i128 {
let mut delta = raw as i128 - prev_raw as i128;
if delta > WRAP_33BIT_HALF as i128 {
delta -= WRAP_33BIT as i128; } else if delta < -(WRAP_33BIT_HALF as i128) {
delta += WRAP_33BIT as i128; }
prev_unwrapped + delta
}
#[must_use]
pub fn wrapping_forward_distance(from: u64, to: u64) -> u64 {
to.wrapping_sub(from) % WRAP_33BIT
}
#[must_use]
pub fn add(a: u64, b: u64) -> u64 {
let a = a % WRAP_33BIT;
let b = b % WRAP_33BIT;
(a + b) % WRAP_33BIT
}
#[must_use]
pub fn add_signed(a: u64, delta: i64) -> u64 {
let sum = i128::from(a % WRAP_33BIT) + i128::from(delta);
let reduced = sum.rem_euclid(i128::from(WRAP_33BIT));
reduced as u64
}
#[must_use]
pub fn signed_distance(from: u64, to: u64) -> i64 {
let forward = wrapping_forward_distance(from % WRAP_33BIT, to % WRAP_33BIT);
if forward <= WRAP_33BIT_HALF {
forward as i64 } else {
let back = WRAP_33BIT - forward;
-(back as i64)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn unwrap_delta_forward_wrap_advances_by_one_modulus() {
let prev_unwrapped = (WRAP_33BIT - 10) as i128;
let got = unwrap_delta(prev_unwrapped, WRAP_33BIT - 10, 5);
assert_eq!(got, prev_unwrapped + 15);
assert_eq!(got, 5 + WRAP_33BIT as i128);
}
#[test]
fn unwrap_delta_small_forward_step_is_identity_shift() {
assert_eq!(unwrap_delta(1_000, 1_000, 2_000), 2_000);
}
#[test]
fn unwrap_delta_small_backward_step_is_preserved_not_wrapped() {
assert_eq!(unwrap_delta(2_000, 2_000, 1_995), 1_995);
}
#[test]
fn unwrap_delta_backward_reorder_across_origin_stays_small_and_negative() {
let got = unwrap_delta(2, 2, WRAP_33BIT - 3);
assert_eq!(got, -3);
}
#[test]
fn wrapping_forward_distance_small_forward_is_small() {
assert_eq!(wrapping_forward_distance(100, 105), 5);
}
#[test]
fn wrapping_forward_distance_wraps_at_modulus() {
assert_eq!(wrapping_forward_distance(WRAP_33BIT - 1, 0), 1);
}
#[test]
fn wrapping_forward_distance_backward_step_is_large() {
let d = wrapping_forward_distance(105, 100);
assert_eq!(d, WRAP_33BIT - 5);
assert!(d > WRAP_33BIT_HALF);
}
#[test]
fn add_wraps_at_modulus() {
assert_eq!(add(WRAP_33BIT - 1, 1), 0);
assert_eq!(add(WRAP_33BIT - 10, 20), 10);
}
#[test]
fn add_reduces_inputs_at_or_above_the_modulus() {
assert_eq!(add(WRAP_33BIT + 3, 0), 3);
}
#[test]
fn add_signed_negative_delta_wraps_below_zero() {
assert_eq!(add_signed(5, -10), WRAP_33BIT - 5);
}
#[test]
fn add_signed_extreme_deltas_stay_in_range() {
for delta in [i64::MIN, i64::MAX] {
let got = add_signed(0, delta);
assert!(
got < WRAP_33BIT,
"add_signed(0, {delta}) = {got} escaped [0, 2^33)"
);
}
}
#[test]
fn signed_distance_matches_doc_examples() {
assert_eq!(signed_distance(WRAP_33BIT - 10, 5), 15);
assert_eq!(signed_distance(5, WRAP_33BIT - 10), -15);
}
#[test]
fn signed_distance_half_range_boundary_is_positive() {
assert_eq!(signed_distance(0, WRAP_33BIT_HALF), WRAP_33BIT_HALF as i64);
assert_eq!(
signed_distance(0, WRAP_33BIT_HALF + 1),
-((WRAP_33BIT_HALF - 1) as i64)
);
}
#[test]
fn signed_distance_reduces_inputs_at_or_above_the_modulus() {
assert_eq!(signed_distance(WRAP_33BIT + 5, WRAP_33BIT + 8), 3);
}
}