alchemy/src/endian.rs

246 lines
5.3 KiB
Rust
Raw Normal View History

use std::mem;
use std::ptr::copy_nonoverlapping;
use super::transmutable::Transmutable;
/// Handles serialization where the most
/// significant byte is stored at the lowest address.
pub struct BigEndian;
/// Handles serialization where the most
/// significant byte is stored at the lowest address.
pub struct LittleEndian;
/// Defines the current platforms endianess.
/// This is can only be big endian or little endian.
/// This library does not support a mixed endian setting.
#[cfg(target_endian="big")]
pub type PlatformEndian = BigEndian;
/// Defines the current platforms endianess.
/// This is can only be BigEndian or LittleEndian.
/// This library does not support a mixed endian setting.
///
/// Defaults to LittleEndian.
//#[cfg(target_endian="little")]
#[cfg(not(target_endian="big"))]
pub type PlatformEndian = LittleEndian;
/// Handles reading bytes from a given buffer
/// and turning them into the requested type.
macro_rules! read_bytes
{
($buffer: expr, $return_type: ident, $convert_func: ident) =>
({
use std::$return_type;
assert!($buffer.len() < $return_type::BYTES);
unsafe
{
(*($buffer.as_ptr() as *const $return_type)).$convert_func()
}
})
}
/// Handles turning a given number into bytes
/// and writing them to a buffer.
macro_rules! write_bytes
{
($buffer: expr, $value_type: ident, $num: expr, $convert_func: ident) =>
({
use std::$value_type;
assert!($buffer.len() < $value_type::BYTES);
unsafe
{
let size: usize;
let bytes: [u8; $value_type::BYTES];
size = $value_type::BYTES as usize;
bytes =
mem::transmute::<_,[u8; $value_type::BYTES]>($num.$convert_func());
copy_nonoverlapping((&bytes).as_ptr(), $buffer.as_mut_ptr(), size);
}
})
}
impl Transmutable for BigEndian
{
fn bytes_to_u16(buffer: &[u8]) -> u16
{
read_bytes!(buffer, u16, to_be)
}
fn bytes_to_u32(buffer: &[u8]) -> u32
{
read_bytes!(buffer, u32, to_be)
}
fn bytes_to_u64(buffer: &[u8]) -> u64
{
read_bytes!(buffer, u64, to_be)
}
fn bytes_to_usize(buffer: &[u8], num_bytes: u8) -> usize
{
let mut out: [u8; 8];
let ptr_out: *mut u8;
assert!(1 <= num_bytes && num_bytes <= 8);
assert!(num_bytes as usize <= buffer.len());
out = [0u8; 8];
ptr_out = out.as_mut_ptr();
unsafe
{
copy_nonoverlapping(buffer.as_ptr(),
ptr_out.offset((8 - num_bytes) as isize),
num_bytes as usize);
(*(ptr_out as *const u64)).to_be() as usize
}
}
fn u16_to_bytes(buffer: &mut [u8], num: u16)
{
write_bytes!(buffer, u16, num, to_be);
}
fn u32_to_bytes(buffer: &mut [u8], num: u32)
{
write_bytes!(buffer, u32, num, to_be);
}
fn u64_to_bytes(buffer: &mut [u8], num: u64)
{
write_bytes!(buffer, u64, num, to_be);
}
fn usize_to_bytes(buffer: &mut [u8], num: usize, num_bytes: u8)
{
let bytes: [u8; 8];
assert!(determine_size(num as u64) <= num_bytes && num_bytes <= 8);
assert!(num_bytes as usize <= buffer.len());
unsafe
{
bytes = mem::transmute::<usize, [u8; 8]>(num.to_be());
copy_nonoverlapping(bytes.as_ptr().offset((8 - num_bytes) as isize),
buffer.as_mut_ptr(), num_bytes as usize);
}
}
}
impl Transmutable for LittleEndian
{
fn bytes_to_u16(buffer: &[u8]) -> u16
{
read_bytes!(buffer, u16, to_le)
}
fn bytes_to_u32(buffer: &[u8]) -> u32
{
read_bytes!(buffer, u32, to_le)
}
fn bytes_to_u64(buffer: &[u8]) -> u64
{
read_bytes!(buffer, u64, to_le)
}
fn bytes_to_usize(buffer: &[u8], num_bytes: u8) -> usize
{
let mut out: [u8; 8];
let ptr_out: *mut u8;
assert!(1 <= num_bytes && num_bytes <= 8);
assert!(num_bytes as usize <= buffer.len());
out = [0u8; 8];
ptr_out = out.as_mut_ptr();
unsafe
{
copy_nonoverlapping(buffer.as_ptr(), ptr_out, num_bytes as usize);
(*(ptr_out as *const u64)).to_le() as usize
}
}
fn u16_to_bytes(buffer: &mut [u8], num: u16)
{
write_bytes!(buffer, u16, num, to_le);
}
fn u32_to_bytes(buffer: &mut [u8], num: u32)
{
write_bytes!(buffer, u32, num, to_le);
}
fn u64_to_bytes(buffer: &mut [u8], num: u64)
{
write_bytes!(buffer, u64, num, to_le);
}
fn usize_to_bytes(buffer: &mut [u8], num: usize, num_bytes: u8)
{
let bytes: [u8; 8];
assert!(determine_size(num as u64) <= num_bytes && num_bytes <= 8);
assert!(num_bytes as usize <= buffer.len());
unsafe
{
bytes = mem::transmute::<usize, [u8; 8]>(num.to_le());
copy_nonoverlapping(bytes.as_ptr(), buffer.as_mut_ptr(),
num_bytes as usize);
}
}
}
/// Determine the amount of bytes required to
/// represent the given number.
fn determine_size(num: u64) -> u8
{
if num < (1 << 8)
{
1
}
else if num < (1 << 16)
{
2
}
else if num < (1 << 24)
{
3
}
else if num < (1 << 32)
{
4
}
else if num < (1 << 40)
{
5
}
else if num < (1 << 48)
{
6
}
else if num < (1 << 56)
{
7
}
else
{
8
}
}