Numbers can be converted to and from bytes in both BigEndian and LittleEndian styles. This does not yet take care of the other mathematical structures provided by Sigil. Also, no tests of these capabilities have been written yet.
246 lines
5.3 KiB
Rust
246 lines
5.3 KiB
Rust
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!($return_type::BYTES <= $buffer.len());
|
|
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!($value_type::BYTES <= $buffer.len());
|
|
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
|
|
}
|
|
}
|