gemstone 0.1.0

collection of utilities
Documentation
use core::{
    mem::{size_of, MaybeUninit},
    ptr,
};

pub const fn zero<T>() -> T {
    unsafe { MaybeUninit::zeroed().assume_init() }
}

pub const fn ones<T>() -> T {
    unsafe {
        let mut x = MaybeUninit::uninit();
        ptr::write_bytes(x.as_mut_ptr(), 0xFF, 1);
        x.assume_init()
    }
}

pub const fn make_zero<T>(v: &mut T) {
    unsafe { ptr::write_bytes(v, 0, 1) }
}

pub const fn read<D, T: Copy>(data: *const D, offset: usize) -> T {
    unsafe { *data.cast::<u8>().add(offset).cast() }
}

pub const fn write<D, T: Copy>(data: *mut D, offset: usize, val: T) {
    unsafe { data.cast::<u8>().add(offset).cast::<T>().write(val) }
}

pub trait MemValue: Sized + Copy {
    fn from_le_bytes(bytes: [u8; size_of::<Self>()]) -> Self;
    fn from_be_bytes(bytes: [u8; size_of::<Self>()]) -> Self;
    fn from_ne_bytes(bytes: [u8; size_of::<Self>()]) -> Self;

    fn to_le_bytes(self) -> [u8; size_of::<Self>()];
    fn to_be_bytes(self) -> [u8; size_of::<Self>()];
    fn to_ne_bytes(self) -> [u8; size_of::<Self>()];

    /// # Safety
    /// The given pointer must be [valid] for `Self` reads and point to a properly initialized value
    /// of `Self`.
    ///
    /// [valid]: https://doc.rust-lang.org/stable/std/ptr/index.html#safety
    unsafe fn read_le(ptr: *const Self) -> Self;
    /// # Safety
    /// The given pointer must be aligned to a `Self` boundary, be [valid] for `Self` reads and
    /// point to a properly initialized value of `Self`.
    ///
    /// [valid]: https://doc.rust-lang.org/stable/std/ptr/index.html#safety
    unsafe fn read_le_aligned(ptr: *const Self) -> Self;
    /// # Safety
    /// The given pointer must be [valid] for `Self` reads and point to a properly initialized value
    /// of `Self`.
    ///
    /// [valid]: https://doc.rust-lang.org/stable/std/ptr/index.html#safety
    unsafe fn read_be(ptr: *const Self) -> Self;
    /// # Safety
    /// The given pointer must be aligned to a `Self` boundary, be [valid] for `Self` reads and
    /// point to a properly initialized value of `Self`.
    ///
    /// [valid]: https://doc.rust-lang.org/stable/std/ptr/index.html#safety
    unsafe fn read_be_aligned(ptr: *const Self) -> Self;
    /// # Safety
    /// The given pointer must be [valid] for `Self` reads and point to a properly initialized value
    /// of `Self`.
    ///
    /// [valid]: https://doc.rust-lang.org/stable/std/ptr/index.html#safety
    unsafe fn read_ne(ptr: *const Self) -> Self;
    /// # Safety
    /// The given pointer must be aligned to a `Self` boundary, be [valid] for `Self` reads and
    /// point to a properly initialized value of `Self`.
    ///
    /// [valid]: https://doc.rust-lang.org/stable/std/ptr/index.html#safety
    unsafe fn read_ne_aligned(ptr: *const Self) -> Self;

    /// # Safety
    /// The given pointer must be [valid] for `Self` writes.
    ///
    /// [valid]: https://doc.rust-lang.org/stable/std/ptr/index.html#safety
    unsafe fn write_le(self, ptr: *mut Self);
    /// # Safety
    /// The given pointer must be aligned to a `Self` boundary and be [valid] for `Self` writes.
    ///
    /// [valid]: https://doc.rust-lang.org/stable/std/ptr/index.html#safety
    unsafe fn write_le_aligned(self, ptr: *mut Self);
    /// # Safety
    /// The given pointer must be [valid] for `Self` writes.
    ///
    /// [valid]: https://doc.rust-lang.org/stable/std/ptr/index.html#safety
    unsafe fn write_be(self, ptr: *mut Self);
    /// # Safety
    /// The given pointer must be aligned to a `Self` boundary and be [valid] for `Self` writes.
    ///
    /// [valid]: https://doc.rust-lang.org/stable/std/ptr/index.html#safety
    unsafe fn write_be_aligned(self, ptr: *mut Self);
    /// # Safety
    /// The given pointer must be [valid] for `Self` writes.
    ///
    /// [valid]: https://doc.rust-lang.org/stable/std/ptr/index.html#safety
    unsafe fn write_ne(self, ptr: *mut Self);
    /// # Safety
    /// The given pointer must be aligned to a `Self` boundary and be [valid] for `Self` writes.
    ///
    /// [valid]: https://doc.rust-lang.org/stable/std/ptr/index.html#safety
    unsafe fn write_ne_aligned(self, ptr: *mut Self);
}

