use std::io::{self, Read, Write};
pub fn encode(value: i64, buf: &mut [u8]) -> usize {
debug_assert!(buf.len() >= 9);
if value >= 0 {
if value & !0x3f == 0 {
buf[0] = (value as u8) | 0x40;
return 1;
}
if value & !0x1fff == 0 {
buf[0] = ((value >> 8) as u8) | 0x20;
buf[1] = (value & 0xff) as u8;
return 2;
}
let le = value.to_le_bytes();
let d = data_bytes_positive(value);
buf[0] = (d - 1) as u8; buf[1..1 + d].copy_from_slice(&le[..d]);
1 + d
} else {
if !value & !0x3f == 0 {
buf[0] = (value as u8) | 0x40;
return 1;
}
let le = value.to_le_bytes();
let d = data_bytes_negative(value);
buf[0] = 0x80 | (d - 1) as u8; buf[1..1 + d].copy_from_slice(&le[..d]);
1 + d
}
}
pub fn decode(buf: &[u8]) -> (i64, usize) {
match buf[0] >> 5 {
2 | 3 => {
let val = i64::from(buf[0] & 0x3f);
(val, 1)
}
6 | 7 => {
let val = (buf[0] as i8) as i64;
(val, 1)
}
1 => {
let val = (i64::from(buf[0] & 0x1f) << 8) | i64::from(buf[1]);
(val, 2)
}
0 => {
let d = (buf[0] & 0x07) as usize;
assert!(d >= 1, "LTF decode: invalid byte count 0 in positive multi-byte");
let val = read_le_masked(&buf[1..], d);
(val, 1 + d + 1) }
4 => {
let d = (buf[0] & 0x07) as usize;
assert!(d >= 1, "LTF decode: invalid byte count 0 in negative multi-byte");
let val = read_le_sign_extended(&buf[1..], d);
(val, 1 + d + 1)
}
_ => unreachable!("LTF decode: unexpected prefix {:#04x}", buf[0]),
}
}
pub fn write(value: i64, writer: &mut impl Write) -> io::Result<usize> {
let mut buf = [0u8; 9];
let n = encode(value, &mut buf);
writer.write_all(&buf[..n])?;
Ok(n)
}
pub fn read(reader: &mut impl Read) -> io::Result<i64> {
let mut first = [0u8; 1];
reader.read_exact(&mut first)?;
let u0 = first[0];
if u0 & 0x40 != 0 {
if u0 & 0x80 != 0 {
Ok((u0 as i8) as i64)
} else {
Ok(i64::from(u0 & 0x3f))
}
} else if u0 & 0x20 != 0 {
let mut second = [0u8; 1];
reader.read_exact(&mut second)?;
Ok((i64::from(u0 & 0x1f) << 8) | i64::from(second[0]))
} else {
let d = ((u0 & 0x07) + 1) as usize;
let negative = u0 & 0x80 != 0;
let mut data = [0u8; 8];
reader.read_exact(&mut data[..d])?;
if negative {
Ok(read_le_sign_extended(&data, d - 1))
} else {
Ok(read_le_masked(&data, d - 1))
}
}
}
fn data_bytes_positive(val: i64) -> usize {
debug_assert!(val >= 0);
if val & !0x0000_0000_0000_ffff == 0 { return 2; }
if val & !0x0000_0000_00ff_ffff == 0 { return 3; }
if val & !0x0000_0000_ffff_ffff == 0 { return 4; }
if val & !0x0000_00ff_ffff_ffff == 0 { return 5; }
if val & !0x0000_ffff_ffff_ffff == 0 { return 6; }
if val & !0x00ff_ffff_ffff_ffff == 0 { return 7; }
8
}
fn data_bytes_negative(val: i64) -> usize {
debug_assert!(val < 0);
if !val & !0x0000_0000_0000_ffff == 0 { return 2; }
if !val & !0x0000_0000_00ff_ffff == 0 { return 3; }
if !val & !0x0000_0000_ffff_ffff == 0 { return 4; }
if !val & !0x0000_00ff_ffff_ffff == 0 { return 5; }
if !val & !0x0000_ffff_ffff_ffff == 0 { return 6; }
if !val & !0x00ff_ffff_ffff_ffff == 0 { return 7; }
8
}
fn read_le_masked(buf: &[u8], d: usize) -> i64 {
let n = d + 1; let mut bytes = [0u8; 8];
bytes[..n].copy_from_slice(&buf[..n]);
i64::from_le_bytes(bytes)
}
fn read_le_sign_extended(buf: &[u8], d: usize) -> i64 {
let n = d + 1;
let mut bytes = [0xffu8; 8]; bytes[..n].copy_from_slice(&buf[..n]);
i64::from_le_bytes(bytes)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn single_byte_positive() {
let mut buf = [0u8; 9];
for v in 0..=63 {
let n = encode(v, &mut buf);
assert_eq!(n, 1, "value {v} should encode in 1 byte");
let (decoded, consumed) = decode(&buf);
assert_eq!(consumed, 1);
assert_eq!(decoded, v, "round-trip failed for {v}");
}
}
#[test]
fn single_byte_negative() {
let mut buf = [0u8; 9];
for v in -64..=-1 {
let n = encode(v, &mut buf);
assert_eq!(n, 1, "value {v} should encode in 1 byte");
let (decoded, consumed) = decode(&buf);
assert_eq!(consumed, 1);
assert_eq!(decoded, v, "round-trip failed for {v}");
}
}
#[test]
fn two_byte_positive() {
let mut buf = [0u8; 9];
for v in [64, 100, 255, 1000, 8191] {
let n = encode(v, &mut buf);
assert_eq!(n, 2, "value {v} should encode in 2 bytes");
let (decoded, consumed) = decode(&buf);
assert_eq!(consumed, 2);
assert_eq!(decoded, v, "round-trip failed for {v}");
}
}
#[test]
fn boundary_values() {
let mut buf = [0u8; 9];
let cases = [
(0i64, 1),
(63, 1),
(64, 2),
(-1, 1),
(-64, 1),
(-65, 3), (8191, 2),
(8192, 3),
(0xffff, 3),
(0x1_0000, 4),
(i64::MAX, 9),
(i64::MIN, 9),
];
for (val, expected_bytes) in cases {
let n = encode(val, &mut buf);
assert_eq!(n, expected_bytes, "value {val} should encode in {expected_bytes} bytes, got {n}");
let (decoded, consumed) = decode(&buf);
assert_eq!(consumed, expected_bytes);
assert_eq!(decoded, val, "round-trip failed for {val}");
}
}
#[test]
fn read_write_round_trip() {
let values = [0, 1, -1, 63, 64, -64, -65, 8191, 8192, -8193,
0xffff, 0x1_0000, -0x1_0000, i64::MAX, i64::MIN,
42, -42, 1000000, -1000000];
let mut data = Vec::new();
for &v in &values {
write(v, &mut data).unwrap();
}
let mut cursor = std::io::Cursor::new(&data);
for &expected in &values {
let got = read(&mut cursor).unwrap();
assert_eq!(got, expected, "stream round-trip failed for {expected}");
}
}
}