Git fork
at reftables-rust 107 lines 3.4 kB view raw
1/// Decode the variable-length integer stored in `bufp` and return the decoded value. 2/// 3/// Returns 0 in case the decoded integer would overflow u64::MAX. 4/// 5/// # Safety 6/// 7/// The buffer must be NUL-terminated to ensure safety. 8#[no_mangle] 9pub unsafe extern "C" fn decode_varint(bufp: *mut *const u8) -> u64 { 10 let mut buf = *bufp; 11 let mut c = *buf; 12 let mut val = u64::from(c & 127); 13 14 buf = buf.add(1); 15 16 while (c & 128) != 0 { 17 val = val.wrapping_add(1); 18 if val == 0 || val.leading_zeros() < 7 { 19 return 0; // overflow 20 } 21 22 c = *buf; 23 buf = buf.add(1); 24 25 val = (val << 7) + u64::from(c & 127); 26 } 27 28 *bufp = buf; 29 val 30} 31 32/// Encode `value` into `buf` as a variable-length integer unless `buf` is null. 33/// 34/// Returns the number of bytes written, or, if `buf` is null, the number of bytes that would be 35/// written to encode the integer. 36/// 37/// # Safety 38/// 39/// `buf` must either be null or point to at least 16 bytes of memory. 40#[no_mangle] 41pub unsafe extern "C" fn encode_varint(value: u64, buf: *mut u8) -> u8 { 42 let mut varint: [u8; 16] = [0; 16]; 43 let mut pos = varint.len() - 1; 44 45 varint[pos] = (value & 127) as u8; 46 47 let mut value = value >> 7; 48 while value != 0 { 49 pos -= 1; 50 value -= 1; 51 varint[pos] = 128 | (value & 127) as u8; 52 value >>= 7; 53 } 54 55 if !buf.is_null() { 56 std::ptr::copy_nonoverlapping(varint.as_ptr().add(pos), buf, varint.len() - pos); 57 } 58 59 (varint.len() - pos) as u8 60} 61 62#[cfg(test)] 63mod tests { 64 use super::*; 65 66 #[test] 67 fn test_decode_varint() { 68 unsafe { 69 assert_eq!(decode_varint(&mut [0x00].as_slice().as_ptr()), 0); 70 assert_eq!(decode_varint(&mut [0x01].as_slice().as_ptr()), 1); 71 assert_eq!(decode_varint(&mut [0x7f].as_slice().as_ptr()), 127); 72 assert_eq!(decode_varint(&mut [0x80, 0x00].as_slice().as_ptr()), 128); 73 assert_eq!(decode_varint(&mut [0x80, 0x01].as_slice().as_ptr()), 129); 74 assert_eq!(decode_varint(&mut [0x80, 0x7f].as_slice().as_ptr()), 255); 75 76 // Overflows are expected to return 0. 77 assert_eq!(decode_varint(&mut [0x88; 16].as_slice().as_ptr()), 0); 78 } 79 } 80 81 #[test] 82 fn test_encode_varint() { 83 unsafe { 84 let mut varint: [u8; 16] = [0; 16]; 85 86 assert_eq!(encode_varint(0, std::ptr::null_mut()), 1); 87 88 assert_eq!(encode_varint(0, varint.as_mut_slice().as_mut_ptr()), 1); 89 assert_eq!(varint, [0; 16]); 90 91 assert_eq!(encode_varint(10, varint.as_mut_slice().as_mut_ptr()), 1); 92 assert_eq!(varint, [10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); 93 94 assert_eq!(encode_varint(127, varint.as_mut_slice().as_mut_ptr()), 1); 95 assert_eq!(varint, [127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); 96 97 assert_eq!(encode_varint(128, varint.as_mut_slice().as_mut_ptr()), 2); 98 assert_eq!(varint, [128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); 99 100 assert_eq!(encode_varint(129, varint.as_mut_slice().as_mut_ptr()), 2); 101 assert_eq!(varint, [128, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); 102 103 assert_eq!(encode_varint(255, varint.as_mut_slice().as_mut_ptr()), 2); 104 assert_eq!(varint, [128, 127, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]); 105 } 106 } 107}