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
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
//! Type-erased forms of [`crate::unversioned::Transport`] and [`Timer`], so
//! a facade can be **one concrete type** instead of two type parameters.
//!
//! A backend implements nothing here: [`BoxedTransport`] and [`BoxedTimer`]
//! have blanket impls over every `Transport` and every `Timer`.
//!
//! # Nothing boxed here declares `Send`
//!
//! The boxed future, body, sleep and instant carry no auto trait, and that
//! is what makes the blanket impls possible: proving
//! `Transport::execute`'s RPITIT `Send` for a generic `T` needs return type
//! notation, unstable as of rustc 1.98. Following the bound down to where
//! it *can* be proven would put it on seven seam methods, which excludes a
//! single-threaded runtime such as `hclient-rt-embassy`, whose `connect`
//! future holds a `RefCell` and always will.
//!
//! The consequence a caller meets: **nothing a request produces is
//! `Send`** — not the future, not the response body. One `BoxBody` serves
//! every backend, and a browser's body holds a `dyn Stream` with no auto
//! trait, so declaring `Send` would exclude that backend rather than weaken
//! it.
//!
//! # Where `Send + Sync` does appear
//!
//! [`SharedTransport`] and [`SharedTimer`], which a facade writes at its
//! own use site to hold these behind an `Arc` and cross a `tokio::spawn`.
//! A backend that cannot satisfy the bound is **refused at the
//! constructor** — a compile error at the line that asked — rather than
//! taxed at the seam. `hclient-rt-embassy` is that backend: `RefCell`
//! throughout, because embassy's executor is single-threaded, so an
//! embedded caller uses `Transport` directly rather than a facade.
//!
//! # The instant is erased as a question, not as a type
//!
//! [`Timer::Instant`] is `Copy + PartialOrd`, and `Copy` on a trait object
//! is not a thing. [`ErasedInstant`] answers the one question a client asks
//! of a stamp — *how long ago was this* — so the instant stays inside the
//! clock that made it and `Copy` is asked of nothing erased.
use crateError;
use crateRequestBody;
use crateTimer;
use Bytes;
use Future;
use Pin;
use ;
use Duration;
/// A response body with its type erased, as an erased transport hands back.
///
/// **Not `Send`**, so it cannot cross a `tokio::spawn`. One `BoxBody`
/// serves every backend and a browser's body holds a `dyn Stream` with no
/// auto trait, so the bound would exclude that backend rather than weaken
/// it. A caller who needs a spawnable body reaches past the facade for the
/// concrete transport's own body type.
pub type BoxBody = ;
/// An erased exchange, as [`BoxedTransport`] hands one back.
pub type BoxExchange<'a> =
;
/// An erased sleep, as [`BoxedTimer`] hands one back.
///
/// Not `Send`, for [`BoxBody`]'s reason and inseparably from it: a response
/// body holds a sleep — that is how a total timeout cuts a silent body — so
/// the two answer the same question.
pub type BoxSleep = ;
/// Erase a body, mapping its error into [`Error`] on the way.
///
/// Written here rather than taken from `http-body-util`: `hclient-core`
/// depends on `http-body` and not on the util crate, and this is a dozen
/// lines against a dependency every backend would then carry.
/// The inner body is held **already pinned**, so this needs no projection
/// and therefore no `unsafe` — `hclient-core` is `#![forbid(unsafe_code)]`,
/// and a newtype that has to project is how that gets quietly broken. The
/// cost is one allocation, on a path that is boxing anyway.
;
/// [`crate::unversioned::Transport`], with the future and the body boxed.
///
/// Implemented for every `Transport` whose error and body error convert
/// into [`Error`], which is every backend in this workspace. A backend
/// author writes nothing.
/// A transport a facade can share between threads, erased.
///
/// **The bound lives on this alias rather than at the use sites, and that
/// is a rule rather than a style.** `cargo fmt` moves a trailing comment
/// off a line it reflows and deletes one from a `where` clause outright,
/// so a `send-bound-exception` marker cannot survive on a long signature.
/// A short named type is a line fmt has no reason to touch, so every use
/// site writes `Box<SharedTransport>` and carries no marker at all.
///
/// The bound is amendment C12's criterion: one this crate chooses so a
/// caller's value reaches a facade by erasure rather than by a type
/// parameter, said at the use site and never on the trait. A backend that
/// cannot satisfy it is refused at a constructor rather than taxed at the
/// seam.
pub type SharedTransport = dyn BoxedTransport + Send + Sync; // send-bound-exception: amendment-C12
/// A moment a [`BoxedTimer`] recorded, which can be asked how long ago it
/// was and nothing else.
///
/// One method on purpose: it is what lets an erased clock exist at all.
/// See this module's own doc.
/// A stamp a [`BoxedTimer`] took, erased.
///
/// Not `Send`, for [`BoxSleep`]'s reason: the same body holds the stamp the
/// sleep was computed from.
pub type BoxInstant = ;
/// [`Timer`], with the sleep boxed and the instant behind [`ErasedInstant`].
/// A clock a facade can share between threads, erased.
///
/// [`SharedTransport`]'s reasoning, for the other seam.
pub type SharedTimer = dyn BoxedTimer + Send + Sync; // send-bound-exception: amendment-C12
/// The stamp the blanket [`BoxedTimer`] hands out: the clock and the moment
/// together, so `elapsed` is answered by the clock that took it.