#![allow(unsafe_code)]
use core::cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd};
use core::marker::PhantomData;
use core::{fmt, hash, mem, num, ptr, slice};
use crate::buf::buf;
pub struct Texel<P: ?Sized>(PhantomData<P>);
pub struct IsTransparentWrapper<P, O>(PhantomData<(P, O)>);
pub trait AsTexel {
fn texel() -> Texel<Self>;
}
pub(crate) const MAX_ALIGN: usize = 16;
#[derive(Clone, Copy)]
#[repr(align(16))]
#[repr(C)]
pub struct MaxAligned(pub(crate) [u8; 16]);
unsafe impl bytemuck::Zeroable for MaxAligned {}
unsafe impl bytemuck::Pod for MaxAligned {}
pub(crate) mod constants {
use super::{AsTexel, MaxAligned, Texel};
macro_rules! constant_texel {
($(($name:ident, $type:ty)),*) => {
$(pub const $name: Texel<$type> = Texel(core::marker::PhantomData) ;
impl AsTexel for $type {
fn texel() -> Texel<Self> {
$name
}
}
)*
}
}
constant_texel!(
(I8, i8),
(U8, u8),
(I16, i16),
(U16, u16),
(I32, i32),
(U32, u32),
(F32, f32),
(I64, i64),
(U64, u64),
(F64, f64),
(MAX, MaxAligned)
);
impl<T: AsTexel> AsTexel for [T; 1] {
fn texel() -> Texel<[T; 1]> {
T::texel().array::<1>()
}
}
impl<T: AsTexel> AsTexel for [T; 2] {
fn texel() -> Texel<[T; 2]> {
T::texel().array::<2>()
}
}
impl<T: AsTexel> AsTexel for [T; 3] {
fn texel() -> Texel<[T; 3]> {
T::texel().array::<3>()
}
}
impl<T: AsTexel> AsTexel for [T; 4] {
fn texel() -> Texel<[T; 4]> {
T::texel().array::<4>()
}
}
impl<T: AsTexel> AsTexel for ::core::num::Wrapping<T> {
fn texel() -> Texel<::core::num::Wrapping<T>> {
T::texel().num_wrapping()
}
}
}
impl<P: bytemuck::Pod> Texel<P> {
pub fn for_type() -> Option<Self> {
if mem::align_of::<P>() <= MAX_ALIGN && mem::size_of::<P>() > 0 && !mem::needs_drop::<P>() {
Some(Texel(PhantomData))
} else {
None
}
}
}
impl<P, O: bytemuck::TransparentWrapper<P>> IsTransparentWrapper<P, O> {
pub const CONST: Self = IsTransparentWrapper(PhantomData);
}
impl buf {
pub const ALIGNMENT: usize = MAX_ALIGN;
pub fn from_bytes(bytes: &[u8]) -> Option<&Self> {
if bytes.as_ptr() as usize % Self::ALIGNMENT == 0 {
Some(unsafe { &*(bytes as *const [u8] as *const Self) })
} else {
None
}
}
pub fn from_bytes_mut(bytes: &mut [u8]) -> Option<&mut Self> {
if bytes.as_ptr() as usize % Self::ALIGNMENT == 0 {
Some(unsafe { &mut *(bytes as *mut [u8] as *mut Self) })
} else {
None
}
}
}
impl<P> Texel<P> {
pub const unsafe fn new_unchecked() -> Self {
Texel(PhantomData)
}
pub const fn align(self) -> usize {
mem::align_of::<P>()
}
pub const fn size(self) -> usize {
mem::size_of::<P>()
}
pub const fn size_nz(self) -> core::num::NonZeroUsize {
match core::num::NonZeroUsize::new(self.size()) {
None => panic!(""),
Some(num) => num,
}
}
pub const fn array<const N: usize>(self) -> Texel<[P; N]> {
if N == 0 {
panic!()
}
unsafe { Texel::new_unchecked() }
}
pub const fn transparent_wrap<O>(self, _: IsTransparentWrapper<P, O>) -> Texel<O> {
unsafe { Texel::new_unchecked() }
}
pub const fn transparent_unwrap<O>(self, _: IsTransparentWrapper<O, P>) -> Texel<O> {
unsafe { Texel::new_unchecked() }
}
pub const fn num_wrapping(self) -> Texel<num::Wrapping<P>> {
unsafe { Texel::new_unchecked() }
}
}
impl<T, const N: usize> Texel<[T; N]> {
pub const fn array_element(self) -> Texel<T> {
unsafe { Texel::new_unchecked() }
}
}
impl<P> Texel<P> {
pub fn copy_val(self, val: &P) -> P {
unsafe { ptr::read(val) }
}
pub fn to_slice<'buf>(self, buffer: &'buf [MaxAligned]) -> &'buf [P] {
self.cast_buf(buf::new(buffer))
}
pub fn to_mut_slice<'buf>(self, buffer: &'buf mut [MaxAligned]) -> &'buf mut [P] {
self.cast_mut_buf(buf::new_mut(buffer))
}
pub fn try_to_slice<'buf>(self, bytes: &'buf [u8]) -> Option<&'buf [P]> {
if bytes.as_ptr() as usize % mem::align_of::<P>() == 0 {
let len = bytes.len() / mem::size_of::<P>();
Some(unsafe { &*ptr::slice_from_raw_parts(bytes.as_ptr() as *const P, len) })
} else {
None
}
}
pub fn try_to_slice_mut<'buf>(self, bytes: &'buf mut [u8]) -> Option<&'buf [P]> {
if let Some(slice) = self.try_to_slice(bytes) {
let len = slice.len();
Some(unsafe { &*ptr::slice_from_raw_parts_mut(bytes.as_ptr() as *mut P, len) })
} else {
None
}
}
pub fn to_bytes<'buf>(self, texel: &'buf [P]) -> &'buf [u8] {
self.cast_bytes(texel)
}
pub fn to_mut_bytes<'buf>(self, texel: &'buf mut [P]) -> &'buf mut [u8] {
self.cast_mut_bytes(texel)
}
pub(crate) fn cast_buf<'buf>(self, buffer: &'buf buf) -> &'buf [P] {
debug_assert_eq!(buffer.as_ptr() as usize % mem::align_of::<MaxAligned>(), 0);
debug_assert_eq!(buffer.as_ptr() as usize % mem::align_of::<P>(), 0);
unsafe {
slice::from_raw_parts(
buffer.as_ptr() as *const P,
buffer.len() / self.size_nz().get(),
)
}
}
pub(crate) fn cast_mut_buf<'buf>(self, buffer: &'buf mut buf) -> &'buf mut [P] {
debug_assert_eq!(buffer.as_ptr() as usize % mem::align_of::<MaxAligned>(), 0);
debug_assert_eq!(buffer.as_ptr() as usize % mem::align_of::<P>(), 0);
unsafe {
slice::from_raw_parts_mut(
buffer.as_mut_ptr() as *mut P,
buffer.len() / self.size_nz().get(),
)
}
}
pub(crate) fn cast_bytes<'buf>(self, texel: &'buf [P]) -> &'buf [u8] {
unsafe { slice::from_raw_parts(texel.as_ptr() as *const u8, mem::size_of_val(texel)) }
}
pub(crate) fn cast_mut_bytes<'buf>(self, texel: &'buf mut [P]) -> &'buf mut [u8] {
unsafe { slice::from_raw_parts_mut(texel.as_ptr() as *mut u8, mem::size_of_val(texel)) }
}
}
impl<P> Clone for Texel<P> {
fn clone(&self) -> Self {
Texel(PhantomData)
}
}
impl<P> PartialEq for Texel<P> {
fn eq(&self, _: &Self) -> bool {
true
}
}
impl<P> Eq for Texel<P> {}
impl<P> PartialOrd for Texel<P> {
fn partial_cmp(&self, _: &Self) -> Option<Ordering> {
Some(Ordering::Equal)
}
}
impl<P> Ord for Texel<P> {
fn cmp(&self, _: &Self) -> Ordering {
Ordering::Equal
}
}
impl<P> Copy for Texel<P> {}
impl<P> fmt::Debug for Texel<P> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_struct("Texel")
.field("size", &self.size())
.field("align", &self.align())
.finish()
}
}
impl<P> hash::Hash for Texel<P> {
fn hash<H: hash::Hasher>(&self, _: &mut H) {}
}