1 //! This library provides wrapper types that permit sending non `Send` types to
2 //! other threads and use runtime checks to ensure safety.
3 //!
4 //! It provides three types: [`Fragile`] and [`Sticky`] which are similar in nature
5 //! but have different behaviors with regards to how destructors are executed and
6 //! the extra [`SemiSticky`] type which uses [`Sticky`] if the value has a
7 //! destructor and [`Fragile`] if it does not.
8 //!
9 //! All three types wrap a value and provide a `Send` bound.  Neither of the types permit
10 //! access to the enclosed value unless the thread that wrapped the value is attempting
11 //! to access it.  The difference between the types starts playing a role once
12 //! destructors are involved.
13 //!
14 //! A [`Fragile`] will actually send the `T` from thread to thread but will only
15 //! permit the original thread to invoke the destructor.  If the value gets dropped
16 //! in a different thread, the destructor will panic.
17 //!
18 //! A [`Sticky`] on the other hand does not actually send the `T` around but keeps
19 //! it stored in the original thread's thread local storage.  If it gets dropped
20 //! in the originating thread it gets cleaned up immediately, otherwise it leaks
21 //! until the thread shuts down naturally.  [`Sticky`] because it borrows into the
22 //! TLS also requires you to "prove" that you are not doing any funny business with
23 //! the borrowed value that lives for longer than the current stack frame which
24 //! results in a slightly more complex API.
25 //!
26 //! There is a third typed called [`SemiSticky`] which shares the API with [`Sticky`]
27 //! but internally uses a boxed [`Fragile`] if the type does not actually need a dtor
28 //! in which case [`Fragile`] is preferred.
29 //!
30 //! # Fragile Usage
31 //!
32 //! [`Fragile`] is the easiest type to use.  It works almost like a cell.
33 //!
34 //! ```
35 //! use std::thread;
36 //! use fragile::Fragile;
37 //!
38 //! // creating and using a fragile object in the same thread works
39 //! let val = Fragile::new(true);
40 //! assert_eq!(*val.get(), true);
41 //! assert!(val.try_get().is_ok());
42 //!
43 //! // once send to another thread it stops working
44 //! thread::spawn(move || {
45 //!     assert!(val.try_get().is_err());
46 //! }).join()
47 //!     .unwrap();
48 //! ```
49 //!
50 //! # Sticky Usage
51 //!
52 //! [`Sticky`] is similar to [`Fragile`] but because it places the value in the
53 //! thread local storage it comes with some extra restrictions to make it sound.
54 //! The advantage is it can be dropped from any thread but it comes with extra
55 //! restrictions.  In particular it requires that values placed in it are `'static`
56 //! and that [`StackToken`]s are used to restrict lifetimes.
57 //!
58 //! ```
59 //! use std::thread;
60 //! use fragile::Sticky;
61 //!
62 //! // creating and using a fragile object in the same thread works
63 //! fragile::stack_token!(tok);
64 //! let val = Sticky::new(true);
65 //! assert_eq!(*val.get(tok), true);
66 //! assert!(val.try_get(tok).is_ok());
67 //!
68 //! // once send to another thread it stops working
69 //! thread::spawn(move || {
70 //!     fragile::stack_token!(tok);
71 //!     assert!(val.try_get(tok).is_err());
72 //! }).join()
73 //!     .unwrap();
74 //! ```
75 //!
76 //! # Why?
77 //!
78 //! Most of the time trying to use this crate is going to indicate some code smell.  But
79 //! there are situations where this is useful.  For instance you might have a bunch of
80 //! non `Send` types but want to work with a `Send` error type.  In that case the non
81 //! sendable extra information can be contained within the error and in cases where the
82 //! error did not cross a thread boundary yet extra information can be obtained.
83 //!
84 //! # Drop / Cleanup Behavior
85 //!
86 //! All types will try to eagerly drop a value if they are dropped on the right thread.
87 //! [`Sticky`] and [`SemiSticky`] will however temporarily leak memory until a thread
88 //! shuts down if the value is dropped on the wrong thread.  The benefit however is that
89 //! if you have that type of situation, and you can live with the consequences, the
90 //! type is not panicking.  A [`Fragile`] dropped in the wrong thread will not just panic,
91 //! it will effectively also tear down the process because panicking in destructors is
92 //! non recoverable.
93 //!
94 //! # Features
95 //!
96 //! By default the crate has no dependencies.  Optionally the `slab` feature can
97 //! be enabled which optimizes the internal storage of the [`Sticky`] type to
98 //! make it use a [`slab`](https://docs.rs/slab/latest/slab/) instead.
99 mod errors;
100 mod fragile;
101 mod registry;
102 mod semisticky;
103 mod sticky;
104 mod thread_id;
105 
106 use std::marker::PhantomData;
107 
108 pub use crate::errors::InvalidThreadAccess;
109 pub use crate::fragile::Fragile;
110 pub use crate::semisticky::SemiSticky;
111 pub use crate::sticky::Sticky;
112 
113 /// A token that is placed to the stack to constrain lifetimes.
114 ///
115 /// For more information about how these work see the documentation of
116 /// [`stack_token!`] which is the only way to create this token.
117 pub struct StackToken(PhantomData<*const ()>);
118 
119 impl StackToken {
120     /// Stack tokens must only be created on the stack.
121     #[doc(hidden)]
__private_new() -> StackToken122     pub unsafe fn __private_new() -> StackToken {
123         // we place a const pointer in there to get a type
124         // that is neither Send nor Sync.
125         StackToken(PhantomData)
126     }
127 }
128 
129 /// Crates a token on the stack with a certain name for semi-sticky.
130 ///
131 /// The argument to the macro is the target name of a local variable
132 /// which holds a reference to a stack token.  Because this is the
133 /// only way to create such a token, it acts as a proof to [`Sticky`]
134 /// or [`SemiSticky`] that can be used to constrain the lifetime of the
135 /// return values to the stack frame.
136 ///
137 /// This is necessary as otherwise a [`Sticky`] placed in a [`Box`] and
138 /// leaked with [`Box::leak`] (which creates a static lifetime) would
139 /// otherwise create a reference with `'static` lifetime.  This is incorrect
140 /// as the actual lifetime is constrained to the lifetime of the thread.
141 /// For more information see [`issue 26`](https://github.com/mitsuhiko/fragile/issues/26).
142 ///
143 /// ```rust
144 /// let sticky = fragile::Sticky::new(true);
145 ///
146 /// // this places a token on the stack.
147 /// fragile::stack_token!(my_token);
148 ///
149 /// // the token needs to be passed to `get` and others.
150 /// let _ = sticky.get(my_token);
151 /// ```
152 #[macro_export]
153 macro_rules! stack_token {
154     ($name:ident) => {
155         let $name = &unsafe { $crate::StackToken::__private_new() };
156     };
157 }
158