diff options
Diffstat (limited to 'compiler/rustc_serialize/src/leb128.rs')
| -rw-r--r-- | compiler/rustc_serialize/src/leb128.rs | 110 |
1 files changed, 110 insertions, 0 deletions
diff --git a/compiler/rustc_serialize/src/leb128.rs b/compiler/rustc_serialize/src/leb128.rs new file mode 100644 index 00000000000..1fe6a309e96 --- /dev/null +++ b/compiler/rustc_serialize/src/leb128.rs @@ -0,0 +1,110 @@ +macro_rules! impl_write_unsigned_leb128 { + ($fn_name:ident, $int_ty:ident) => { + #[inline] + pub fn $fn_name(out: &mut Vec<u8>, mut value: $int_ty) { + loop { + if value < 0x80 { + out.push(value as u8); + break; + } else { + out.push(((value & 0x7f) | 0x80) as u8); + value >>= 7; + } + } + } + }; +} + +impl_write_unsigned_leb128!(write_u16_leb128, u16); +impl_write_unsigned_leb128!(write_u32_leb128, u32); +impl_write_unsigned_leb128!(write_u64_leb128, u64); +impl_write_unsigned_leb128!(write_u128_leb128, u128); +impl_write_unsigned_leb128!(write_usize_leb128, usize); + +macro_rules! impl_read_unsigned_leb128 { + ($fn_name:ident, $int_ty:ident) => { + #[inline] + pub fn $fn_name(slice: &[u8]) -> ($int_ty, usize) { + let mut result = 0; + let mut shift = 0; + let mut position = 0; + loop { + let byte = slice[position]; + position += 1; + if (byte & 0x80) == 0 { + result |= (byte as $int_ty) << shift; + return (result, position); + } else { + result |= ((byte & 0x7F) as $int_ty) << shift; + } + shift += 7; + } + } + }; +} + +impl_read_unsigned_leb128!(read_u16_leb128, u16); +impl_read_unsigned_leb128!(read_u32_leb128, u32); +impl_read_unsigned_leb128!(read_u64_leb128, u64); +impl_read_unsigned_leb128!(read_u128_leb128, u128); +impl_read_unsigned_leb128!(read_usize_leb128, usize); + +#[inline] +/// encodes an integer using signed leb128 encoding and stores +/// the result using a callback function. +/// +/// The callback `write` is called once for each position +/// that is to be written to with the byte to be encoded +/// at that position. +pub fn write_signed_leb128_to<W>(mut value: i128, mut write: W) +where + W: FnMut(u8), +{ + loop { + let mut byte = (value as u8) & 0x7f; + value >>= 7; + let more = + !(((value == 0) && ((byte & 0x40) == 0)) || ((value == -1) && ((byte & 0x40) != 0))); + + if more { + byte |= 0x80; // Mark this byte to show that more bytes will follow. + } + + write(byte); + + if !more { + break; + } + } +} + +#[inline] +pub fn write_signed_leb128(out: &mut Vec<u8>, value: i128) { + write_signed_leb128_to(value, |v| out.push(v)) +} + +#[inline] +pub fn read_signed_leb128(data: &[u8], start_position: usize) -> (i128, usize) { + let mut result = 0; + let mut shift = 0; + let mut position = start_position; + let mut byte; + + loop { + byte = data[position]; + position += 1; + result |= i128::from(byte & 0x7F) << shift; + shift += 7; + + if (byte & 0x80) == 0 { + break; + } + } + + if (shift < 64) && ((byte & 0x40) != 0) { + // sign extend + result |= -(1 << shift); + } + + (result, position - start_position) +} |
