1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
//! An isolated workaround for a rustc limitation, kept apart from the session
//! logic on purpose.
//!
//! ## What this is
//!
//! [`ForceSend`] is a transparent wrapper that is *always* `Send` and `Sync`,
//! regardless of the wrapped type. It is used in exactly one place — around the
//! `Arc<DownloadResultInner<..>>` inside
//! [`DownloadResult`](crate::DownloadResult) — to work around rustc's
//! `async fn` auto-trait leak check.
//!
//! ## Why it is needed
//!
//! `download_multi` and `download_single` are synchronous, but downstream code
//! naturally constructs their result inside an `async` block and holds it
//! across an `await`:
//!
//! ```ignore
//! tokio::spawn(async move {
//! let result = download_multi(puller, pusher, options);
//! while result.recv().await.is_ok() {}
//! });
//! ```
//!
//! rustc's `async fn` auto-trait leak check rejects this with a spurious
//! `higher-ranked lifetime error`, even though the handle really is `Send`.
//! There are two independent triggers, and this file addresses the first:
//!
//! 1. **Constructing the handle.** The leak check gives up when it has to
//! normalize an associated-type projection (`E::Handle`, named by the
//! session's task queue) from inside an `async` context. `ForceSend` erases
//! the projection from the handle's fields, which discharges the check.
//! 2. **Awaiting the event stream.** `crossfire::RecvFuture` is only `Send`
//! through a hand-written impl the check does not see through; that is why
//! [`DownloadResult::recv`](crate::DownloadResult::recv) exists — use it
//! instead of `event_chain().recv()` in a spawned driver.
//!
//! Both are false negatives of the same class, tracked in
//! <https://github.com/rust-lang/rust/issues/110338> (metabug: "incorrect
//! lifetime bound errors in async"); the fix lives behind the upcoming
//! "assumptions on binders" work and is not available yet.
//!
//! ## Why it is sound
//!
//! Every field of `DownloadResultInner` is genuinely `Send + Sync` for **every**
//! instantiation that can exist: the event chain (`crossfire::MAsyncRx`) is
//! unconditionally `Send + Sync`, the task queue + executor require
//! `E: Executor + Send + Sync` by its own definition, and the cancellation
//! token is `Send + Sync`. `ForceSend` therefore asserts a property the type
//! already has; it only silences a compiler false negative. The assertion is
//! deliberately stated once, here, rather than spread across the session code.
//!
//! Once the leak check is fixed upstream, this type can be deleted and the
//! field can go back to a bare `Arc<DownloadResultInner<..>>`.
use Deref;
/// A transparent, unconditionally `Send + Sync` holder.
///
/// See the module docs for why this exists and why it is sound. It derefs to
/// the wrapped value, so code that goes through it reads exactly like code that
/// holds the value directly.
;
// SAFETY: `ForceSend` is transparent and is only ever used to wrap a value that
// is already `Send + Sync`. The assertion exists solely to bypass rustc's
// `async fn` auto-trait leak check (rust-lang/rust#110338), which cannot prove
// the wrapped value's auto-traits in an `async` context.
unsafe
unsafe