+variable-length signed support

This commit is contained in:
sergeych committed 2023-10-12 00:40:15 +01:00
1 parent 588446cd42
commit e0ac1b1094
5 files changed
+90 -15

No files matched your search

+21 -11
View File
@@ -54,12 +54,12 @@ pub trait BipackSink {
for b in data { self.put_u8(*b); }
}
fn put_var_bytes(self: &mut Self,data: &[u8]) {
fn put_var_bytes(self: &mut Self, data: &[u8]) {
self.put_unsigned(data.len());
self.put_fixed_bytes(data);
}
fn put_str(self: &mut Self,str: &str) {
fn put_str(self: &mut Self, str: &str) {
self.put_var_bytes(str.as_bytes());
}
@@ -118,20 +118,30 @@ pub trait BipackSink {
};
if value < V0LIMIT {
encode_seq(0, &[value]);
}
else if value < V1LIMIT {
encode_seq( 1, &[value & 0x3F, value >> 6]);
}
else if value < V2LIMIT {
encode_seq( 2, &[value & 0x3f, value >> 6, value >> 14]);
}
else {
encode_seq(0, &[value]);
} else if value < V1LIMIT {
encode_seq(1, &[value & 0x3F, value >> 6]);
} else if value < V2LIMIT {
encode_seq(2, &[value & 0x3f, value >> 6, value >> 14]);
} else {
encode_seq(3, &[value & 0x3f, value >> 6, value >> 14]);
self.put_var_unsigned(value >> 22);
}
}
/// Put variable-length encoded integer value. it is packed just like variable-length
/// unsigned value except that LSB (bit 0) is used as negative number flag (when set,
/// the encoded number is negative).
///
/// Note that because of this the range of supported integers is one bit smaller than
/// i64, only 30 bits for value and one for a sign. This will probably be fixed later
/// but please note that it is impractical to store really big numbers in variable-length
/// format, consider using [put_i64] instead which has no such limitation.
fn put_signed(self: &mut Self, val: i64) {
let (neg, val) = if val < 0 { (1, -val) } else { (0, val) };
self.put_unsigned( (neg as u64) | ((val as u64) << 1) );
}
fn put_var_unsigned(self: &mut Self, value: u64) {
let mut rest = value;
loop {
+8
View File
@@ -97,6 +97,14 @@ pub trait BipackSource {
Ok(result | (self.get_varint_unsigned()? << 22))
}
/// Unpack variable-length signed value, packed with
/// [crate::bipack_sink::BipackSink::put_signed], see it for the packing details.
fn get_signed(self: &mut Self) -> Result<i64> {
let value = self.get_unsigned()?;
let result = (value >> 1) as i64;
Ok(if value & 1 != 0 { -result } else { result } )
}
/// read 8-bytes varint-packed unsigned value from the source. We dont' recommend
/// using it directly; use [BipackSource::get_unsigned] instead.
fn get_varint_unsigned(self: &mut Self) -> Result<u64> {
+27
View File
@@ -245,6 +245,33 @@ mod tests {
}
#[test]
fn test_varsigned() -> Result<()> {
fn test(value: i64) -> Result<()> {
let mut x = Vec::new();
x.put_signed(value);
assert_eq!(value, SliceSource::from(&x).get_signed()?);
Ok(())
}
fn test2(value: i64) -> Result<()> {
test(value)?;
test(-value)?;
Ok(())
}
test(0)?;
test2(1)?;
test2(2)?;
test2(64)?;
test2(65)?;
test2(127)?;
test2(128)?;
test2(255)?;
test2(256)?;
test2(2147483647)?;
test2(2222147483647)?;
Ok(())
}
#[test]
fn test_packer() -> Result<()>{
let a = 177u32;
let b = "hello!";