#[inline(always)]
pub const fn oppv_len_u64(val: u64) -> usize {
if val < 0x80 {
1
} else if val < 0x4000 {
2
} else if val < 0x20_0000 {
3
} else if val < 0x1000_0000 {
4
} else {
9
}
}
#[inline(always)]
pub fn encode_oppv_u64_slice(val: u64, buf: &mut [u8]) -> usize {
if val < 0x80 {
buf[0] = val as u8;
1
} else if val < 0x4000 {
buf[0] = 0x80 | ((val >> 8) as u8);
buf[1] = (val & 0xFF) as u8;
2
} else if val < 0x20_0000 {
buf[0] = 0xC0 | ((val >> 16) as u8);
buf[1] = ((val >> 8) & 0xFF) as u8;
buf[2] = (val & 0xFF) as u8;
3
} else if val < 0x1000_0000 {
buf[0] = 0xE0 | ((val >> 24) as u8);
buf[1] = ((val >> 16) & 0xFF) as u8;
buf[2] = ((val >> 8) & 0xFF) as u8;
buf[3] = (val & 0xFF) as u8;
4
} else {
buf[0] = 0xF8;
buf[1..9].copy_from_slice(&val.to_be_bytes());
9
}
}
#[inline(always)]
pub fn encode_oppv_u64_fixed(val: u64, buf: &mut [u8; 9]) -> usize {
encode_oppv_u64_slice(val, buf)
}
#[inline]
pub fn encode_oppv_u64(val: u64, buf: &mut Vec<u8>) {
let mut fixed = [0u8; 9];
let n = encode_oppv_u64_fixed(val, &mut fixed);
buf.extend_from_slice(&fixed[..n]);
}
#[inline]
pub fn decode_oppv_u64(slice: &[u8]) -> Option<(u64, usize)> {
let first = *slice.first()?;
if first < 0x80 {
Some((first as u64, 1))
} else if first < 0xC0 {
if slice.len() < 2 {
return None;
}
let val = (((first & 0x3F) as u64) << 8) | (slice[1] as u64);
Some((val, 2))
} else if first < 0xE0 {
if slice.len() < 3 {
return None;
}
let val = (((first & 0x1F) as u64) << 16) | ((slice[1] as u64) << 8) | (slice[2] as u64);
Some((val, 3))
} else if first < 0xF0 {
if slice.len() < 4 {
return None;
}
let val = (((first & 0x0F) as u64) << 24)
| ((slice[1] as u64) << 16)
| ((slice[2] as u64) << 8)
| (slice[3] as u64);
Some((val, 4))
} else if first == 0xF8 {
if slice.len() < 9 {
return None;
}
let bytes = slice[1..9].try_into().ok()?;
Some((u64::from_be_bytes(bytes), 9))
} else {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_oppv_strict_order_preservation() {
let test_values = [
0u64,
1,
2,
127,
128,
129,
1000,
16383,
16384,
100_000,
1_000_000,
268_435_455,
268_435_456,
1_000_000_000,
u64::MAX - 1,
u64::MAX,
];
let mut encoded_list = Vec::new();
for &v in &test_values {
let mut buf = Vec::new();
encode_oppv_u64(v, &mut buf);
let (decoded, consumed) = decode_oppv_u64(&buf).unwrap();
assert_eq!(decoded, v);
assert_eq!(consumed, buf.len());
encoded_list.push((v, buf));
}
for w in encoded_list.windows(2) {
let (v1, ref b1) = w[0];
let (v2, ref b2) = w[1];
assert!(
v1 < v2,
"Value {v1} should be strictly less than value {v2}"
);
assert!(
b1 < b2,
"Encoded bytes {b1:?} should be strictly less than bytes {b2:?}"
);
}
}
}