1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
//! Traits implementing raw function calls for cloning, dropping, and creating default values for
//! Rust types.

use std::{
    ffi::c_void,
    hash::{Hash, Hasher},
};

use bones_utils::fxhash::FxHasher;

use crate::Unsafe;

#[cfg(doc)]
use crate::SchemaData;

/// Trait implemented automatically for types that implement [`Clone`] and can be used to clone the
/// type through raw pointers.
pub trait RawClone {
    /// Write the default value of the type to the pointer.
    ///
    /// # Safety
    ///
    /// The `dst` pointer must be aligned, writable, and have the same layout that this function is
    /// assocated to, and the `src` pointer must be readable and point to a valid instance of the
    /// type that this function is associated with.
    unsafe fn raw_clone(src: *const c_void, dst: *mut c_void);

    /// Get a callback suitable for [`SchemaData`].
    fn raw_clone_cb(
    ) -> Unsafe<&'static (dyn Fn(*const c_void, *mut c_void) + Sync + Send + 'static)> {
        unsafe { Unsafe::new(Box::leak(Box::new(|a, b| Self::raw_clone(a, b)))) }
    }
}
impl<T: Clone> RawClone for T {
    unsafe fn raw_clone(src: *const c_void, dst: *mut c_void) {
        let t = &*(src as *const T);
        let t = t.clone();
        (dst as *mut T).write(t)
    }
}

/// Trait implemented automatically for types that implement [`Drop`] and can be used to drop the
/// type through a raw pointer.
pub trait RawDrop {
    /// Write the default value of the type to the pointer.
    ///
    /// # Safety
    ///
    /// The pointer must be aligned, writable, and have the same layout that this function is
    /// assocated to.
    unsafe fn raw_drop(ptr: *mut c_void);

    /// Get a callback suitable for [`SchemaData`].
    fn raw_drop_cb() -> Unsafe<&'static (dyn Fn(*mut c_void) + Sync + Send + 'static)> {
        unsafe { Unsafe::new(Box::leak(Box::new(|a| Self::raw_drop(a)))) }
    }
}
impl<T> RawDrop for T {
    unsafe fn raw_drop(ptr: *mut c_void) {
        if std::mem::needs_drop::<T>() {
            (ptr as *mut T).drop_in_place()
        }
    }
}

/// Trait implemented automatically for types that implement [`Hash`] and can be used compute a
/// [`u64`] hash for a type using a pointer to it.
pub trait RawHash {
    /// Get the hash of the type.
    ///
    /// # Safety
    ///
    /// The pointer must be aligned, readable, and be a pointer to the type that this Hash function
    /// was created for.
    unsafe fn raw_hash(ptr: *const c_void) -> u64;

    /// Get a callback suitable for [`SchemaData`].
    fn raw_hash_cb() -> Unsafe<&'static (dyn Fn(*const c_void) -> u64 + Sync + Send + 'static)> {
        unsafe { Unsafe::new(Box::leak(Box::new(|a| Self::raw_hash(a)))) }
    }
}
impl<T: Hash> RawHash for T {
    unsafe fn raw_hash(ptr: *const c_void) -> u64 {
        let this = unsafe { &*(ptr as *const Self) };
        let mut hasher = FxHasher::default();
        this.hash(&mut hasher);
        hasher.finish()
    }
}

/// Trait implemented automatically for types that implement [`Eq`] that can compare two values
/// through their pointers.
pub trait RawEq {
    /// Get the hash of the type.
    ///
    /// # Safety
    ///
    /// The pointer must be aligned, readable, and be a pointer to the type that this Hash function
    /// was created for.
    unsafe fn raw_eq(a: *const c_void, b: *const c_void) -> bool;

    /// Get a callback suitable for [`SchemaData`].
    fn raw_eq_cb(
    ) -> Unsafe<&'static (dyn Fn(*const c_void, *const c_void) -> bool + Sync + Send + 'static)>
    {
        unsafe { Unsafe::new(Box::leak(Box::new(|a, b| Self::raw_eq(a, b)))) }
    }
}
impl<T: Eq> RawEq for T {
    unsafe fn raw_eq(a: *const c_void, b: *const c_void) -> bool {
        let a = unsafe { &*(a as *const Self) };
        let b = unsafe { &*(b as *const Self) };
        a.eq(b)
    }
}

/// Trait implemented automatically for types that implement [`Default`] and can be used to write
/// the default value of the type to a pointer.
pub trait RawDefault {
    /// Write the default value of the type to the pointer.
    ///
    /// # Safety
    ///
    /// The pointer must be aligned, writable, and have the same layout that this function is
    /// assocated to.
    unsafe fn raw_default(dst: *mut c_void);

    /// Get a callback suitable for [`SchemaData`].
    fn raw_default_cb() -> Unsafe<&'static (dyn Fn(*mut c_void) + Sync + Send + 'static)> {
        unsafe { Unsafe::new(Box::leak(Box::new(|a| Self::raw_default(a)))) }
    }
}
impl<T: Default> RawDefault for T {
    unsafe fn raw_default(dst: *mut c_void) {
        let d = T::default();
        (dst as *mut T).write(d)
    }
}