use crate::types::byte;
pub struct ByteOrder {
big: bool,
}
#[allow(non_upper_case_globals)]
pub const BigEndian: ByteOrder = ByteOrder { big: true };
#[allow(non_upper_case_globals)]
pub const LittleEndian: ByteOrder = ByteOrder { big: false };
impl ByteOrder {
pub fn Uint16(&self, b: &[byte]) -> u16 {
if self.big {
u16::from_be_bytes([b[0], b[1]])
} else {
u16::from_le_bytes([b[0], b[1]])
}
}
pub fn Uint32(&self, b: &[byte]) -> u32 {
let bytes: [u8; 4] = [b[0], b[1], b[2], b[3]];
if self.big { u32::from_be_bytes(bytes) } else { u32::from_le_bytes(bytes) }
}
pub fn Uint64(&self, b: &[byte]) -> u64 {
let bytes: [u8; 8] = [b[0], b[1], b[2], b[3], b[4], b[5], b[6], b[7]];
if self.big { u64::from_be_bytes(bytes) } else { u64::from_le_bytes(bytes) }
}
pub fn PutUint16(&self, b: &mut [byte], v: u16) {
let bytes = if self.big { v.to_be_bytes() } else { v.to_le_bytes() };
b[0] = bytes[0]; b[1] = bytes[1];
}
pub fn PutUint32(&self, b: &mut [byte], v: u32) {
let bytes = if self.big { v.to_be_bytes() } else { v.to_le_bytes() };
b[..4].copy_from_slice(&bytes);
}
pub fn PutUint64(&self, b: &mut [byte], v: u64) {
let bytes = if self.big { v.to_be_bytes() } else { v.to_le_bytes() };
b[..8].copy_from_slice(&bytes);
}
pub fn AppendUint16(&self, mut b: Vec<byte>, v: u16) -> Vec<byte> {
let bytes = if self.big { v.to_be_bytes() } else { v.to_le_bytes() };
b.extend_from_slice(&bytes);
b
}
pub fn AppendUint32(&self, mut b: Vec<byte>, v: u32) -> Vec<byte> {
let bytes = if self.big { v.to_be_bytes() } else { v.to_le_bytes() };
b.extend_from_slice(&bytes);
b
}
pub fn AppendUint64(&self, mut b: Vec<byte>, v: u64) -> Vec<byte> {
let bytes = if self.big { v.to_be_bytes() } else { v.to_le_bytes() };
b.extend_from_slice(&bytes);
b
}
pub fn String(&self) -> &'static str {
if self.big { "BigEndian" } else { "LittleEndian" }
}
}
pub const MaxVarintLen64: usize = 10;
pub const MaxVarintLen32: usize = 5;
pub const MaxVarintLen16: usize = 3;
#[allow(non_snake_case)]
pub fn PutUvarint(buf: &mut [byte], mut x: u64) -> crate::types::int {
let mut i = 0;
while x >= 0x80 {
buf[i] = (x as u8) | 0x80;
x >>= 7;
i += 1;
}
buf[i] = x as u8;
(i + 1) as crate::types::int
}
#[allow(non_snake_case)]
pub fn Uvarint(buf: &[byte]) -> (u64, crate::types::int) {
let mut x: u64 = 0;
let mut s: u32 = 0;
for (i, &b) in buf.iter().enumerate() {
if i == MaxVarintLen64 {
return (0, -((i as crate::types::int) + 1));
}
if b < 0x80 {
if i == MaxVarintLen64 - 1 && b > 1 {
return (0, -((i as crate::types::int) + 1));
}
return (x | ((b as u64) << s), (i + 1) as crate::types::int);
}
x |= ((b & 0x7f) as u64) << s;
s += 7;
}
(0, 0)
}
#[allow(non_snake_case)]
pub fn PutVarint(buf: &mut [byte], x: i64) -> crate::types::int {
let ux = if x < 0 { (!((x as u64) << 1)).wrapping_add(1) | 1 } else { (x as u64) << 1 };
let zig = ((x << 1) ^ (x >> 63)) as u64;
let _ = ux;
PutUvarint(buf, zig)
}
#[allow(non_snake_case)]
pub fn Varint(buf: &[byte]) -> (i64, crate::types::int) {
let (u, n) = Uvarint(buf);
let x = ((u >> 1) as i64) ^ -((u & 1) as i64);
(x, n)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn big_endian_round_trip() {
let mut b = [0u8; 8];
BigEndian.PutUint64(&mut b, 0x0102_0304_0506_0708);
assert_eq!(b, [1, 2, 3, 4, 5, 6, 7, 8]);
assert_eq!(BigEndian.Uint64(&b), 0x0102_0304_0506_0708);
}
#[test]
fn little_endian_round_trip() {
let mut b = [0u8; 4];
LittleEndian.PutUint32(&mut b, 0xdead_beef);
assert_eq!(b, [0xef, 0xbe, 0xad, 0xde]);
assert_eq!(LittleEndian.Uint32(&b), 0xdead_beef);
}
#[test]
fn u16_round_trip_both_orders() {
let mut b = [0u8; 2];
BigEndian.PutUint16(&mut b, 0x1234);
assert_eq!(BigEndian.Uint16(&b), 0x1234);
LittleEndian.PutUint16(&mut b, 0x1234);
assert_eq!(LittleEndian.Uint16(&b), 0x1234);
}
#[test]
fn append_uint_helpers() {
let out = BigEndian.AppendUint32(vec![0xaa], 1u32);
assert_eq!(out, vec![0xaa, 0, 0, 0, 1]);
}
#[test]
fn uvarint_encodes_small() {
let mut b = [0u8; MaxVarintLen64];
let n = PutUvarint(&mut b, 1) as usize;
assert_eq!(n, 1);
assert_eq!(b[0], 1);
let (v, read) = Uvarint(&b[..n]);
assert_eq!(v, 1);
assert_eq!(read, 1);
}
#[test]
fn uvarint_encodes_large() {
let mut b = [0u8; MaxVarintLen64];
let n = PutUvarint(&mut b, 300) as usize;
assert_eq!(&b[..n], &[0xac, 0x02]);
let (v, _) = Uvarint(&b[..n]);
assert_eq!(v, 300);
}
#[test]
fn varint_round_trips_signed() {
for &v in &[0i64, 1, -1, 150, -150, i64::MAX, i64::MIN] {
let mut b = [0u8; MaxVarintLen64];
let n = PutVarint(&mut b, v) as usize;
let (r, _) = Varint(&b[..n]);
assert_eq!(r, v, "varint roundtrip {} != {}", r, v);
}
}
#[test]
fn strings() {
assert_eq!(BigEndian.String(), "BigEndian");
assert_eq!(LittleEndian.String(), "LittleEndian");
}
}