blaze-rs 1.0.3

A Rustified OpenCL Experience
Documentation
use std::{
    alloc::{Layout, LayoutError},
    marker::PhantomData,
    mem::ManuallyDrop,
    ptr::NonNull,
};

#[repr(C)]
union PtrRepr<T: ?Sized> {
    const_ptr: *const T,
    mut_ptr: *mut T,
    components: PtrComponents,
}

#[derive(Debug, Clone, Copy)]
#[repr(C)]
struct PtrComponents {
    data_address: *const (),
    metadata: *const (),
}

pub struct ThinFn<F: ?Sized + FnClosure> {
    inner: NonNull<u8>,
    _phtm: PhantomData<F>,
}

impl<T: ?Sized + FnClosure> ThinFn<T> {
    #[allow(dead_code)]
    pub fn new<F: IntoFnClosure<T>>(f: F) -> Self
    where
        T: FnClosureNew,
    {
        let (layout, f_offset) = calculate_layout::<F>().expect("unexpected layout error");
        let Some(ptr) = NonNull::new(unsafe { std::alloc::alloc(layout) }) else { std::alloc::handle_alloc_error(layout) };

        unsafe {
            let raw = ptr.as_ptr().add(f_offset);
            raw.sub(core::mem::size_of::<*const ()>())
                .cast::<*const ()>()
                .write(f.metadata());
            raw.cast::<F>().write(f);

            return Self {
                inner: NonNull::new_unchecked(raw).cast(),
                _phtm: PhantomData,
            };
        }
    }

    #[inline]
    pub unsafe fn from_raw(ptr: *mut ()) -> Self {
        return Self {
            inner: NonNull::new_unchecked(ptr.cast()),
            _phtm: PhantomData,
        };
    }

    #[inline]
    pub fn into_raw(self) -> *mut () {
        let this = ManuallyDrop::new(self);
        return this.inner.as_ptr().cast();
    }

    #[inline]
    pub fn as_raw(&self) -> *mut () {
        return self.inner.as_ptr().cast();
    }

    #[inline]
    pub fn metadata(&self) -> *const () {
        unsafe {
            self.inner
                .as_ptr()
                .sub(core::mem::size_of::<*const ()>())
                .cast::<*const ()>()
                .read()
        }
    }

    pub fn as_ptr(&self) -> *const T::Ptr {
        unsafe {
            PtrRepr {
                components: PtrComponents {
                    data_address: self.inner.as_ptr().cast(),
                    metadata: self.metadata(),
                },
            }
            .const_ptr
        }
    }

    pub fn as_mut_ptr(&mut self) -> *mut T::Ptr {
        unsafe {
            PtrRepr {
                components: PtrComponents {
                    data_address: self.inner.as_ptr().cast(),
                    metadata: self.metadata(),
                },
            }
            .mut_ptr
        }
    }
}

impl<F: ?Sized + FnClosure> Drop for ThinFn<F> {
    #[inline]
    fn drop(&mut self) {
        unsafe {
            struct DeallocGuard(*mut u8, Layout);
            impl Drop for DeallocGuard {
                #[inline]
                fn drop(&mut self) {
                    let (layout, offset) =
                        unsafe { Layout::new::<*const ()>().extend(self.1).unwrap_unchecked() };

                    unsafe {
                        std::alloc::dealloc(self.0.sub(offset), layout);
                    }
                }
            }

            let guard = DeallocGuard(self.inner.as_ptr(), Layout::for_value(&*self.as_ptr()));
            core::ptr::drop_in_place(self.as_mut_ptr());
            drop(guard);
        }
    }
}

unsafe impl<F: ?Sized + FnClosure + Send> Send for ThinFn<F> {}
unsafe impl<F: ?Sized + FnClosure + Sync> Sync for ThinFn<F> {}

#[doc(hidden)]
pub unsafe trait FnClosure: sealed::Sealed {
    type Ptr: ?Sized;
}
#[doc(hidden)]
pub trait FnClosureNew: FnClosure {}

#[doc(hidden)]
pub unsafe trait IntoFnClosure<F: ?Sized + FnClosure> {
    unsafe fn metadata(&self) -> *const ();
}

