1#![doc = include_str!("../README.md")]
2#![cfg_attr(docsrs, feature(doc_auto_cfg))]
3#![cfg_attr(not(test), no_std)]
4
5use bytes::{Buf, BufMut};
6
7pub fn encode(mut value: u64, mut buf: impl BufMut) {
8 loop {
9 if value < 0x80 {
10 buf.put_u8(value as u8);
11 break;
12 } else {
13 buf.put_u8((value & 0x7f) as u8 | 0x80);
14 value >>= 7;
15 }
16 }
17}
18
19pub fn decode(mut buf: impl Buf) -> u64 {
20 let mut value = 0;
21 for i in 0..10.min(buf.remaining()) {
22 let byte = buf.get_u8();
23 value |= (byte as u64 & 0x7f) << (i * 7);
24 if byte < 0x80 {
25 if i == 9 && byte > 0x01 {
26 break;
27 } else {
28 return value;
29 }
30 }
31 }
32
33 panic!("encoded integer doesn't fit in u64");
34}
35
36pub fn encoded_len(value: u64) -> usize {
37 (((value | 0x1).ilog2() * 9 + 73) / 64) as _
40}
41
42#[cfg(test)]
43mod tests {
44 use super::*;
45 use proptest::{prelude::any, prop_assert_eq, proptest};
46
47 #[test]
48 fn min() {
49 let mut buf = [0u8; 1];
50 encode(0, &mut buf[..]);
51 assert_eq!(buf, [0u8; 1]);
52
53 let v = decode(&buf[..]);
54 assert_eq!(0, v);
55 }
56
57 #[test]
58 fn max() {
59 let mut buf = [0u8; 10];
60 encode(u64::MAX, &mut buf[..]);
61 let mut expected = [255u8; 10];
62 expected[9] = 0x01;
63 assert_eq!(buf, expected);
64
65 let v = decode(&buf[..]);
66 assert_eq!(u64::MAX, v);
67 }
68
69 proptest! {
70 #[test]
71 fn random(input in any::<u64>()) {
72 let mut buf = Vec::new();
73 encode(input, &mut buf);
74 prop_assert_eq!(encoded_len(input), buf.len());
75
76 let output = decode(&buf[..]);
77 prop_assert_eq!(input, output);
78 }
79 }
80}