#![cfg_attr(docsrs, feature(doc_cfg))]
#[cfg(feature = "futures")]
#[cfg_attr(docsrs, doc(cfg(feature = "futures")))]
mod futures;
use std::fmt;
use std::mem::{self, ManuallyDrop};
use std::ops::{Deref, DerefMut, Drop};
use std::thread::{self, ThreadId};
pub struct SendWrapper<T> {
data: ManuallyDrop<T>,
thread_id: ThreadId,
}
impl<T> SendWrapper<T> {
pub fn new(data: T) -> SendWrapper<T> {
SendWrapper {
data: ManuallyDrop::new(data),
thread_id: thread::current().id(),
}
}
pub fn valid(&self) -> bool {
self.thread_id == thread::current().id()
}
#[track_caller]
pub fn take(self) -> T {
self.assert_valid_for_deref();
let mut this = ManuallyDrop::new(self);
unsafe { ManuallyDrop::take(&mut this.data) }
}
#[track_caller]
fn assert_valid_for_deref(&self) {
if !self.valid() {
invalid_deref()
}
}
#[track_caller]
fn assert_valid_for_poll(&self) {
if !self.valid() {
invalid_poll()
}
}
}
unsafe impl<T> Send for SendWrapper<T> {}
unsafe impl<T> Sync for SendWrapper<T> {}
impl<T> Deref for SendWrapper<T> {
type Target = T;
#[track_caller]
fn deref(&self) -> &T {
self.assert_valid_for_deref();
&*self.data
}
}
impl<T> DerefMut for SendWrapper<T> {
#[track_caller]
fn deref_mut(&mut self) -> &mut T {
self.assert_valid_for_deref();
&mut *self.data
}
}
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()
}
}
}
impl<T: fmt::Debug> fmt::Debug for SendWrapper<T> {
#[track_caller]
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("SendWrapper")
.field("data", self.deref())
.field("thread_id", &self.thread_id)
.finish()
}
}
impl<T: Clone> Clone for SendWrapper<T> {
#[track_caller]
fn clone(&self) -> Self {
Self::new(self.deref().clone())
}
}
#[cold]
#[inline(never)]
#[track_caller]
fn invalid_deref() -> ! {
const DEREF_ERROR: &'static str = "Dereferenced SendWrapper<T> variable from a thread different to the one it has been created with.";
panic!("{}", DEREF_ERROR)
}
#[cold]
#[inline(never)]
#[track_caller]
fn invalid_poll() -> ! {
const POLL_ERROR: &'static str = "Polling SendWrapper<T> variable from a thread different to the one it has been created with.";
panic!("{}", POLL_ERROR)
}
#[cold]
#[inline(never)]
#[track_caller]
fn invalid_drop() {
const DROP_ERROR: &'static str = "Dropped SendWrapper<T> variable from a thread different to the one it has been created with.";
if !std::thread::panicking() {
panic!("{}", DROP_ERROR)
}
}
#[cfg(test)]
mod tests {
use std::ops::Deref;
use std::rc::Rc;
use std::sync::mpsc::channel;
use std::sync::Arc;
use std::thread;
use super::SendWrapper;
#[test]
fn test_deref() {
let (sender, receiver) = channel();
let w = SendWrapper::new(Rc::new(42));
{
let _x = w.deref();
}
let t = thread::spawn(move || {
sender.send(w).unwrap();
});
let w2 = receiver.recv().unwrap();
{
let _x = w2.deref();
}
assert!(t.join().is_ok());
}
#[test]
fn test_deref_panic() {
let w = SendWrapper::new(Rc::new(42));
let t = thread::spawn(move || {
let _x = w.deref();
});
let join_result = t.join();
assert!(join_result.is_err());
}
#[test]
fn test_drop_panic() {
let w = SendWrapper::new(Rc::new(42));
let t = thread::spawn(move || {
let _x = w;
});
let join_result = t.join();
assert!(join_result.is_err());
}
#[test]
fn test_valid() {
let w = SendWrapper::new(Rc::new(42));
assert!(w.valid());
thread::spawn(move || {
assert!(!w.valid());
});
}
#[test]
fn test_take() {
let w = SendWrapper::new(Rc::new(42));
let inner: Rc<usize> = w.take();
assert_eq!(42, *inner);
}
#[test]
fn test_take_panic() {
let w = SendWrapper::new(Rc::new(42));
let t = thread::spawn(move || {
let _ = w.take();
});
assert!(t.join().is_err());
}
#[test]
fn test_sync() {
let arc = Arc::new(SendWrapper::new(42));
thread::spawn(move || {
let _ = arc;
});
}
#[test]
fn test_debug() {
let w = SendWrapper::new(Rc::new(42));
let info = format!("{:?}", w);
assert!(info.contains("SendWrapper {"));
assert!(info.contains("data: 42,"));
assert!(info.contains("thread_id: ThreadId("));
}
#[test]
fn test_debug_panic() {
let w = SendWrapper::new(Rc::new(42));
let t = thread::spawn(move || {
let _ = format!("{:?}", w);
});
assert!(t.join().is_err());
}
#[test]
fn test_clone() {
let w1 = SendWrapper::new(Rc::new(42));
let w2 = w1.clone();
assert_eq!(format!("{:?}", w1), format!("{:?}", w2));
}
#[test]
fn test_clone_panic() {
let w = SendWrapper::new(Rc::new(42));
let t = thread::spawn(move || {
let _ = w.clone();
});
assert!(t.join().is_err());
}
}