unsafe_fn 0.1.2

macro to mark a function as unsafe without its body being unsafe
Documentation
#![deny(unused_unsafe)]

use unsafe_fn::{safe_body, unsafe_fn};

#[derive(Default, Clone)]
struct SomeStruct {
    i: u32,
    s: String,
}

#[unsafe_fn]
fn hello(x: u32, foo: String) -> u32 {
    let y: u32 = unsafe { std::mem::zeroed() };
    y + x + foo.len() as u32
}

#[unsafe_fn]
fn plus_one(mut val: u32, _x: String) -> u32 {
    let y: u32 = unsafe { std::mem::zeroed() };
    val += 1;
    y + val
}

#[unsafe_fn]
fn take_struct(
    SomeStruct { mut i, s }: SomeStruct,
    foo @ SomeStruct { .. }: &mut SomeStruct,
) -> SomeStruct {
    let y: u32 = unsafe { std::mem::zeroed() };
    foo.i += 1;
    i += foo.i;
    SomeStruct {
        i: i + y,
        s: s + &foo.s,
    }
}

impl SomeStruct {
    #[unsafe_fn]
    fn i_plus(&self, plus: u32) -> u32 {
        let y: u32 = unsafe { std::mem::zeroed() };
        self.i + plus + y
    }

    #[unsafe_fn]
    fn i_plus_box(self: Box<Self>, plus: u32) -> u32 {
        unsafe { self.i_plus(plus) }
    }

    #[unsafe_fn]
    fn with_generic<'a, 'b, T: Clone>(&'a self, r: &'b T, _: u32, _: u32) -> (&'b T, T, &'a str)
    where
        (T, Self): Default,
    {
        let _: u32 = unsafe { std::mem::zeroed() };
        (r, r.clone(), &self.s)
    }

    #[unsafe_fn]
    fn take_self(mut self) -> Self {
        let y: u32 = unsafe { std::mem::zeroed() };
        self.i += 2 + y;
        self
    }

    #[unsafe_fn]
    fn new() -> SomeStruct {
        let _: u32 = unsafe { std::mem::zeroed() };
        SomeStruct::default()
    }

    #[unsafe_fn]
    fn with_i(i: u32) -> Self {
        let _: u32 = unsafe { std::mem::zeroed() };
        SomeStruct {
            i,
            ..Default::default()
        }
    }

    #[unsafe_fn]
    fn with_s(s: String) -> Self {
        let _: u32 = unsafe { std::mem::zeroed() };
        SomeStruct {
            s,
            ..Self::default()
        }
    }
}

pub struct StructWithGen<'a, T>(&'a T);

impl<'a, T: 'a> StructWithGen<'a, T> {
    #[unsafe_fn]
    fn new_t() -> T
    where
        T: Default,
    {
        let _: u32 = unsafe { std::mem::zeroed() };
        let _: Option<Self> = None;
        T::default()
    }

    #[unsafe_fn]
    fn get_t(&self) -> T
    where
        T: Clone,
    {
        let _: u32 = unsafe { std::mem::zeroed() };
        self.0.clone()
    }
}

mod some_module {
    #[unsafe_fn::unsafe_fn]
    pub(crate) fn create_vec<T>() -> Vec<T> {
        let _: u32 = unsafe { std::mem::zeroed() };
        Vec::new()
    }

    #[unsafe_fn::unsafe_fn]
    pub fn size_plus<T>(x: usize) -> usize {
        let y: usize = unsafe { std::mem::zeroed() };
        x + y + std::mem::size_of::<T>()
    }
}

#[unsafe_fn]
#[no_mangle]
extern "C" fn deref_ptr(ptr: *const u32) -> u32 {
    struct Q(u32);
    impl Q {
        fn new(i: u32) -> Self {
            Self(i)
        }
    }
    Q::new(unsafe { *ptr }).0
}

#[unsafe_fn]
fn with_return(x: &mut u32, cond: bool) {
    *x += 4;
    if cond {
        return;
    }
    *x += 8;
}

#[unsafe_fn]
trait Marker {}

unsafe impl Marker for SomeStruct {}

#[test]
fn test_unsafe_fn1() {
    assert_eq!(unsafe { hello(42, "XYZ".into()) }, 42 + 3);
    assert_eq!(unsafe { plus_one(42, "XYZ".into()) }, 42 + 1);
    let mut s1 = SomeStruct {
        i: 8,
        s: "DEF".into(),
    };
    let s2 = unsafe {
        take_struct(
            SomeStruct {
                i: 5,
                s: "ABC".into(),
            },
            &mut s1,
        )
    };
    assert_eq!(s1.i, 9);
    assert_eq!(s2.i, 5 + 9);
    assert_eq!(unsafe { s2.i_plus(58) }, 5 + 9 + 58);
    assert_eq!(unsafe { Box::new(s2.clone()).i_plus(58) }, 5 + 9 + 58);
    let x = 31;
    assert_eq!(unsafe { s2.with_generic(&x, 5, 8) }, (&x, x, "ABCDEF"));
    assert_eq!(unsafe { s2.take_self() }.i, 5 + 9 + 2);
    let _ = unsafe { some_module::create_vec::<u32>() };
    assert_eq!(unsafe { some_module::size_plus::<u32>(1) }, 4 + 1);
    assert_eq!(unsafe { deref_ptr(&x) }, 31);
    let mut m = 1;
    unsafe { with_return(&mut m, true) };
    assert_eq!(m, 1 + 4);
}

#[test]
fn test_safe_body1() {
    #[safe_body]
    unsafe fn some_func((x, mut y): (u32, u32)) -> u32 {
        let z: u32 = unsafe { std::mem::zeroed() };
        y += z;
        x + y
    }

    assert_eq!(unsafe { some_func((4, 3)) }, 4 + 3);
}

#[test]
fn raw_identifier() {
    #[unsafe_fn]
    fn r#unsafe(r#u32: u32) -> u32 {
        return r#u32;
    }
    assert_eq!(unsafe { r#unsafe(5) }, 5);
}

trait SomeTrait {
    #[unsafe_fn]
    fn foo(&self) -> u32;
    #[unsafe_fn]
    fn bar(&self) -> u32 {
        unsafe { self.foo() }
    }

    #[unsafe_fn]
    fn generic<Q>(&self) -> Q
    where
        Q: Default;
}

impl SomeTrait for u32 {
    #[unsafe_fn]
    fn foo(&self) -> u32 {
        let _: u32 = unsafe { std::mem::zeroed() };
        *self
    }
    #[unsafe_fn]
    fn bar(&self) -> u32 {
        unsafe { self.foo() + 2 }
    }

    #[unsafe_fn]
    fn generic<R>(&self) -> R
    where
        R: Default,
    {
        R::default()
    }
}