diff --git a/.hgignore b/.hgignore --- a/.hgignore +++ b/.hgignore @@ -18,3 +18,4 @@ subinclude:cfastmanifest/.hgignore subinclude:linelog/.hgignore +subinclude:rust/.hgignore diff --git a/rust/.hgignore b/rust/.hgignore new file mode 100644 --- /dev/null +++ b/rust/.hgignore @@ -0,0 +1,2 @@ +target/ +vlq/Cargo.lock diff --git a/rust/vlq/Cargo.toml b/rust/vlq/Cargo.toml new file mode 100644 --- /dev/null +++ b/rust/vlq/Cargo.toml @@ -0,0 +1,5 @@ +[package] +name = "vlq" +version = "0.1.0" + +[dependencies] diff --git a/rust/vlq/src/lib.rs b/rust/vlq/src/lib.rs new file mode 100644 --- /dev/null +++ b/rust/vlq/src/lib.rs @@ -0,0 +1,101 @@ +/// VLQ (Variable-length quantity) encoding. + +/// Encode a u64 value to a byte array +/// +/// # Example +/// +/// ``` +/// use vlq::encode; +/// +/// let x = encode(120); +/// assert_eq!(x, vec![120]); +/// +/// let x = encode(22742734291); +/// assert_eq!(x, vec![211, 171, 202, 220, 84]); +/// ``` +pub fn encode(value: u64) -> Vec { + let mut result = Vec::new(); + let mut x = value; + loop { + let next = x >> 7; + let byte = match next { + 0 => x & 127, + _ => x & 127 | 128, + } as u8; + result.push(byte); + x = next; + if x == 0 { + break; + } + } + result +} + +/// Decode a byte array to a u64 value +/// +/// # Example +/// +/// ``` +/// use vlq::decode; +/// +/// let mut pos = 0; +/// let buf = vec![120, 211, 171, 202, 220, 84]; +/// +/// let x = decode(&buf, &mut pos); +/// assert_eq!(x, 120); +/// assert_eq!(pos, 1); +/// +/// let x = decode(&buf, &mut pos); +/// assert_eq!(x, 22742734291); +/// assert_eq!(pos, buf.len()); +/// ``` +pub fn decode(buf: &Vec, pos: &mut usize) -> u64 { + let mut result: u64 = 0; + let mut shift: usize = 0; + while *pos < buf.len() { + let x: u8 = buf[*pos]; + *pos += 1; + result |= ((x & 127) as u64) << shift; + if x & 128 == 0 { + break; + } + shift += 7; + } + result +} + +#[cfg(test)] +mod tests { + use {encode, decode}; + + #[test] + fn round_trip() { + let numbers = vec![ + 0, + 1, + 17, + 63, + 127, + 128, + 129, + 255, + 256, + 65535, + 65536, + 65537, + 12345678901234, + 12345678901234567890, + 18446744073709551615u64, + ]; + let mut buf = vec![255, 127]; // buffer with unrelated bytes + let mut pos = buf.len(); + for i in &numbers { + let mut encoded = encode(*i); + buf.append(&mut encoded); + } + for i in &numbers { + let v = decode(&buf, &mut pos); + assert_eq!(v, *i); + } + } +}