#[inline(always)]
pub const fn is_little_endian() -> bool {
cfg!(target_endian = "little")
}
#[inline(always)]
pub const fn MEM_isLittleEndian() -> u32 {
if is_little_endian() {
1
} else {
0
}
}
#[inline(always)]
pub const fn MEM_64bits() -> u32 {
(core::mem::size_of::<usize>() == 8) as u32
}
#[inline(always)]
pub const fn MEM_32bits() -> u32 {
(core::mem::size_of::<usize>() == 4) as u32
}
#[inline(always)]
pub fn MEM_read16(ptr: &[u8]) -> u16 {
u16::from_ne_bytes(ptr[..2].try_into().unwrap())
}
#[inline(always)]
pub fn MEM_read32(ptr: &[u8]) -> u32 {
u32::from_ne_bytes(ptr[..4].try_into().unwrap())
}
#[inline(always)]
pub fn MEM_read64(ptr: &[u8]) -> u64 {
u64::from_ne_bytes(ptr[..8].try_into().unwrap())
}
#[inline(always)]
pub fn MEM_readST(ptr: &[u8]) -> usize {
if core::mem::size_of::<usize>() == 4 {
MEM_read32(ptr) as usize
} else {
MEM_read64(ptr) as usize
}
}
#[inline(always)]
pub fn MEM_write16(dst: &mut [u8], value: u16) {
let b = value.to_ne_bytes();
dst[..2].copy_from_slice(&b);
}
#[inline(always)]
pub fn MEM_write32(dst: &mut [u8], value: u32) {
let b = value.to_ne_bytes();
dst[..4].copy_from_slice(&b);
}
#[inline(always)]
pub fn MEM_write64(dst: &mut [u8], value: u64) {
let b = value.to_ne_bytes();
dst[..8].copy_from_slice(&b);
}
#[inline(always)]
pub fn MEM_readLE16(ptr: &[u8]) -> u16 {
if MEM_isLittleEndian() != 0 {
MEM_read16(ptr)
} else {
(ptr[0] as u16) | ((ptr[1] as u16) << 8)
}
}
#[inline(always)]
pub fn MEM_readLE24(ptr: &[u8]) -> u32 {
MEM_readLE16(ptr) as u32 | ((ptr[2] as u32) << 16)
}
#[inline(always)]
pub fn MEM_readLE32(ptr: &[u8]) -> u32 {
if MEM_isLittleEndian() != 0 {
MEM_read32(ptr)
} else {
MEM_swap32(MEM_read32(ptr))
}
}
#[inline(always)]
pub fn MEM_readLE64(ptr: &[u8]) -> u64 {
if MEM_isLittleEndian() != 0 {
MEM_read64(ptr)
} else {
MEM_swap64(MEM_read64(ptr))
}
}
#[inline(always)]
pub fn MEM_readLEST(ptr: &[u8]) -> usize {
if core::mem::size_of::<usize>() == 4 {
MEM_readLE32(ptr) as usize
} else {
MEM_readLE64(ptr) as usize
}
}
#[inline(always)]
pub fn MEM_writeLE16(dst: &mut [u8], value: u16) {
if MEM_isLittleEndian() != 0 {
MEM_write16(dst, value);
} else {
dst[0] = value as u8;
dst[1] = (value >> 8) as u8;
}
}
#[inline(always)]
pub fn MEM_writeLE24(dst: &mut [u8], value: u32) {
MEM_writeLE16(dst, value as u16);
dst[2] = (value >> 16) as u8;
}
#[inline(always)]
pub fn MEM_writeLE32(dst: &mut [u8], value: u32) {
if MEM_isLittleEndian() != 0 {
MEM_write32(dst, value);
} else {
MEM_write32(dst, MEM_swap32(value));
}
}
#[inline(always)]
pub fn MEM_writeLE64(dst: &mut [u8], value: u64) {
if MEM_isLittleEndian() != 0 {
MEM_write64(dst, value);
} else {
MEM_write64(dst, MEM_swap64(value));
}
}
#[inline(always)]
pub fn MEM_writeLEST(dst: &mut [u8], value: usize) {
if core::mem::size_of::<usize>() == 4 {
MEM_writeLE32(dst, value as u32);
} else {
MEM_writeLE64(dst, value as u64);
}
}
#[inline(always)]
pub fn MEM_readBE32(ptr: &[u8]) -> u32 {
if MEM_isLittleEndian() != 0 {
MEM_swap32(MEM_read32(ptr))
} else {
MEM_read32(ptr)
}
}
#[inline(always)]
pub fn MEM_readBE64(ptr: &[u8]) -> u64 {
if MEM_isLittleEndian() != 0 {
MEM_swap64(MEM_read64(ptr))
} else {
MEM_read64(ptr)
}
}
#[inline(always)]
pub fn MEM_readBEST(ptr: &[u8]) -> usize {
if core::mem::size_of::<usize>() == 4 {
MEM_readBE32(ptr) as usize
} else {
MEM_readBE64(ptr) as usize
}
}
#[inline(always)]
pub fn MEM_writeBE32(dst: &mut [u8], value: u32) {
if MEM_isLittleEndian() != 0 {
MEM_write32(dst, MEM_swap32(value));
} else {
MEM_write32(dst, value);
}
}
#[inline(always)]
pub fn MEM_writeBE64(dst: &mut [u8], value: u64) {
if MEM_isLittleEndian() != 0 {
MEM_write64(dst, MEM_swap64(value));
} else {
MEM_write64(dst, value);
}
}
#[inline(always)]
pub fn MEM_writeBEST(dst: &mut [u8], value: usize) {
if core::mem::size_of::<usize>() == 4 {
MEM_writeBE32(dst, value as u32);
} else {
MEM_writeBE64(dst, value as u64);
}
}
#[inline(always)]
pub const fn MEM_swap32(x: u32) -> u32 {
x.swap_bytes()
}
#[inline(always)]
pub const fn MEM_swap64(x: u64) -> u64 {
x.swap_bytes()
}
#[inline(always)]
pub const fn MEM_swapST(x: usize) -> usize {
if core::mem::size_of::<usize>() == 4 {
MEM_swap32(x as u32) as usize
} else {
MEM_swap64(x as u64) as usize
}
}
#[inline(always)]
pub const fn MEM_check() {
assert!(core::mem::size_of::<usize>() == 4 || core::mem::size_of::<usize>() == 8);
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn le_roundtrip_16() {
let mut buf = [0u8; 2];
MEM_writeLE16(&mut buf, 0x1234);
assert_eq!(buf, [0x34, 0x12]);
assert_eq!(MEM_readLE16(&buf), 0x1234);
}
#[test]
fn le_roundtrip_24() {
let mut buf = [0u8; 3];
MEM_writeLE24(&mut buf, 0x123456);
assert_eq!(buf, [0x56, 0x34, 0x12]);
assert_eq!(MEM_readLE24(&buf), 0x123456);
}
#[test]
fn le_roundtrip_32() {
let mut buf = [0u8; 4];
MEM_writeLE32(&mut buf, 0xdeadbeef);
assert_eq!(buf, [0xef, 0xbe, 0xad, 0xde]);
assert_eq!(MEM_readLE32(&buf), 0xdeadbeef);
}
#[test]
fn le_roundtrip_64() {
let mut buf = [0u8; 8];
MEM_writeLE64(&mut buf, 0x0123456789abcdef);
assert_eq!(buf, [0xef, 0xcd, 0xab, 0x89, 0x67, 0x45, 0x23, 0x01]);
assert_eq!(MEM_readLE64(&buf), 0x0123456789abcdef);
}
#[test]
fn be_roundtrip_32() {
let mut buf = [0u8; 4];
MEM_writeBE32(&mut buf, 0xdeadbeef);
assert_eq!(buf, [0xde, 0xad, 0xbe, 0xef]);
assert_eq!(MEM_readBE32(&buf), 0xdeadbeef);
}
#[test]
fn is_le_is_const() {
let b = MEM_isLittleEndian();
assert!(b == 0 || b == 1);
}
#[test]
fn mem_check_accepts_supported_pointer_width() {
MEM_check();
assert!(MEM_32bits() != 0 || MEM_64bits() != 0);
}
#[test]
fn best_roundtrip_matches_size_of_usize() {
let value: usize = 0x1234_5678;
let mut buf = vec![0u8; 8];
MEM_writeBEST(&mut buf, value);
assert_eq!(MEM_readBEST(&buf), value);
let mut explicit = vec![0u8; 8];
if core::mem::size_of::<usize>() == 8 {
MEM_writeBE64(&mut explicit, value as u64);
} else {
MEM_writeBE32(&mut explicit[..4], value as u32);
}
let w = core::mem::size_of::<usize>();
assert_eq!(&buf[..w], &explicit[..w]);
}
#[test]
fn be_roundtrip_64() {
let mut buf = [0u8; 8];
MEM_writeBE64(&mut buf, 0x0123_4567_89ab_cdef);
assert_eq!(buf, [0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef]);
assert_eq!(MEM_readBE64(&buf), 0x0123_4567_89ab_cdef);
}
#[test]
fn native_roundtrips_match_target_endianness() {
let mut buf = [0u8; 8];
MEM_write16(&mut buf[..2], 0x1234);
assert_eq!(&buf[..2], &0x1234u16.to_ne_bytes());
assert_eq!(MEM_read16(&buf[..2]), 0x1234);
MEM_write32(&mut buf[..4], 0x89ab_cdef);
assert_eq!(&buf[..4], &0x89ab_cdefu32.to_ne_bytes());
assert_eq!(MEM_read32(&buf[..4]), 0x89ab_cdef);
MEM_write64(&mut buf, 0x0123_4567_89ab_cdef);
assert_eq!(buf, 0x0123_4567_89ab_cdefu64.to_ne_bytes());
assert_eq!(MEM_read64(&buf), 0x0123_4567_89ab_cdef);
}
#[test]
fn swap_helpers_match_intrinsic_byte_swaps() {
assert_eq!(MEM_swap32(0x0123_4567), 0x6745_2301);
assert_eq!(MEM_swap64(0x0123_4567_89ab_cdef), 0xefcd_ab89_6745_2301);
let value = 0x0123_4567usize;
if core::mem::size_of::<usize>() == 4 {
assert_eq!(MEM_swapST(value), MEM_swap32(value as u32) as usize);
} else {
assert_eq!(MEM_swapST(value), MEM_swap64(value as u64) as usize);
}
}
#[test]
fn st_roundtrips_match_size_of_usize() {
let size = core::mem::size_of::<usize>();
let mut buf = vec![0u8; 8];
let value_st: usize = 0xDEAD_BEEF;
if size == 8 {
MEM_writeLE64(&mut buf, value_st as u64);
} else {
MEM_writeLE32(&mut buf[..4], value_st as u32);
}
assert_eq!(MEM_readLEST(&buf), value_st);
if MEM_isLittleEndian() == 1 {
assert_eq!(MEM_readST(&buf), value_st);
}
let mut buf2 = vec![0u8; 8];
MEM_writeLEST(&mut buf2, value_st);
assert_eq!(MEM_readLEST(&buf2), value_st);
assert_eq!(&buf2[..size], &buf[..size]);
}
}