macro_rules! impl_fn_closure {
    (
        ($($arg:ident),*): $($trait:ident),*
    ) => {
        impl<'a, $($arg,)* __T__> sealed::Sealed for dyn 'a + $($trait+)* FnOnce($($arg),*) -> __T__ {}
        impl<'a, $($arg,)* __T__> sealed::Sealed for dyn 'a + $($trait+)* Fn($($arg),*) -> __T__ {}
        impl<'a, $($arg,)* __T__> sealed::Sealed for dyn 'a + $($trait+)* FnMut($($arg),*) -> __T__ {}

        impl<'a, $($arg,)* __T__> FnClosureNew for dyn 'a + $($trait+)* Fn($($arg),*) -> __T__ {}
        impl<'a, $($arg,)* __T__> FnClosureNew for dyn 'a + $($trait+)* FnMut($($arg),*) -> __T__ {}

        unsafe impl<'a, $($arg,)* __T__> FnClosure for dyn 'a + $($trait+)* FnOnce($($arg),*) -> __T__ {
            type Ptr = dyn 'a + $($trait+)* FnMut($($arg),*) -> __T__;
        }
        unsafe impl<'a, $($arg,)* __T__> FnClosure for dyn 'a + $($trait+)* Fn($($arg),*) -> __T__ {
            type Ptr = Self;
        }
        unsafe impl<'a, $($arg,)* __T__> FnClosure for dyn 'a + $($trait+)* FnMut($($arg),*) -> __T__ {
            type Ptr = Self;
        }

        unsafe impl<'a, $($arg,)* __T__, __F__: 'a + $($trait+)* Fn($($arg),*) -> __T__> IntoFnClosure<dyn 'a + $($trait+)* Fn($($arg),*) -> __T__> for __F__ {
            unsafe fn metadata(&self) -> *const () {
                PtrRepr {
                    const_ptr: self as *const (dyn 'a + $($trait+)* Fn($($arg),*) -> __T__)
                }.components.metadata
            }
        }

        unsafe impl<'a, $($arg,)* __T__, __F__: 'a + $($trait+)* FnMut($($arg),*) -> __T__> IntoFnClosure<dyn 'a + $($trait+)* FnMut($($arg),*) -> __T__> for __F__ {
            unsafe fn metadata(&self) -> *const () {
                PtrRepr {
                    const_ptr: self as *const (dyn 'a + $($trait+)* FnMut($($arg),*) -> __T__)
                }.components.metadata
            }
        }

        unsafe impl<'a, $($arg,)* __T__, __F__: 'a + $($trait+)* FnOnce($($arg),*) -> __T__> IntoFnClosure<dyn 'a + $($trait+)* FnOnce($($arg),*) -> __T__> for __F__ {
            unsafe fn metadata(&self) -> *const () {
                PtrRepr {
                    const_ptr: self as *const (dyn 'a + $($trait+)* FnOnce($($arg),*) -> __T__)
                }.components.metadata
            }
        }

        #[allow(non_snake_case, dead_code)]
        impl<'a, $($arg,)* __T__> ThinFn<dyn 'a + $($trait+)* FnOnce($($arg),*) -> __T__> {
            pub fn new_once<__F__: 'a + $($trait+)* FnOnce($($arg),*) -> __T__>(f: __F__) -> Self
            {
                #[inline(always)]
                fn cast_ptr_to<T, F> (ptr: *mut T, _f: &F) -> *mut F {
                    ptr.cast::<F>()
                }

                let mut f = Some(f);
                let f = move |$($arg),*| unsafe {
                    (f.take().unwrap_unchecked())($($arg),*)
                };

                let metadata = unsafe {
                    PtrRepr {
                        const_ptr: &f as *const (dyn 'a + $($trait+)* FnMut($($arg),*) -> __T__)
                    }.components.metadata
                };

                let (layout, f_offset) = calculate_layout_of(&f).expect("unexpected layout error");
                let Some(ptr) = NonNull::new(unsafe { std::alloc::alloc(layout) }) else { std::alloc::handle_alloc_error(layout) };

                unsafe {
                    let raw = ptr.as_ptr().add(f_offset);
                    raw.sub(core::mem::size_of::<*const ()>())
                        .cast::<*const ()>()
                        .write(metadata);
                    cast_ptr_to(raw, &f).write(f);

                    return Self {
                        inner: NonNull::new_unchecked(raw).cast(),
                        _phtm: PhantomData,
                    };
                }
            }

            #[inline]
            pub fn call_once (mut self, ($($arg,)*): ($($arg,)*)) -> __T__ {
                (unsafe { &mut *self.as_mut_ptr() })($($arg),*)
            }
        }

        #[allow(non_snake_case, dead_code)]
        impl<'a, $($arg,)* __T__> ThinFn<dyn 'a + $($trait+)* Fn($($arg),*) -> __T__> {
            #[inline]
            pub fn call (&self, ($($arg,)*): ($($arg,)*)) -> __T__ {
                (unsafe { &*self.as_ptr() })($($arg),*)
            }
        }

        #[allow(non_snake_case, dead_code)]
        impl<'a, $($arg,)* __T__> ThinFn<dyn 'a + $($trait+)* FnMut($($arg),*) -> __T__> {
            #[inline]
            pub fn call_mut (&mut self, ($($arg,)*): ($($arg,)*)) -> __T__ {
                (unsafe { &mut *self.as_mut_ptr() })($($arg),*)
            }
        }
    };

    (
        $(
            ($($arg:ident),*)
        ),+
    ) => {
        $(
            impl_fn_closure! {
                ($($arg),*):
            }

            impl_fn_closure! {
                ($($arg),*): Send
            }

            impl_fn_closure! {
                ($($arg),*): Sync
            }

            impl_fn_closure! {
                ($($arg),*): Send, Sync
            }
        )+
    };
}

impl_fn_closure! {
    (),
    (A),
    (A, B),
    (A, B, C),
    (A, B, C, D),
    (A, B, C, D, E),
    (A, B, C, D, E, F),
    (A, B, C, D, E, F, G),
    (A, B, C, D, E, F, G, H),
    (A, B, C, D, E, F, G, H, I),
    (A, B, C, D, E, F, G, H, I, J),
    (A, B, C, D, E, F, G, H, I, J, K),
    (A, B, C, D, E, F, G, H, I, J, K, L),
    (A, B, C, D, E, F, G, H, I, J, K, L, M),
    (A, B, C, D, E, F, G, H, I, J, K, L, M, N),
    (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O),
    (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P),
    (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q),
    (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R),
    (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S),
    (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T),
    (A, B, C, D, E, F, G, H, I, J, K, L, M, N, O, P, Q, R, S, T, U)
}

#[allow(dead_code)]
fn calculate_layout<F>() -> Result<(Layout, usize), LayoutError> {
    let layout = Layout::new::<*const ()>(); // metadata
    let (layout, f) = layout.extend(Layout::new::<F>())?;
    return Ok((layout.pad_to_align(), f));
}

#[allow(dead_code)]
fn calculate_layout_of<F: ?Sized>(f: &F) -> Result<(Layout, usize), LayoutError> {
    let layout = Layout::new::<*const ()>(); // metadata
    let (layout, f) = layout.extend(Layout::for_value(f))?;
    return Ok((layout.pad_to_align(), f));
}

mod sealed {
    pub trait Sealed {}
}