Skip to main content

vexil_runtime/
zigzag.rs

1/// Encode a signed integer using ZigZag encoding.
2///
3/// Maps signed values to unsigned: 0 -> 0, -1 -> 1, 1 -> 2, -2 -> 3, etc.
4/// `type_bits` is the bit width of the source type (e.g. 32 for `i32`, 64 for `i64`).
5pub fn zigzag_encode(n: i64, type_bits: u8) -> u64 {
6    ((n << 1) ^ (n >> (u32::from(type_bits) - 1))) as u64
7}
8
9/// Decode a ZigZag-encoded unsigned integer back to its signed value.
10pub fn zigzag_decode(n: u64) -> i64 {
11    ((n >> 1) as i64) ^ -((n & 1) as i64)
12}
13
14#[cfg(test)]
15mod tests {
16    use super::*;
17
18    #[test]
19    fn encode_mapping() {
20        assert_eq!(zigzag_encode(0, 64), 0);
21        assert_eq!(zigzag_encode(-1, 64), 1);
22        assert_eq!(zigzag_encode(1, 64), 2);
23        assert_eq!(zigzag_encode(-2, 64), 3);
24        assert_eq!(zigzag_encode(2, 64), 4);
25        assert_eq!(zigzag_encode(i64::MIN, 64), u64::MAX);
26        assert_eq!(zigzag_encode(i64::MAX, 64), u64::MAX - 1);
27    }
28
29    #[test]
30    fn round_trip_i32_range() {
31        for &v in &[0i64, 1, -1, 127, -128, i32::MIN as i64, i32::MAX as i64] {
32            let encoded = zigzag_encode(v, 32);
33            let decoded = zigzag_decode(encoded);
34            assert_eq!(decoded, v, "round-trip failed for {v}");
35        }
36    }
37
38    #[test]
39    fn encode_32bit_width() {
40        assert_eq!(zigzag_encode(-1, 32), 1);
41        assert_eq!(zigzag_encode(1, 32), 2);
42    }
43}