1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#![cfg_attr(feature = "nightly", deny(missing_docs))]
#![cfg_attr(feature = "nightly", feature(external_doc))]
#![cfg_attr(feature = "nightly", doc(include = "../README.md"))]
#![cfg_attr(test, deny(warnings))]

/// Returns how many bytes are needed to encode a value.
#[inline]
pub fn length(value: u64) -> usize {
  let zero_len = 64 - value.leading_zeros();
  let offset = if zero_len == 0 { 7 } else { 6 };
  ((offset + zero_len) / 7) as usize
}

/// Encode a `u64` integer to the byte slice. Returns how many bytes were
/// encoded.
#[inline]
pub fn encode(value: u64, buf: &mut [u8]) -> usize {
  encode_with_offset(value, buf, 0)
}

/// Encode a `u64` integer at a specific offset in the byte slice. Returns how
/// many bytes were encoded.
#[inline]
pub fn encode_with_offset(value: u64, buf: &mut [u8], offset: usize) -> usize {
  let mut off = offset;
  let mut val = value;

  while val > 127 {
    buf[off] = (val as u8) | 128;
    off += 1;
    val >>= 7;
  }
  buf[off] = val as u8;

  off + 1 - offset
}

/// Decode a byte slice into a `u64` integer. Returns how many bytes were
/// decoded.
#[inline]
pub fn decode(buf: &[u8], value: &mut u64) -> usize {
  decode_with_offset(buf, 0, value)
}

/// Decode a byte slice into a `u64` integer at a specific offset. Returns how
/// many bytes were decoded.
#[inline]
pub fn decode_with_offset(buf: &[u8], offset: usize, value: &mut u64) -> usize {
  let mut val = 0 as u64;
  let mut fac = 1 as u64;
  let mut off = offset;

  loop {
    let byte = buf[off];
    off += 1;
    val += fac * ((byte & 127) as u64);
    fac <<= 7;
    if byte & 128 == 0 {
      break;
    }
  }

  *value = val;

  off - offset
}

/// Returns how many bytes are needed to encode a value.
#[inline]
pub fn signed_length(value: i64) -> usize {
  length(unsign(value))
}

/// Encode a `i64` (signed) integer at a specific offset in the byte slice.
/// Returns how many bytes were encoded.
#[inline]
pub fn signed_encode(value: i64, buf: &mut [u8]) -> usize {
  encode_with_offset(unsign(value), buf, 0)
}

/// Encode a `i64` (signed) integer at a specific offset in the byte slice.
/// Returns how many bytes were encoded.
#[inline]
pub fn signed_encode_with_offset(
  value: i64,
  buf: &mut [u8],
  offset: usize,
) -> usize {
  encode_with_offset(unsign(value), buf, offset)
}

/// Decode a byte slice into a `i64` (signed) integer.  Returns how many bytes
/// were decoded.
#[inline]
pub fn signed_decode(buf: &[u8], value: &mut i64) -> usize {
  signed_decode_with_offset(buf, 0, value)
}

/// Decode a byte slice into a `i64` (signed) integer at a specific offset.
/// Returns how many bytes were decoded.
#[inline]
pub fn signed_decode_with_offset(
  buf: &[u8],
  offset: usize,
  value: &mut i64,
) -> usize {
  let mut val = 0;
  let off = decode_with_offset(buf, offset, &mut val);
  *value = sign(val);
  off
}

/// Convert an `i64` into a `u64`.
#[inline]
fn unsign(value: i64) -> u64 {
  if value >= 0 {
    (value * 2) as u64
  } else {
    (value * -2 - 1) as u64
  }
}

/// Convert a `u64` into a `i64`.
#[inline]
fn sign(value: u64) -> i64 {
  if value & 1 != 0 {
    -(((value + 1) / 2) as i64)
  } else {
    (value / 2) as i64
  }
}