added i128 integer support

This commit is contained in:
alessandrokonrad
2022-10-16 20:20:47 -04:00
committed by Lucas
parent e30bd829aa
commit 28b9fed8e5
12 changed files with 117 additions and 16 deletions

View File

@@ -36,6 +36,12 @@ impl Decode<'_> for isize {
}
}
impl Decode<'_> for i128 {
fn decode(d: &mut Decoder) -> Result<Self, Error> {
d.big_integer()
}
}
impl Decode<'_> for usize {
fn decode(d: &mut Decoder) -> Result<Self, Error> {
d.word()

View File

@@ -35,6 +35,18 @@ impl<'b> Decoder<'b> {
Ok(zigzag::to_isize(self.word()?))
}
/// Decode an integer of any size.
/// This is byte alignment agnostic.
/// First we decode the next 8 bits of the buffer.
/// We take the 7 least significant bits as the 7 least significant bits of the current unsigned integer.
/// If the most significant bit of the 8 bits is 1 then we take the next 8 and repeat the process above,
/// filling in the next 7 least significant bits of the unsigned integer and so on.
/// If the most significant bit was instead 0 we stop decoding any more bits.
/// Finally we use zigzag to convert the unsigned integer back to a signed integer.
pub fn big_integer(&mut self) -> Result<i128, Error> {
Ok(zigzag::to_i128(self.big_word()?))
}
/// Decode a single bit of the buffer to get a bool.
/// We mask out a single bit of the buffer based on used bits.
/// and check if it is 0 for false or 1 for true.
@@ -130,6 +142,28 @@ impl<'b> Decoder<'b> {
Ok(final_word)
}
/// Decode a word of any size.
/// This is byte alignment agnostic.
/// First we decode the next 8 bits of the buffer.
/// We take the 7 least significant bits as the 7 least significant bits of the current unsigned integer.
/// If the most significant bit of the 8 bits is 1 then we take the next 8 and repeat the process above,
/// filling in the next 7 least significant bits of the unsigned integer and so on.
/// If the most significant bit was instead 0 we stop decoding any more bits.
pub fn big_word(&mut self) -> Result<u128, Error> {
let mut leading_bit = 1;
let mut final_word: u128 = 0;
let mut shl: u128 = 0;
// continue looping if lead bit is 1 which is 128 as a u8 otherwise exit
while leading_bit > 0 {
let word8 = self.bits8(8)?;
let word7 = word8 & 127;
final_word |= (word7 as u128) << shl;
shl += 7;
leading_bit = word8 & 128;
}
Ok(final_word)
}
/// Decode a list of items with a decoder function.
/// This is byte alignment agnostic.
/// Decode a bit from the buffer.

View File

@@ -26,6 +26,14 @@ impl Encode for u8 {
}
}
impl Encode for i128 {
fn encode(&self, e: &mut Encoder) -> Result<(), Error> {
e.big_integer(*self);
Ok(())
}
}
impl Encode for isize {
fn encode(&self, e: &mut Encoder) -> Result<(), Error> {
e.integer(*self);

View File

@@ -98,6 +98,19 @@ impl Encoder {
self
}
/// Encode an integer of any size.
/// This is byte alignment agnostic.
/// First we use zigzag once to double the number and encode the negative sign as the least significant bit.
/// Next we encode the 7 least significant bits of the unsigned integer. If the number is greater than
/// 127 we encode a leading 1 followed by repeating the encoding above for the next 7 bits and so on.
pub fn big_integer(&mut self, i: i128) -> &mut Self {
let i = zigzag::to_u128(i);
self.big_word(i);
self
}
/// Encode a char of 32 bits.
/// This is byte alignment agnostic.
/// We encode the 7 least significant bits of the unsigned byte. If the char value is greater than
@@ -152,6 +165,29 @@ impl Encoder {
self
}
/// Encode a unsigned integer of any size.
/// This is byte alignment agnostic.
/// We encode the 7 least significant bits of the unsigned byte. If the char value is greater than
/// 127 we encode a leading 1 followed by repeating the above for the next 7 bits and so on.
pub fn big_word(&mut self, c: u128) -> &mut Self {
let mut d = c;
loop {
let mut w = (d & 127) as u8;
d >>= 7;
if d != 0 {
w |= 128;
}
self.bits(8, w);
if d == 0 {
break;
}
}
self
}
/// Encode a list of bytes with a function
/// This is byte alignment agnostic.
/// If there are bytes in a list then write 1 bit followed by the functions encoding.

View File

@@ -11,3 +11,17 @@ pub fn to_usize(x: isize) -> usize {
pub fn to_isize(u: usize) -> isize {
((u >> 1) as isize) ^ (-((u & 1) as isize))
}
pub fn to_u128(x: i128) -> u128 {
let double_x = x << 1;
if x.is_positive() || x == 0 {
double_x as u128
} else {
(-double_x - 1) as u128
}
}
pub fn to_i128(u: u128) -> i128 {
((u >> 1) as i128) ^ (-((u & 1) as i128))
}