bones_schema/raw_fns.rs
1//! Traits implementing raw function calls for cloning, dropping, and creating default values for
2//! Rust types.
3
4use std::{
5 ffi::c_void,
6 hash::{Hash, Hasher},
7};
8
9use fxhash::FxHasher;
10
11use crate::Unsafe;
12
13#[cfg(doc)]
14use crate::SchemaData;
15
16/// Trait implemented automatically for types that implement [`Clone`] and can be used to clone the
17/// type through raw pointers.
18pub trait RawClone {
19 /// Write the default value of the type to the pointer.
20 ///
21 /// # Safety
22 ///
23 /// The `dst` pointer must be aligned, writable, and have the same layout that this function is
24 /// assocated to, and the `src` pointer must be readable and point to a valid instance of the
25 /// type that this function is associated with.
26 unsafe fn raw_clone(src: *const c_void, dst: *mut c_void);
27
28 /// Get a callback suitable for [`SchemaData`].
29 fn raw_clone_cb(
30 ) -> Unsafe<&'static (dyn Fn(*const c_void, *mut c_void) + Sync + Send + 'static)> {
31 unsafe { Unsafe::new(Box::leak(Box::new(|a, b| Self::raw_clone(a, b)))) }
32 }
33}
34impl<T: Clone> RawClone for T {
35 unsafe fn raw_clone(src: *const c_void, dst: *mut c_void) {
36 let t = &*(src as *const T);
37 let t = t.clone();
38 (dst as *mut T).write(t)
39 }
40}
41
42/// Trait implemented automatically for types that implement [`Drop`] and can be used to drop the
43/// type through a raw pointer.
44pub trait RawDrop {
45 /// Write the default value of the type to the pointer.
46 ///
47 /// # Safety
48 ///
49 /// The pointer must be aligned, writable, and have the same layout that this function is
50 /// assocated to.
51 unsafe fn raw_drop(ptr: *mut c_void);
52
53 /// Get a callback suitable for [`SchemaData`].
54 fn raw_drop_cb() -> Unsafe<&'static (dyn Fn(*mut c_void) + Sync + Send + 'static)> {
55 unsafe { Unsafe::new(Box::leak(Box::new(|a| Self::raw_drop(a)))) }
56 }
57}
58impl<T> RawDrop for T {
59 unsafe fn raw_drop(ptr: *mut c_void) {
60 if std::mem::needs_drop::<T>() {
61 (ptr as *mut T).drop_in_place()
62 }
63 }
64}
65
66/// Trait implemented automatically for types that implement [`Hash`] and can be used compute a
67/// [`u64`] hash for a type using a pointer to it.
68pub trait RawHash {
69 /// Get the hash of the type.
70 ///
71 /// # Safety
72 ///
73 /// The pointer must be aligned, readable, and be a pointer to the type that this Hash function
74 /// was created for.
75 unsafe fn raw_hash(ptr: *const c_void) -> u64;
76
77 /// Get a callback suitable for [`SchemaData`].
78 fn raw_hash_cb() -> Unsafe<&'static (dyn Fn(*const c_void) -> u64 + Sync + Send + 'static)> {
79 unsafe { Unsafe::new(Box::leak(Box::new(|a| Self::raw_hash(a)))) }
80 }
81}
82impl<T: Hash> RawHash for T {
83 unsafe fn raw_hash(ptr: *const c_void) -> u64 {
84 let this = unsafe { &*(ptr as *const Self) };
85 let mut hasher = FxHasher::default();
86 this.hash(&mut hasher);
87 hasher.finish()
88 }
89}
90
91/// Trait implemented automatically for types that implement [`Eq`] that can compare two values
92/// through their pointers.
93pub trait RawEq {
94 // TODO: correctly document this function ( it thinks it is `raw_hash` )
95 /// Get the hash of the type.
96 ///
97 /// # Safety
98 ///
99 /// The pointer must be aligned, readable, and be a pointer to the type that this Hash function
100 /// was created for.
101 unsafe fn raw_eq(a: *const c_void, b: *const c_void) -> bool;
102
103 /// Get a callback suitable for [`SchemaData`].
104 fn raw_eq_cb(
105 ) -> Unsafe<&'static (dyn Fn(*const c_void, *const c_void) -> bool + Sync + Send + 'static)>
106 {
107 unsafe { Unsafe::new(Box::leak(Box::new(|a, b| Self::raw_eq(a, b)))) }
108 }
109}
110impl<T: Eq> RawEq for T {
111 unsafe fn raw_eq(a: *const c_void, b: *const c_void) -> bool {
112 let a = unsafe { &*(a as *const Self) };
113 let b = unsafe { &*(b as *const Self) };
114 a.eq(b)
115 }
116}
117
118/// Trait implemented automatically for types that implement [`Default`] and can be used to write
119/// the default value of the type to a pointer.
120pub trait RawDefault {
121 /// Write the default value of the type to the pointer.
122 ///
123 /// # Safety
124 ///
125 /// The pointer must be aligned, writable, and have the same layout that this function is
126 /// assocated to.
127 unsafe fn raw_default(dst: *mut c_void);
128
129 /// Get a callback suitable for [`SchemaData`].
130 fn raw_default_cb() -> Unsafe<&'static (dyn Fn(*mut c_void) + Sync + Send + 'static)> {
131 unsafe { Unsafe::new(Box::leak(Box::new(|a| Self::raw_default(a)))) }
132 }
133}
134impl<T: Default> RawDefault for T {
135 unsafe fn raw_default(dst: *mut c_void) {
136 let d = T::default();
137 (dst as *mut T).write(d)
138 }
139}