macro_rules! impl_mem_value {
	($($ty: ty),*) => {
		$(
			#[allow(unused_mut)]
			impl MemValue for $ty {
				#[inline]
				fn from_le_bytes(bytes: [u8; size_of::<Self>()]) -> Self {
					<$ty>::from_le_bytes(bytes)
				}

				#[inline]
				fn from_be_bytes(bytes: [u8; size_of::<Self>()]) -> Self {
					<$ty>::from_be_bytes(bytes)
				}

				#[inline]
				fn from_ne_bytes(bytes: [u8; size_of::<Self>()]) -> Self {
					<$ty>::from_ne_bytes(bytes)
				}

				#[inline]
				fn to_le_bytes(self) -> [u8; size_of::<Self>()] {
					<$ty>::to_le_bytes(self)
				}

				#[inline]
				fn to_be_bytes(self) -> [u8; size_of::<Self>()] {
					<$ty>::to_be_bytes(self)
				}

				#[inline]
				fn to_ne_bytes(self) -> [u8; size_of::<Self>()] {
					<$ty>::to_ne_bytes(self)
				}

				#[inline]
				unsafe fn read_le(ptr: *const Self) -> Self {
					let mut res = ptr.read_unaligned();
					#[cfg(not(target_endian = "little"))]
					{
						res = res.swap_bytes();
					}
					res
				}

				#[inline]
				unsafe fn read_le_aligned(ptr: *const Self) -> Self {
					let mut res = ptr.read();
					#[cfg(not(target_endian = "little"))]
					{
						res = res.swap_bytes();
					}
					res
				}

				#[inline]
				unsafe fn read_be(ptr: *const Self) -> Self {
					let mut res = ptr.read_unaligned();
					#[cfg(not(target_endian = "big"))]
					{
						res = res.swap_bytes();
					}
					res
				}

				#[inline]
				unsafe fn read_be_aligned(ptr: *const Self) -> Self {
					let mut res = ptr.read();
					#[cfg(not(target_endian = "big"))]
					{
						res = res.swap_bytes();
					}
					res
				}

				#[inline]
				unsafe fn read_ne(ptr: *const Self) -> Self {
					ptr.read_unaligned()
				}

				#[inline]
				unsafe fn read_ne_aligned(ptr: *const Self) -> Self {
					ptr.read()
				}

				#[inline]
				unsafe fn write_le(mut self, ptr: *mut Self) {
					#[cfg(not(target_endian = "little"))]
					{
						self = self.swap_bytes();
					}
					ptr.write_unaligned(self);
				}

				#[inline]
				unsafe fn write_le_aligned(mut self, ptr: *mut Self) {
					#[cfg(not(target_endian = "little"))]
					{
						self = self.swap_bytes();
					}
					ptr.write(self);
				}

				#[inline]
				unsafe fn write_be(mut self, ptr: *mut Self) {
					#[cfg(not(target_endian = "big"))]
					{
						self = self.swap_bytes();
					}
					ptr.write_unaligned(self);
				}

				#[inline]
				unsafe fn write_be_aligned(mut self, ptr: *mut Self) {
					#[cfg(not(target_endian = "big"))]
					{
						self = self.swap_bytes();
					}
					ptr.write(self);
				}

				#[inline]
				unsafe fn write_ne(self, ptr: *mut Self) {
					ptr.write_unaligned(self);
				}

				#[inline]
				unsafe fn write_ne_aligned(self, ptr: *mut Self) {
					ptr.write(self);
				}
			}
		)*
	};
}

impl_mem_value!(u8, i8, u16, i16, u32, i32, u64, i64, u128, i128, usize, isize);