1// Copyright 2017 Thomas Keh.
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
5// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
6// option. This file may not be copied, modified, or distributed
7// except according to those terms.
8
9//! This [Rust] library implements a wrapper type called [`SendWrapper`] which allows you to move around non-[`Send`] types
10//! between threads, as long as you access the contained value only from within the original thread. You also have to
11//! make sure that the wrapper is dropped from within the original thread. If any of these constraints is violated,
12//! a panic occurs. [`SendWrapper<T>`] implements [`Send`] and [`Sync`] for any type `T`.
13//!
14//! The idea for this library was born in the context of a [`GTK+`]/[`gtk-rs`]-based application. [`GTK+`] applications
15//! are strictly single-threaded. It is not allowed to call any [`GTK+`] method from a thread different to the main
16//! thread. Consequently, all [`gtk-rs`] structs are non-[`Send`].
17//!
18//! Sometimes you still want to do some work in background. It is possible to enqueue [`GTK+`] calls from there to be
19//! executed in the main thread [using `Glib`]. This way you can know, that the [`gtk-rs`] structs involved are only
20//! accessed in the main thread and will also be dropped there. This library makes it possible that [`gtk-rs`] structs
21//! can leave the main thread at all.
22//!
23//! # Examples
24//!
25//! ```rust
26//! use send_wrapper::SendWrapper;
27//! use std::rc::Rc;
28//! use std::thread;
29//! use std::sync::mpsc::channel;
30//!
31//! // This import is important if you want to use deref() or
32//! // deref_mut() instead of Deref coercion.
33//! use std::ops::{Deref, DerefMut};
34//!
35//! // Rc is a non-Send type.
36//! let value = Rc::new(42);
37//!
38//! // We now wrap the value with `SendWrapper` (value is moved inside).
39//! let wrapped_value = SendWrapper::new(value);
40//!
41//! // A channel allows us to move the wrapped value between threads.
42//! let (sender, receiver) = channel();
43//!
44//! let t = thread::spawn(move || {
45//!
46//! // This would panic (because of dereferencing in wrong thread):
47//! // let value = wrapped_value.deref();
48//!
49//! // Move SendWrapper back to main thread, so it can be dropped from there.
50//! // If you leave this out the thread will panic because of dropping from wrong thread.
51//! sender.send(wrapped_value).unwrap();
52//!
53//! });
54//!
55//! let wrapped_value = receiver.recv().unwrap();
56//!
57//! // Now you can use the value again.
58//! let value = wrapped_value.deref();
59//!
60//! // alternatives for dereferencing:
61//! let value = &*wrapped_value;
62//! let value: &Rc<_> = &wrapped_value;
63//!
64//! let mut wrapped_value = wrapped_value;
65//! // alternatives for mutable dereferencing:
66//! let value = wrapped_value.deref_mut();
67//! let value = &mut *wrapped_value;
68//! let value: &mut Rc<_> = &mut wrapped_value;
69//! ```
70//!
71//! # Features
72//!
73//! This crate has a single feature called `futures` that enables [`Future`] and [`Stream`] implementations for [`SendWrapper`].
74//! You can enable it in `Cargo.toml` like so:
75//!
76//! ```toml
77//! send_wrapper = { version = "...", features = ["futures"] }
78//! ```
79//!
80//! # License
81//!
82//! `send_wrapper` is distributed under the terms of both the MIT license and the Apache License (Version 2.0).
83//!
84//! See LICENSE-APACHE.txt, and LICENSE-MIT.txt for details.
85//!
86//! [Rust]: https://www.rust-lang.org
87//! [`gtk-rs`]: http://gtk-rs.org/
88//! [`GTK+`]: https://www.gtk.org/
89//! [using `Glib`]: http://gtk-rs.org/docs/glib/source/fn.idle_add.html
90//! [`Future`]: std::future::Future
91//! [`Stream`]: futures_core::Stream
92// To build docs locally use `RUSTDOCFLAGS="--cfg docsrs" cargo doc --open --all-features`
93#![cfg_attr(docsrs, feature(doc_cfg))]
94
95#[cfg(feature = "futures")]
96#[cfg_attr(docsrs, doc(cfg(feature = "futures")))]
97mod futures;
98
99use std::fmt;
100use std::mem::{self, ManuallyDrop};
101use std::ops::{Deref, DerefMut, Drop};
102use std::thread::{self, ThreadId};
103
104/// A wrapper which allows you to move around non-[`Send`]-types between threads, as long as you access the contained
105/// value only from within the original thread and make sure that it is dropped from within the original thread.
106pub struct SendWrapper<T> {
107 data: ManuallyDrop<T>,
108 thread_id: ThreadId,
109}
110
111impl<T> SendWrapper<T> {
112 /// Create a `SendWrapper<T>` wrapper around a value of type `T`.
113 /// The wrapper takes ownership of the value.
114 pub fn new(data: T) -> SendWrapper<T> {
115 SendWrapper {
116 data: ManuallyDrop::new(data),
117 thread_id: thread::current().id(),
118 }
119 }
120
121 /// Returns `true` if the value can be safely accessed from within the current thread.
122 pub fn valid(&self) -> bool {
123 self.thread_id == thread::current().id()
124 }
125
126 /// Takes the value out of the `SendWrapper<T>`.
127 ///
128 /// # Panics
129 ///
130 /// Panics if it is called from a different thread than the one the `SendWrapper<T>` instance has
131 /// been created with.
132 #[track_caller]
133 pub fn take(self) -> T {
134 self.assert_valid_for_deref();
135
136 // Prevent drop() from being called, as it would drop `self.data` twice
137 let mut this = ManuallyDrop::new(self);
138
139 // Safety:
140 // - We've just checked that it's valid to access `T` from the current thread
141 // - We only move out from `self.data` here and in drop, so `self.data` is present
142 unsafe { ManuallyDrop::take(&mut this.data) }
143 }
144
145 #[track_caller]
146 fn assert_valid_for_deref(&self) {
147 if !self.valid() {
148 invalid_deref()
149 }
150 }
151
152 #[track_caller]
153 fn assert_valid_for_poll(&self) {
154 if !self.valid() {
155 invalid_poll()
156 }
157 }
158}
159
160unsafe impl<T> Send for SendWrapper<T> {}
161unsafe impl<T> Sync for SendWrapper<T> {}
162
163impl<T> Deref for SendWrapper<T> {
164 type Target = T;
165
166 /// Returns a reference to the contained value.
167 ///
168 /// # Panics
169 ///
170 /// Dereferencing panics if it is done from a different thread than the one the `SendWrapper<T>` instance has been
171 /// created with.
172 #[track_caller]
173 fn deref(&self) -> &T {
174 self.assert_valid_for_deref();
175
176 // Access the value.
177 //
178 // Safety: We just checked that it is valid to access `T` on the current thread.
179 &*self.data
180 }
181}
182
183impl<T> DerefMut for SendWrapper<T> {
184 /// Returns a mutable reference to the contained value.
185 ///
186 /// # Panics
187 ///
188 /// Dereferencing panics if it is done from a different thread than the one the `SendWrapper<T>` instance has been
189 /// created with.
190 #[track_caller]
191 fn deref_mut(&mut self) -> &mut T {
192 self.assert_valid_for_deref();
193
194 // Access the value.
195 //
196 // Safety: We just checked that it is valid to access `T` on the current thread.
197 &mut *self.data
198 }
199}
200
201impl<T> Drop for SendWrapper<T> {
202 /// Drops the contained value.
203 ///
204 /// # Panics
205 ///
206 /// Dropping panics if it is done from a different thread than the one the `SendWrapper<T>` instance has been
207 /// created with.
208 ///
209 /// Exceptions:
210 /// - There is no extra panic if the thread is already panicking/unwinding.
211 /// This is because otherwise there would be double panics (usually resulting in an abort)
212 /// when dereferencing from a wrong thread.
213 /// - If `T` has a trivial drop ([`needs_drop::<T>()`] is false) then this method never panics.
214 ///
215 /// [`needs_drop::<T>()`]: std::mem::needs_drop
216 #[track_caller]
217 fn drop(&mut self) {
218 // If the drop is trivial (`needs_drop` = false), then dropping `T` can't access it
219 // and so it can be safely dropped on any thread.
220 if !mem::needs_drop::<T>() || self.valid() {
221 unsafe {
222 // Drop the inner value
223 //
224 // Safety:
225 // - We've just checked that it's valid to drop `T` on this thread
226 // - We only move out from `self.data` here and in drop, so `self.data` is present
227 ManuallyDrop::drop(&mut self.data);
228 }
229 } else {
230 invalid_drop()
231 }
232 }
233}
234
235impl<T: fmt::Debug> fmt::Debug for SendWrapper<T> {
236 /// Formats the value using the given formatter.
237 ///
238 /// # Panics
239 ///
240 /// Formatting panics if it is done from a different thread than the one
241 /// the `SendWrapper<T>` instance has been created with.
242 #[track_caller]
243 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
244 f&mut DebugStruct<'_, '_>.debug_struct("SendWrapper")
245 .field("data", self.deref())
246 .field(name:"thread_id", &self.thread_id)
247 .finish()
248 }
249}
250
251impl<T: Clone> Clone for SendWrapper<T> {
252 /// Returns a copy of the value.
253 ///
254 /// # Panics
255 ///
256 /// Cloning panics if it is done from a different thread than the one
257 /// the `SendWrapper<T>` instance has been created with.
258 #[track_caller]
259 fn clone(&self) -> Self {
260 Self::new(self.deref().clone())
261 }
262}
263
264#[cold]
265#[inline(never)]
266#[track_caller]
267fn invalid_deref() -> ! {
268 const DEREF_ERROR: &'static str = "Dereferenced SendWrapper<T> variable from a thread different to the one it has been created with.";
269
270 panic!("{}", DEREF_ERROR)
271}
272
273#[cold]
274#[inline(never)]
275#[track_caller]
276fn invalid_poll() -> ! {
277 const POLL_ERROR: &'static str = "Polling SendWrapper<T> variable from a thread different to the one it has been created with.";
278
279 panic!("{}", POLL_ERROR)
280}
281
282#[cold]
283#[inline(never)]
284#[track_caller]
285fn invalid_drop() {
286 const DROP_ERROR: &'static str = "Dropped SendWrapper<T> variable from a thread different to the one it has been created with.";
287
288 if !std::thread::panicking() {
289 // panic because of dropping from wrong thread
290 // only do this while not unwinding (could be caused by deref from wrong thread)
291 panic!("{}", DROP_ERROR)
292 }
293}
294
295#[cfg(test)]
296mod tests {
297 use std::ops::Deref;
298 use std::rc::Rc;
299 use std::sync::mpsc::channel;
300 use std::sync::Arc;
301 use std::thread;
302
303 use super::SendWrapper;
304
305 #[test]
306 fn test_deref() {
307 let (sender, receiver) = channel();
308 let w = SendWrapper::new(Rc::new(42));
309 {
310 let _x = w.deref();
311 }
312 let t = thread::spawn(move || {
313 // move SendWrapper back to main thread, so it can be dropped from there
314 sender.send(w).unwrap();
315 });
316 let w2 = receiver.recv().unwrap();
317 {
318 let _x = w2.deref();
319 }
320 assert!(t.join().is_ok());
321 }
322
323 #[test]
324 fn test_deref_panic() {
325 let w = SendWrapper::new(Rc::new(42));
326 let t = thread::spawn(move || {
327 let _x = w.deref();
328 });
329 let join_result = t.join();
330 assert!(join_result.is_err());
331 }
332
333 #[test]
334 fn test_drop_panic() {
335 let w = SendWrapper::new(Rc::new(42));
336 let t = thread::spawn(move || {
337 let _x = w;
338 });
339 let join_result = t.join();
340 assert!(join_result.is_err());
341 }
342
343 #[test]
344 fn test_valid() {
345 let w = SendWrapper::new(Rc::new(42));
346 assert!(w.valid());
347 thread::spawn(move || {
348 assert!(!w.valid());
349 });
350 }
351
352 #[test]
353 fn test_take() {
354 let w = SendWrapper::new(Rc::new(42));
355 let inner: Rc<usize> = w.take();
356 assert_eq!(42, *inner);
357 }
358
359 #[test]
360 fn test_take_panic() {
361 let w = SendWrapper::new(Rc::new(42));
362 let t = thread::spawn(move || {
363 let _ = w.take();
364 });
365 assert!(t.join().is_err());
366 }
367
368 #[test]
369 fn test_sync() {
370 // Arc<T> can only be sent to another thread if T Sync
371 let arc = Arc::new(SendWrapper::new(42));
372 thread::spawn(move || {
373 let _ = arc;
374 });
375 }
376
377 #[test]
378 fn test_debug() {
379 let w = SendWrapper::new(Rc::new(42));
380 let info = format!("{:?}", w);
381 assert!(info.contains("SendWrapper {"));
382 assert!(info.contains("data: 42,"));
383 assert!(info.contains("thread_id: ThreadId("));
384 }
385
386 #[test]
387 fn test_debug_panic() {
388 let w = SendWrapper::new(Rc::new(42));
389 let t = thread::spawn(move || {
390 let _ = format!("{:?}", w);
391 });
392 assert!(t.join().is_err());
393 }
394
395 #[test]
396 fn test_clone() {
397 let w1 = SendWrapper::new(Rc::new(42));
398 let w2 = w1.clone();
399 assert_eq!(format!("{:?}", w1), format!("{:?}", w2));
400 }
401
402 #[test]
403 fn test_clone_panic() {
404 let w = SendWrapper::new(Rc::new(42));
405 let t = thread::spawn(move || {
406 let _ = w.clone();
407 });
408 assert!(t.join().is_err());
409 }
410}
411