use std::mem::MaybeUninit; use crate::varint::MAX_VARINT_ENCODED_LEN; /// Encode u64 as varint. /// Panics if buffer length is less than 10. #[inline] pub(crate) fn encode_varint64(mut value: u64, buf: &mut [MaybeUninit]) -> usize { assert!(buf.len() >= MAX_VARINT_ENCODED_LEN); fn iter(value: &mut u64, byte: &mut MaybeUninit) -> bool { if (*value & !0x7F) > 0 { byte.write(((*value & 0x7F) | 0x80) as u8); *value >>= 7; true } else { byte.write(*value as u8); false } } // Explicitly unroll loop to avoid either // unsafe code or bound checking when writing to `buf` if !iter(&mut value, &mut buf[0]) { return 1; }; if !iter(&mut value, &mut buf[1]) { return 2; }; if !iter(&mut value, &mut buf[2]) { return 3; }; if !iter(&mut value, &mut buf[3]) { return 4; }; if !iter(&mut value, &mut buf[4]) { return 5; }; if !iter(&mut value, &mut buf[5]) { return 6; }; if !iter(&mut value, &mut buf[6]) { return 7; }; if !iter(&mut value, &mut buf[7]) { return 8; }; if !iter(&mut value, &mut buf[8]) { return 9; }; buf[9].write(value as u8); 10 } /// Encode u32 value as varint. /// Panics if buffer length is less than 5. #[inline] pub(crate) fn encode_varint32(mut value: u32, buf: &mut [MaybeUninit]) -> usize { assert!(buf.len() >= 5); fn iter(value: &mut u32, byte: &mut MaybeUninit) -> bool { if (*value & !0x7F) > 0 { byte.write(((*value & 0x7F) | 0x80) as u8); *value >>= 7; true } else { byte.write(*value as u8); false } } // Explicitly unroll loop to avoid either // unsafe code or bound checking when writing to `buf` if !iter(&mut value, &mut buf[0]) { return 1; }; if !iter(&mut value, &mut buf[1]) { return 2; }; if !iter(&mut value, &mut buf[2]) { return 3; }; if !iter(&mut value, &mut buf[3]) { return 4; }; buf[4].write(value as u8); 5 } /// Encoded size of u64 value. #[inline] pub(crate) fn encoded_varint64_len(value: u64) -> usize { if value == 0 { 1 } else { let significant_bits = 64 - value.leading_zeros(); (significant_bits + 6) as usize / 7 } } #[cfg(test)] mod test { use std::mem::MaybeUninit; use crate::varint::encode::encode_varint64; use crate::varint::encode::encoded_varint64_len; #[test] fn test_encoded_varint64_len() { fn test(n: u64) { let mut buf = [MaybeUninit::uninit(); 10]; let expected = encode_varint64(n, &mut buf); assert_eq!(expected, encoded_varint64_len(n), "n={}", n); } for n in 0..1000 { test(n); } for p in 0.. { match 2u64.checked_pow(p) { Some(n) => test(n), None => break, } } for p in 0.. { match 3u64.checked_pow(p) { Some(n) => test(n), None => break, } } test(u64::MAX); test(u64::MAX - 1); test((i64::MAX as u64) + 1); test(i64::MAX as u64); test((i64::MAX as u64) - 1); test((u32::MAX as u64) + 1); test(u32::MAX as u64); test((u32::MAX as u64) - 1); test((i32::MAX as u64) + 1); test(i32::MAX as u64); test((i32::MAX as u64) - 1); } }