Skip to content

Commit

Permalink
Merge pull request #50 from ferrous-systems/leb
Browse files Browse the repository at this point in the history
Move leb64 encoding and tests to its own file
  • Loading branch information
japaric authored Aug 4, 2020
2 parents 36e5280 + 5f9426e commit 7dce165
Show file tree
Hide file tree
Showing 3 changed files with 109 additions and 106 deletions.
107 changes: 107 additions & 0 deletions src/leb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
/// # Unsafety
/// `buf` must be large enough to hold the encoded value
pub(crate) unsafe fn leb64(x: u64, buf: &mut [u8]) -> usize {
let mut low = x as u32;
let mut high = (x >> 32) as u32;

let mut i = 0;
loop {
let mut byte = (low & 0x7f) as u8;
low >>= 7;
if low != 0 {
byte |= 0x80;
}

*buf.get_unchecked_mut(i) = byte;
i += 1;
if low == 0 {
break;
}
}

if high == 0 {
return i;
}

for j in (i - 1)..4 {
*buf.get_unchecked_mut(j) = 0x80;
}

if i != 5 {
*buf.get_unchecked_mut(4) = 0;
}

i = 4;
*buf.get_unchecked_mut(i) |= (high as u8 & 0b111) << 4;
high >>= 3;

if high != 0 {
*buf.get_unchecked_mut(i) |= 0x80;
}

i += 1;

if high == 0 {
return i;
}

loop {
let mut byte = (high & 0x7f) as u8;
high >>= 7;
if high != 0 {
byte |= 0x80;
}

*buf.get_unchecked_mut(i) = byte;
i += 1;
if high == 0 {
return i;
}
}
}

#[cfg(test)]
mod tests {
#[test]
fn leb() {
let mut buf = [0x55; 10];

let i = unsafe { super::leb64(0, &mut buf) };
assert_eq!(buf[..i], [0]);
buf.iter_mut().for_each(|b| *b = 0x55);

let i = unsafe { super::leb64(1, &mut buf) };
assert_eq!(buf[..i], [1]);
buf.iter_mut().for_each(|b| *b = 0x55);

let i = unsafe { super::leb64((1 << 7) - 1, &mut buf) };
assert_eq!(buf[..i], [0x7f]);
buf.iter_mut().for_each(|b| *b = 0x55);

let i = unsafe { super::leb64(1 << 7, &mut buf) };
assert_eq!(buf[..i], [0x80, 1]);
buf.iter_mut().for_each(|b| *b = 0x55);

let i = unsafe { super::leb64((1 << 32) - 1, &mut buf) };
assert_eq!(buf[..i], [0xff, 0xff, 0xff, 0xff, 0xf]);
buf.iter_mut().for_each(|b| *b = 0x55);

let i = unsafe { super::leb64((1 << 35) - 1, &mut buf) };
assert_eq!(buf[..i], [0xff, 0xff, 0xff, 0xff, 0x7f]);
buf.iter_mut().for_each(|b| *b = 0x55);

let i = unsafe { super::leb64(1 << 35, &mut buf) };
assert_eq!(buf[..i], [0x80, 0x80, 0x80, 0x80, 0x80, 1]);
buf.iter_mut().for_each(|b| *b = 0x55);

let i = unsafe { super::leb64((1 << 42) - 1, &mut buf) };
assert_eq!(buf[..i], [0xff, 0xff, 0xff, 0xff, 0xff, 0x7f]);
buf.iter_mut().for_each(|b| *b = 0x55);

let i = unsafe { super::leb64(u64::max_value(), &mut buf) };
assert_eq!(
buf[..i],
[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1]
);
}
}
65 changes: 2 additions & 63 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ use core::{mem::MaybeUninit, ptr::NonNull};
#[doc(hidden)]
pub mod export;
mod impls;
mod leb;
#[cfg(test)]
mod tests;

Expand Down Expand Up @@ -147,68 +148,6 @@ pub struct Formatter {
bytes: Vec<u8>,
}

/// # Unsafety
/// `buf` must be large enough to hold the encoded value
unsafe fn leb64(x: u64, buf: &mut [u8]) -> usize {
let mut low = x as u32;
let mut high = (x >> 32) as u32;

let mut i = 0;
loop {
let mut byte = (low & 0x7f) as u8;
low >>= 7;
if low != 0 {
byte |= 0x80;
}

*buf.get_unchecked_mut(i) = byte;
i += 1;
if low == 0 {
break;
}
}

if high == 0 {
return i;
}

for j in (i - 1)..4 {
*buf.get_unchecked_mut(j) = 0x80;
}

if i != 5 {
*buf.get_unchecked_mut(4) = 0;
}

i = 4;
*buf.get_unchecked_mut(i) |= (high as u8 & 0b111) << 4;
high >>= 3;

if high != 0 {
*buf.get_unchecked_mut(i) |= 0x80;
}

i += 1;

if high == 0 {
return i;
}

loop {
let mut byte = (high & 0x7f) as u8;
high >>= 7;
if high != 0 {
byte |= 0x80;
}

*buf.get_unchecked_mut(i) = byte;
i += 1;
if high == 0 {
return i;
}
}
}

impl Formatter {
/// Only for testing on x86_64
#[cfg(target_arch = "x86_64")]
Expand Down Expand Up @@ -273,7 +212,7 @@ impl Formatter {
#[doc(hidden)]
pub fn leb64(&mut self, x: u64) {
let mut buf: [u8; 10] = unsafe { MaybeUninit::uninit().assume_init() };
let i = unsafe { leb64(x, &mut buf) };
let i = unsafe { leb::leb64(x, &mut buf) };
self.write(unsafe { buf.get_unchecked(..i) })
}

Expand Down
43 changes: 0 additions & 43 deletions src/tests.rs
Original file line number Diff line number Diff line change
@@ -1,48 +1,5 @@
use crate as binfmt;

#[test]
fn leb() {
let mut buf = [0x55; 10];

let i = unsafe { super::leb64(0, &mut buf) };
assert_eq!(buf[..i], [0]);
buf.iter_mut().for_each(|b| *b = 0x55);

let i = unsafe { super::leb64(1, &mut buf) };
assert_eq!(buf[..i], [1]);
buf.iter_mut().for_each(|b| *b = 0x55);

let i = unsafe { super::leb64((1 << 7) - 1, &mut buf) };
assert_eq!(buf[..i], [0x7f]);
buf.iter_mut().for_each(|b| *b = 0x55);

let i = unsafe { super::leb64(1 << 7, &mut buf) };
assert_eq!(buf[..i], [0x80, 1]);
buf.iter_mut().for_each(|b| *b = 0x55);

let i = unsafe { super::leb64((1 << 32) - 1, &mut buf) };
assert_eq!(buf[..i], [0xff, 0xff, 0xff, 0xff, 0xf]);
buf.iter_mut().for_each(|b| *b = 0x55);

let i = unsafe { super::leb64((1 << 35) - 1, &mut buf) };
assert_eq!(buf[..i], [0xff, 0xff, 0xff, 0xff, 0x7f]);
buf.iter_mut().for_each(|b| *b = 0x55);

let i = unsafe { super::leb64(1 << 35, &mut buf) };
assert_eq!(buf[..i], [0x80, 0x80, 0x80, 0x80, 0x80, 1]);
buf.iter_mut().for_each(|b| *b = 0x55);

let i = unsafe { super::leb64((1 << 42) - 1, &mut buf) };
assert_eq!(buf[..i], [0xff, 0xff, 0xff, 0xff, 0xff, 0x7f]);
buf.iter_mut().for_each(|b| *b = 0x55);

let i = unsafe { super::leb64(u64::max_value(), &mut buf) };
assert_eq!(
buf[..i],
[0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 1]
);
}

#[test]
fn log_levels() {
// just make sure they build OK for now
Expand Down

0 comments on commit 7dce165

Please sign in to comment.