use std::fmt::Debug;
use tracing::{instrument, Span};
pub(crate) struct CustomPtrDrop<'a, EltT> {
t: SendablePtr<EltT>,
drop: Box<dyn Fn(*mut EltT) + 'a + Send>,
}
impl<'a, EltT> CustomPtrDrop<'a, EltT> {
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
pub(crate) fn new(elt: *mut EltT, drop_fn: Box<dyn Fn(*mut EltT) + Send>) -> Self {
Self {
t: SendablePtr(elt),
drop: drop_fn,
}
}
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
pub(crate) fn as_mut_ptr(&self) -> *mut EltT {
self.t.0
}
}
impl<'a, EltT> Debug for CustomPtrDrop<'a, EltT> {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.debug_struct("CustomDrop").finish()
}
}
impl<'a, EltT> Drop for CustomPtrDrop<'a, EltT> {
#[instrument(skip_all, parent = Span::current(), level= "Trace")]
fn drop(&mut self) {
let drop_fn = &self.drop;
drop_fn(self.t.0)
}
}
struct SendablePtr<T>(*mut T);
unsafe impl<T> Send for SendablePtr<T> {}
#[cfg(test)]
mod tests {
#[cfg(target_os = "windows")]
use std::sync::{Arc, Mutex};
#[cfg(target_os = "windows")]
use std::thread;
#[cfg(target_os = "windows")]
use super::CustomPtrDrop;
#[test]
#[cfg(target_os = "windows")]
fn test_custom_drop_multithreaded() {
let i_ptr = Box::into_raw(Box::new(1));
let cd_arc = {
let cd = CustomPtrDrop::new(
i_ptr,
Box::new(|ptr| {
unsafe {
let _ = Box::from_raw(ptr);
};
}),
);
Arc::new(Mutex::new(cd))
};
let mut join_handles = Vec::new();
for _ in 0..10 {
let cd = cd_arc.clone();
let join_handle = thread::spawn(move || print!("cd: {cd:?}"));
join_handles.push(join_handle);
}
for join_handle in join_handles {
join_handle.join().unwrap();
}
}
}