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 /// Get the hash of the type.
95 ///
96 /// # Safety
97 ///
98 /// The pointer must be aligned, readable, and be a pointer to the type that this Hash function
99 /// was created for.
100 unsafe fn raw_eq(a: *const c_void, b: *const c_void) -> bool;
101
102 /// Get a callback suitable for [`SchemaData`].
103 fn raw_eq_cb(
104 ) -> Unsafe<&'static (dyn Fn(*const c_void, *const c_void) -> bool + Sync + Send + 'static)>
105 {
106 unsafe { Unsafe::new(Box::leak(Box::new(|a, b| Self::raw_eq(a, b)))) }
107 }
108}
109impl<T: Eq> RawEq for T {
110 unsafe fn raw_eq(a: *const c_void, b: *const c_void) -> bool {
111 let a = unsafe { &*(a as *const Self) };
112 let b = unsafe { &*(b as *const Self) };
113 a.eq(b)
114 }
115}
116
117/// Trait implemented automatically for types that implement [`Default`] and can be used to write
118/// the default value of the type to a pointer.
119pub trait RawDefault {
120 /// Write the default value of the type to the pointer.
121 ///
122 /// # Safety
123 ///
124 /// The pointer must be aligned, writable, and have the same layout that this function is
125 /// assocated to.
126 unsafe fn raw_default(dst: *mut c_void);
127
128 /// Get a callback suitable for [`SchemaData`].
129 fn raw_default_cb() -> Unsafe<&'static (dyn Fn(*mut c_void) + Sync + Send + 'static)> {
130 unsafe { Unsafe::new(Box::leak(Box::new(|a| Self::raw_default(a)))) }
131 }
132}
133impl<T: Default> RawDefault for T {
134 unsafe fn raw_default(dst: *mut c_void) {
135 let d = T::default();
136 (dst as *mut T).write(d)
137 }
138}