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)
}
}
pub const PTS_HZ: u64 = 90_000;
pub const PCR_HZ: u64 = 27_000_000;
pub const PCR_EXT_MODULUS: u64 = PCR_HZ / PTS_HZ;
pub const PCR_WRAP_27MHZ: u64 = WRAP_33BIT * PCR_EXT_MODULUS;
#[must_use]
pub const fn pcr_from_parts(base: u64, extension: u16) -> u64 {
base.wrapping_mul(PCR_EXT_MODULUS)
.wrapping_add(extension as u64)
}
#[must_use]
pub const fn pcr_split(ticks: u64) -> (u64, u16) {
(
(ticks / PCR_EXT_MODULUS) & (WRAP_33BIT - 1),
(ticks % PCR_EXT_MODULUS) as u16,
)
}
#[must_use]
pub fn pcr_forward_distance(from: u64, to: u64) -> u64 {
(to % PCR_WRAP_27MHZ + PCR_WRAP_27MHZ - from % PCR_WRAP_27MHZ) % PCR_WRAP_27MHZ
}
#[must_use]
pub fn pcr_signed_distance(from: u64, to: u64) -> i64 {
let forward = pcr_forward_distance(from, to);
if forward <= PCR_WRAP_27MHZ / 2 {
forward as i64 } else {
-((PCR_WRAP_27MHZ - forward) as i64) }
}
pub const MARKERS_ALL_SET: u8 = 0b111;
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub struct Marked {
pub prefix: u8,
pub timestamp: u64,
pub markers: u8,
}
#[must_use]
pub fn unpack_marked(b: &[u8; 5]) -> Marked {
let hi = u64::from((b[0] >> 1) & 0x07); let mid = (u64::from(b[1]) << 7) | u64::from(b[2] >> 1); let lo = (u64::from(b[3]) << 7) | u64::from(b[4] >> 1); Marked {
prefix: b[0] >> 4,
timestamp: (hi << 30) | (mid << 15) | lo,
markers: ((b[0] & 1) << 2) | ((b[2] & 1) << 1) | (b[4] & 1),
}
}
#[must_use]
pub fn pack_marked_with(timestamp: u64, prefix: u8, markers: u8) -> [u8; 5] {
let ts = timestamp & (WRAP_33BIT - 1);
[
((prefix & 0x0F) << 4) | ((((ts >> 30) & 0x07) as u8) << 1) | ((markers >> 2) & 1),
((ts >> 22) & 0xFF) as u8,
((((ts >> 15) & 0x7F) as u8) << 1) | ((markers >> 1) & 1),
((ts >> 7) & 0xFF) as u8,
(((ts & 0x7F) as u8) << 1) | (markers & 1),
]
}
#[must_use]
pub fn pack_marked(timestamp: u64, prefix: u8) -> [u8; 5] {
pack_marked_with(timestamp, prefix, MARKERS_ALL_SET)
}
#[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);
}
#[test]
fn pcr_constants_are_the_spec_values() {
assert_eq!(PCR_EXT_MODULUS, 300);
assert_eq!(PCR_WRAP_27MHZ, (1u64 << 33) * 300);
assert_eq!(PCR_WRAP_27MHZ, 2_576_980_377_600);
assert_eq!(PCR_HZ, PTS_HZ * PCR_EXT_MODULUS);
}
#[test]
fn pcr_parts_round_trip() {
for ticks in [0, 1, 299, 300, 301, 27_000_000, PCR_WRAP_27MHZ - 1] {
let (base, ext) = pcr_split(ticks);
assert!(ext < 300 && base < WRAP_33BIT);
assert_eq!(pcr_from_parts(base, ext), ticks);
}
let _ = pcr_from_parts(u64::MAX, 299);
}
#[test]
fn pcr_forward_distance_across_the_wrap() {
let m = PCR_WRAP_27MHZ;
assert_eq!(pcr_forward_distance(m - 5, 10), 15);
assert_eq!(pcr_forward_distance(10, m - 5), m - 15);
assert_eq!(pcr_forward_distance(7, 7), 0);
assert_eq!(pcr_forward_distance(0, m - 1), m - 1);
assert_eq!(pcr_forward_distance(m + 3, 5), 2);
}
#[test]
fn pcr_forward_distance_is_not_wrapping_sub_mod_m() {
let m = PCR_WRAP_27MHZ;
let (from, to) = (m - 5, 10u64);
let naive = to.wrapping_sub(from) % m;
assert_ne!(naive, 15, "the naive form is wrong across a wrap");
assert_eq!(pcr_forward_distance(from, to), 15);
}
#[test]
fn pcr_signed_distance_is_the_shortest_path() {
let m = PCR_WRAP_27MHZ;
assert_eq!(pcr_signed_distance(m - 10, 5), 15);
assert_eq!(pcr_signed_distance(5, m - 10), -15);
assert_eq!(pcr_signed_distance(0, m / 2), (m / 2) as i64);
assert_eq!(pcr_signed_distance(0, m / 2 + 1), -((m / 2 - 1) as i64));
assert_eq!(pcr_signed_distance(100, 100), 0);
}
#[test]
fn marked_decodes_and_re_encodes_a_real_capture_pts_field() {
let real = [0x29, 0xFD, 0x91, 0xD2, 0x29];
let m = unpack_marked(&real);
assert_eq!(
m,
Marked {
prefix: 0b0010,
timestamp: 5_358_512_404,
markers: MARKERS_ALL_SET
}
);
assert_eq!(pack_marked(m.timestamp, m.prefix), real);
}
#[test]
fn marked_round_trips_every_boundary_and_marker_combination() {
for ts in [0, 1, 90_000, 0x1_2345_6789, WRAP_33BIT - 1] {
for prefix in [0b0001, 0b0010, 0b0011, 0x0F, 0] {
for markers in 0..8u8 {
let b = pack_marked_with(ts, prefix, markers);
let m = unpack_marked(&b);
assert_eq!(
(m.prefix, m.timestamp, m.markers),
(prefix, ts, markers),
"ts={ts:#x} prefix={prefix:#x} markers={markers:#05b}"
);
}
}
}
}
#[test]
fn marked_pack_reduces_modulo_2_pow_33_and_masks_the_prefix() {
assert_eq!(pack_marked(WRAP_33BIT + 5, 0b0010), pack_marked(5, 0b0010));
assert_eq!(pack_marked(7, 0xF2), pack_marked(7, 0x02));
}
#[test]
fn marked_a_cleared_marker_is_visible_to_the_caller() {
let mut b = pack_marked(0x1234, 0b0010);
b[2] &= !1; assert_eq!(unpack_marked(&b).markers, 0b101);
}
}