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.
99mod errors;
100mod fragile;
101mod registry;
102mod semisticky;
103mod sticky;
104mod thread_id;
105
106use std::marker::PhantomData;
107
108pub use crate::errors::InvalidThreadAccess;
109pub use crate::fragile::Fragile;
110pub use crate::semisticky::SemiSticky;
111pub 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.
117pub struct StackToken(PhantomData<*const ()>);
118
119impl StackToken {
120 /// Stack tokens must only be created on the stack.
121 #[doc(hidden)]
122 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]
153macro_rules! stack_token {
154 ($name:ident) => {
155 let $name = &unsafe { $crate::StackToken::__private_new() };
156 };
157}
158