ckb_script_ipc_common/
vlq.rs

1use alloc::vec::Vec;
2
3use crate::error::IpcError;
4/// Encodes an integer using VLQ (Variable-Length Quantity) encoding.
5pub fn vlq_encode(mut value: u64) -> Vec<u8> {
6    let mut buffer = Vec::new();
7    loop {
8        let mut byte = (value & 0x7F) as u8;
9        value >>= 7;
10        if value != 0 {
11            byte |= 0x80;
12        }
13        buffer.push(byte);
14        if value == 0 {
15            break;
16        }
17    }
18    buffer
19}
20
21/// Decodes a VLQ (Variable-Length Quantity) encoded byte slice into an integer.
22pub fn vlq_decode(bytes: &[u8]) -> Result<u64, IpcError> {
23    let mut value = 0u64;
24    let mut shift = 0;
25    for &byte in bytes {
26        value |= ((byte & 0x7F) as u64) << shift;
27        if byte & 0x80 == 0 {
28            return Ok(value);
29        }
30        shift += 7;
31        if shift >= 64 {
32            return Err(IpcError::DecodeVlqOverflow);
33        }
34    }
35    Err(IpcError::IncompleteVlqSeq)
36}
37
38#[cfg(test)]
39mod tests {
40    use alloc::vec;
41
42    use super::*;
43
44    #[test]
45    fn test_vlq_encode() {
46        assert_eq!(vlq_encode(0), vec![0]);
47        assert_eq!(vlq_encode(127), vec![127]);
48        assert_eq!(vlq_encode(128), vec![128, 1]);
49        assert_eq!(vlq_encode(16384), vec![128, 128, 1]);
50        assert_eq!(
51            vlq_encode(u64::MAX),
52            vec![255, 255, 255, 255, 255, 255, 255, 255, 255, 1]
53        );
54    }
55
56    #[test]
57    fn test_vlq_decode() {
58        assert_eq!(vlq_decode(&[0]).unwrap(), 0);
59        assert_eq!(vlq_decode(&[127]).unwrap(), 127);
60        assert_eq!(vlq_decode(&[128, 1]).unwrap(), 128);
61        assert_eq!(vlq_decode(&[128, 128, 1]).unwrap(), 16384);
62        assert_eq!(
63            vlq_decode(&[255, 255, 255, 255, 255, 255, 255, 255, 255, 1]).unwrap(),
64            u64::MAX
65        );
66    }
67
68    #[test]
69    fn test_vlq_encode_decode_roundtrip() {
70        let test_values = vec![0, 1, 127, 128, 16383, 16384, u64::MAX / 2, u64::MAX];
71        for value in test_values {
72            let encoded = vlq_encode(value);
73            let decoded = vlq_decode(&encoded).unwrap();
74            assert_eq!(decoded, value, "Roundtrip failed for value: {}", value);
75        }
76    }
77
78    #[test]
79    fn test_vlq_decode_errors() {
80        assert!(matches!(
81            vlq_decode(&[128, 128, 128, 128, 128, 128, 128, 128, 128, 128]),
82            Err(IpcError::DecodeVlqOverflow)
83        ));
84        assert!(matches!(
85            vlq_decode(&[128]),
86            Err(IpcError::IncompleteVlqSeq)
87        ));
88    }
89}