added i128 integer support
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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.
|
||||
|
||||
@@ -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))
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user