xelf 0.5.3

A versatile Rust toolkit for self-use.
Documentation
#![allow(clippy::missing_safety_doc)]

use std::{ptr::NonNull, slice};

pub trait RawPtrOps: Sized {
    #[must_use]
    #[inline(always)]
    fn raw_ptr(&self) -> *const Self {
        self as *const _
    }

    #[must_use]
    #[inline(always)]
    fn raw_mut(&mut self) -> *mut Self {
        self as *mut _
    }

    #[must_use]
    #[inline(always)]
    unsafe fn iadd(&self, count: isize) -> &'static Self {
        &*(self as *const Self).wrapping_offset(count)
    }

    #[must_use]
    #[inline(always)]
    unsafe fn iadd_mut(&mut self, count: isize) -> &'static mut Self {
        &mut *(self as *mut Self).wrapping_offset(count)
    }

    #[must_use]
    #[inline(always)]
    unsafe fn uadd(&self, count: usize) -> &'static Self {
        &*(self as *const Self).wrapping_add(count)
    }

    #[must_use]
    #[inline(always)]
    unsafe fn uadd_mut(&mut self, count: usize) -> &'static mut Self {
        &mut *(self as *mut Self).wrapping_add(count)
    }

    #[must_use]
    #[inline(always)]
    fn idiff(&self, rhs: *const Self) -> isize {
        ((self as *const _ as isize) - (rhs as isize)) / std::mem::size_of::<Self>() as isize
    }

    #[must_use]
    #[inline(always)]
    fn udiff(&self, rhs: *const Self) -> usize {
        ((self as *const _ as usize) - (rhs as usize)) / std::mem::size_of::<Self>()
    }

    #[must_use]
    #[inline(always)]
    unsafe fn slice(&self, len: usize) -> &'static [Self] {
        slice::from_raw_parts(self, len)
    }

    #[must_use]
    #[inline(always)]
    unsafe fn slice_mut(&mut self, len: usize) -> &'static mut [Self] {
        slice::from_raw_parts_mut(self, len)
    }
}

pub trait SlicePtrOps {
    type Item: Sized;

    #[must_use]
    unsafe fn begin(&self) -> &'static Self::Item;
    #[must_use]
    unsafe fn begin_mut(&mut self) -> &'static mut Self::Item;

    #[must_use]
    unsafe fn end(&self) -> &'static Self::Item;
    #[must_use]
    unsafe fn end_mut(&mut self) -> &'static mut Self::Item;

    #[must_use]
    unsafe fn slice_unchecked_at(&self, at: usize) -> &[Self::Item];
    #[must_use]
    unsafe fn slice_unchecked_at_mut(&mut self, at: usize) -> &mut [Self::Item];

    #[must_use]
    fn slice_at(&self, at: usize) -> &[Self::Item];
    #[must_use]
    fn slice_at_mut(&mut self, at: usize) -> &mut [Self::Item];
}

impl<T: 'static + Copy + Sized> RawPtrOps for T {}

impl<T: 'static + Copy + Sized> SlicePtrOps for [T] {
    type Item = T;

    #[inline(always)]
    unsafe fn begin(&self) -> &'static Self::Item {
        &*self.as_ptr()
    }

    #[inline(always)]
    unsafe fn end(&self) -> &'static Self::Item {
        &*self.as_ptr().wrapping_add(self.len())
    }

    #[inline(always)]
    unsafe fn begin_mut(&mut self) -> &'static mut Self::Item {
        &mut *self.as_mut_ptr()
    }

    #[inline(always)]
    unsafe fn end_mut(&mut self) -> &'static mut Self::Item {
        &mut *self.as_mut_ptr().wrapping_add(self.len())
    }

    #[inline]
    unsafe fn slice_unchecked_at(&self, at: usize) -> &[Self::Item] {
        self.begin().uadd(at).slice(self.len() - at)
    }

    #[inline]
    unsafe fn slice_unchecked_at_mut(&mut self, at: usize) -> &mut [Self::Item] {
        self.begin_mut().uadd_mut(at).slice_mut(self.len() - at)
    }

    #[inline]
    fn slice_at(&self, at: usize) -> &[Self::Item] {
        unsafe {
            if at >= self.len() {
                slice::from_raw_parts(NonNull::dangling().as_ptr(), 0)
            } else {
                self.begin().uadd(at).slice(self.len() - at)
            }
        }
    }

    #[inline]
    fn slice_at_mut(&mut self, at: usize) -> &mut [Self::Item] {
        unsafe {
            if at >= self.len() {
                slice::from_raw_parts_mut(NonNull::dangling().as_ptr(), 0)
            } else {
                self.begin_mut().uadd_mut(at).slice_mut(self.len() - at)
            }
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[derive(Clone, Copy)]
    struct Foo {
        a: i32,
        b: *const i32,
        c: *mut i32,
    }

    #[test]
    fn test_raw_ptr() {
        let a = Foo {
            a: 1,
            b: std::ptr::null(),
            c: std::ptr::null_mut(),
        };
        assert_eq!(a.idiff(&a), 0);
        assert_eq!(a.a.idiff(&a.a), 0);
        assert_eq!(a.b.idiff(&a.b), 0);
        assert_eq!(a.c.idiff(&a.c), 0);
    }
}