Skip to content

Instantly share code, notes, and snippets.

@udoprog
Created September 22, 2019 19:37
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save udoprog/34d8047e801762f0df56a2a21431979f to your computer and use it in GitHub Desktop.
Save udoprog/34d8047e801762f0df56a2a21431979f to your computer and use it in GitHub Desktop.
Just a simple variable-length encoding for integers I threw together
use std::io::{self, Read, Write};
trait Encoder: Sized {
fn encode<W>(self, writer: &mut W) -> io::Result<()>
where
W: Write;
fn decode<R>(reader: &mut R) -> io::Result<Self>
where
R: Read;
}
macro_rules! encoder {
($ty:ty) => {
impl Encoder for $ty {
fn encode<W>(self, writer: &mut W) -> io::Result<()>
where
W: Write,
{
const CONT: $ty = 0x80;
const MASK: $ty = CONT ^ 0xff;
let mut v: $ty = self;
while v >= 0x80 {
writer.write(&[((v & MASK) | CONT) as u8])?;
v = v >> 7;
}
writer.write(&[v as u8])?;
Ok(())
}
fn decode<R>(reader: &mut R) -> io::Result<Self>
where
R: Read,
{
const CONT: u8 = 0x80;
const MASK: u8 = CONT ^ 0xff;
let mut value: $ty = 0;
let mut shift = 1;
let mut buf = [0u8; 1];
reader.read(&mut buf)?;
while buf[0] & CONT != 0 {
value += ((buf[0] & MASK) as $ty)
.checked_mul(shift)
.ok_or_else(overflow)?;
reader.read(&mut buf)?;
shift <<= 7;
}
let last = ((buf[0] & MASK) as $ty)
.checked_mul(shift)
.ok_or_else(overflow)?;
value = value.checked_add(last).ok_or_else(overflow)?;
return Ok(value);
fn overflow() -> io::Error {
io::Error::new(io::ErrorKind::Other, "overflow")
}
}
}
};
}
encoder!(u16);
encoder!(u32);
encoder!(u64);
encoder!(u128);
fn main() -> Result<(), Box<dyn std::error::Error>> {
use std::io::Cursor;
let mut data = Vec::new();
0x7f7f7f7fu32.encode(&mut data)?;
println!("{:x}", u128::decode(&mut Cursor::new(&data))?);
Ok(())
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment