use futures::io;
use tokio::io::{AsyncWrite, AsyncWriteExt};
pub const MAX_ENCODING_LEN: usize = 10;
pub fn encoding_len(num: u64) -> usize {
match num {
0 => 1,
num => ((64 + 6) - num.leading_zeros() as usize) / 7,
}
}
#[derive(Debug, PartialEq)]
pub enum DecodeError {
EncodedValueTooLarge,
UnexpectedEndOfBuffer,
UnexpectedEncodingLen,
}
#[inline]
const fn is_last_encoded_byte(byte: u8) -> bool {
byte >= 0x80
}
#[inline]
const fn clear_msb(byte: u8) -> u8 {
byte & 0x7f
}
#[inline]
const fn set_msb(byte: u8) -> u8 {
byte | 0x80
}
#[inline]
fn max_byte_too_large(shift: u32, byte: u8) -> bool {
shift == 63 && byte > 0x81
}
pub fn decode(buf: &[u8]) -> Result<(u64, usize), DecodeError> {
let mut num: u64 = 0;
let mut shift: u32 = 0;
for (i, &b) in buf.iter().enumerate() {
if is_last_encoded_byte(b) {
return if max_byte_too_large(shift, b) {
Err(DecodeError::EncodedValueTooLarge)
} else {
Ok((num | ((clear_msb(b) as u64) << shift), i + 1))
};
}
num |= (b as u64) << shift;
shift += 7;
if shift > 64 {
return Err(DecodeError::UnexpectedEncodingLen);
}
}
Err(DecodeError::UnexpectedEndOfBuffer)
}
#[inline]
const fn more_than_7bits_remain(num: u64) -> bool {
num >= 0x80
}
unsafe fn encode_unchecked(buf: &mut [u8], mut num: u64) -> usize {
let mut i = 0;
while more_than_7bits_remain(num) {
*buf.get_unchecked_mut(i) = clear_msb(num as u8);
num >>= 7;
i += 1;
}
*buf.get_unchecked_mut(i) = set_msb(num as u8);
i + 1
}
pub fn encode_slice(buf: &mut [u8], num: u64) -> Option<usize> {
if encoding_len(num) > buf.len() {
None
} else {
unsafe { Some(encode_unchecked(buf, num)) }
}
}
pub fn encode_vec(num: u64) -> Vec<u8> {
let mut vec = vec![0; encoding_len(num)];
unsafe { encode_unchecked(&mut vec, num) };
vec
}
pub async fn write_async<A>(dest: &mut A, num: u64) -> io::Result<usize>
where
A: 'static + AsyncWrite + Unpin + Send,
{
let vec = encode_vec(num);
let len = vec.len();
dest.write_all(&vec).await?;
Ok(len)
}
#[cfg(test)]
mod tests {
use super::*;
fn encode_decode_success(buf: &mut [u8], expected: &[u8], num: u64) {
assert_eq!(Some(expected.len()), encode_slice(buf, num));
assert_eq!(expected, buf);
let (n, len) = decode(&buf).unwrap();
assert_eq!(num, n);
assert_eq!(expected.len(), len);
}
#[test]
fn encode_decode_1_byte() {
let mut buf = [0; 1];
encode_decode_success(&mut buf, &[set_msb(0)], 0);
encode_decode_success(&mut buf, &[set_msb(1)], 1);
encode_decode_success(&mut buf, &[set_msb(42)], 42);
}
#[test]
fn encode_decode_2_bytes() {
let mut buf = [0; 2];
encode_decode_success(&mut buf, &[0b0101000, set_msb(0b1)], 0b1_0101000);
let expected = [0b0000000, set_msb(0b1111111)];
encode_decode_success(&mut buf, &expected, 0b1111111_0000000);
}
#[test]
fn encode_decode_4_bytes() {
let mut buf = [0; 4];
let expected = [0b0110010, 0b0101111, 0b0011101, set_msb(0b10100)];
encode_decode_success(&mut buf, &expected, 0b10100_0011101_0101111_0110010);
}
#[test]
fn encode_decode_7_bytes() {
let mut buf = [0; 7];
let expected = [
0b0100000,
0b0010010,
0b1010101,
0b1001010,
0b1001000,
0b1000110,
set_msb(0b1100001),
];
let num = 0b1100001_1000110_1001000_1001010_1010101_0010010_0100000;
encode_decode_success(&mut buf, &expected, num);
}
#[test]
fn encode_decode_max_bytes() {
let mut buf = [0; MAX_ENCODING_LEN];
let mut expected = [0x7f; 10];
assert_eq!(Err(DecodeError::UnexpectedEncodingLen), decode(&buf));
expected[9] = set_msb(0x01);
encode_decode_success(&mut buf, &expected, u64::max_value());
expected[0] -= 1;
encode_decode_success(&mut buf, &expected, u64::max_value() - 1);
}
#[test]
fn encode_decode_4_bytes_in_20_bytes() {
let mut buf = [0; 20];
assert_eq!(Some(4), encode_slice(&mut buf, 194984659));
let (n, len) = decode(&buf).unwrap();
assert_eq!(194984659, n);
assert_eq!(4, len);
}
#[test]
fn encode_0_bytes_fails() {
let mut buf = [];
assert_eq!(None, encode_slice(&mut buf, 0));
}
#[test]
fn encode_4_bytes_to_3_bytes_fails() {
let mut buf = [0; 3];
let num = 0b1011100_1111100_1110101_1010011;
assert_eq!(None, encode_slice(&mut buf, num));
}
#[test]
fn decode_0_bytes_fails() {
let buf = [];
assert_eq!(Err(DecodeError::UnexpectedEndOfBuffer), decode(&buf));
}
#[test]
fn decode_1_byte_without_msb_fails() {
let buf = [0b0001000];
assert_eq!(Err(DecodeError::UnexpectedEndOfBuffer), decode(&buf));
}
#[test]
fn encoded_value_too_large_fails() {
let mut buf = [0; 10];
buf[9] = set_msb(0x02);
assert_eq!(Err(DecodeError::EncodedValueTooLarge), decode(&buf));
}
#[test]
fn decode_11_bytes_fails() {
let mut buf = [0; 11];
buf[10] = set_msb(0x01);
assert_eq!(Err(DecodeError::UnexpectedEncodingLen), decode(&buf));
}
#[test]
fn encoded_len_tests() {
for &(len, num) in &[
(1, 0),
(1, 1),
(2, 0b11_0101000),
(7, 0b1100001_1000110_1001000_1001010_1010101_0010010_0100000),
(10, u64::max_value() - 1),
(MAX_ENCODING_LEN, u64::max_value()),
] {
assert_eq!(len, encoding_len(num));
}
}
}