use crate::result::IonResult;
use crate::{Int, UInt};
use std::io::Write;
#[derive(Debug)]
pub struct DecodedUInt {
size_in_bytes: usize,
value: UInt,
}
impl DecodedUInt {
#[inline]
pub(crate) fn uint_from_slice(uint_bytes: &[u8]) -> UInt {
match uint_bytes.len() {
0 => 0u128.into(),
1 => uint_bytes[0].into(),
2 => u16::from_le_bytes([uint_bytes[1], uint_bytes[0]]).into(),
3 => u32::from_le_bytes([uint_bytes[2], uint_bytes[1], uint_bytes[0], 0u8]).into(),
_ => UInt::from_be_bytes(uint_bytes),
}
}
pub fn write_u64<W: Write>(sink: &mut W, magnitude: u64) -> IonResult<usize> {
let encoded = encode(magnitude);
let bytes_to_write = encoded.as_ref();
sink.write_all(bytes_to_write)?;
Ok(bytes_to_write.len())
}
#[inline(always)]
pub fn value(&self) -> &UInt {
&self.value
}
#[inline(always)]
pub fn size_in_bytes(&self) -> usize {
self.size_in_bytes
}
}
impl From<DecodedUInt> for Int {
fn from(uint: DecodedUInt) -> Self {
let DecodedUInt {
value,
.. } = uint;
value.into()
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct UIntBeBytes {
bytes: [u8; size_of::<u128>()],
}
impl UIntBeBytes {
pub fn new(bytes: [u8; size_of::<u128>()]) -> Self {
Self { bytes }
}
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub struct EncodedUInt {
be_bytes: UIntBeBytes,
first_occupied_byte: usize,
}
impl EncodedUInt {
pub fn as_bytes(&self) -> &[u8] {
&self.be_bytes.bytes[self.first_occupied_byte..]
}
}
impl AsRef<[u8]> for EncodedUInt {
fn as_ref(&self) -> &[u8] {
self.as_bytes()
}
}
pub fn encode(magnitude: impl Into<u128>) -> EncodedUInt {
let magnitude: u128 = magnitude.into();
let empty_leading_bytes: u32 = magnitude.leading_zeros() / 8;
let first_occupied_byte = empty_leading_bytes as usize;
EncodedUInt {
be_bytes: UIntBeBytes::new(magnitude.to_be_bytes()),
first_occupied_byte,
}
}
#[cfg(test)]
mod tests {
use super::*;
const WRITE_ERROR_MESSAGE: &str = "Writing a UInt to the provided sink failed.";
#[test]
fn test_write_ten_byte_uint() {
let value = u128::from_str_radix("ffffffffffffffffffff", 16).unwrap();
let mut buffer: Vec<u8> = vec![];
let encoded = super::encode(value);
buffer.write_all(encoded.as_bytes()).unwrap();
let expected_bytes = vec![0xFFu8; 10];
assert_eq!(expected_bytes.as_slice(), buffer.as_slice());
}
#[test]
fn test_write_eight_byte_uint() {
let value = 0x01_23_45_67_89_AB_CD_EF;
let mut buffer: Vec<u8> = vec![];
DecodedUInt::write_u64(&mut buffer, value).expect(WRITE_ERROR_MESSAGE);
let expected_bytes = &[0x01, 0x23, 0x45, 0x67, 0x89, 0xAB, 0xCD, 0xEF];
assert_eq!(expected_bytes, buffer.as_slice());
}
#[test]
fn test_write_five_byte_uint() {
let value = 0x01_23_45_67_89;
let mut buffer: Vec<u8> = vec![];
DecodedUInt::write_u64(&mut buffer, value).expect(WRITE_ERROR_MESSAGE);
let expected_bytes = &[0x01, 0x23, 0x45, 0x67, 0x89];
assert_eq!(expected_bytes, buffer.as_slice());
}
#[test]
fn test_write_three_byte_uint() {
let value = 0x01_23_45;
let mut buffer: Vec<u8> = vec![];
DecodedUInt::write_u64(&mut buffer, value).expect(WRITE_ERROR_MESSAGE);
let expected_bytes: &[u8] = &[0x01, 0x23, 0x45];
assert_eq!(expected_bytes, buffer.as_slice());
}
#[test]
fn test_write_uint_zero() {
let value = 0x00;
let mut buffer: Vec<u8> = vec![];
DecodedUInt::write_u64(&mut buffer, value).expect(WRITE_ERROR_MESSAGE);
let expected_bytes: &[u8] = &[];
assert_eq!(expected_bytes, buffer.as_slice());
}
}