#[cfg(feature = "current_thread_id")]
use std::thread::current_id;
use std::{
mem::{self, ManuallyDrop},
thread::{self, ThreadId},
};
#[cfg(not(feature = "current_thread_id"))]
mod imp {
use std::{
cell::Cell,
thread::{self, ThreadId},
};
thread_local! {
static THREAD_ID: Cell<ThreadId> = Cell::new(thread::current().id());
}
pub fn current_id() -> ThreadId {
THREAD_ID.get()
}
}
#[cfg(not(feature = "current_thread_id"))]
use imp::current_id;
pub struct SendWrapper<T> {
data: ManuallyDrop<T>,
thread_id: ThreadId,
}
impl<T> SendWrapper<T> {
#[inline]
pub fn new(data: T) -> SendWrapper<T> {
SendWrapper {
data: ManuallyDrop::new(data),
thread_id: current_id(),
}
}
#[inline]
pub fn valid(&self) -> bool {
self.thread_id == current_id()
}
#[inline]
pub unsafe fn get_unchecked(&self) -> &T {
&self.data
}
#[inline]
#[allow(dead_code)]
pub fn get(&self) -> Option<&T> {
if self.valid() { Some(&self.data) } else { None }
}
#[inline]
pub fn tracker(&self) -> SendWrapper<()> {
SendWrapper {
data: ManuallyDrop::new(()),
thread_id: self.thread_id,
}
}
}
unsafe impl<T> Send for SendWrapper<T> {}
unsafe impl<T> Sync for SendWrapper<T> {}
impl<T> Drop for SendWrapper<T> {
#[track_caller]
fn drop(&mut self) {
if !mem::needs_drop::<T>() || self.valid() {
unsafe {
ManuallyDrop::drop(&mut self.data);
}
} else {
invalid_drop()
}
}
}
#[cold]
#[inline(never)]
#[track_caller]
fn invalid_drop() {
const DROP_ERROR: &str = "Dropped SendWrapper<T> variable from a thread different to the one \
it has been created with.";
if !thread::panicking() {
panic!("{}", DROP_ERROR)
}
}