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
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
//! The inbound edge: a stream of whole frames from a peer.
//!
//! # Why this trait exists
//!
//! [`FrameSink`](crate::application::session::frame_sink::FrameSink) already covers the outbound half, and it lives in
//! [`crate::application::session`] because the session engine is what consumes
//! it. The inbound half has a different consumer — the loop that reads a frame
//! and routes it — and by the project's rule that a port trait belongs to the
//! consumer, that puts this one here rather than beside its sibling. Two
//! transports facing opposite directions are not one capability, and a shared
//! `ports` module would have implied they were.
//!
//! It is deliberately not a `Transport` trait. A trait that both read and wrote
//! would force every implementor to answer for both, which is exactly the
//! "three adapters wearing one name" objection that
//! [`FrameSink`](crate::application::session::frame_sink::FrameSink) is documented against.
//! The stdio server writes to a child it spawned and reads from the same pipe;
//! the bridge reads from an HTTP body and writes to stdio; a replay source only
//! reads at all.
//!
//! # What it hides
//!
//! Chunking. An implementor is given no way to express "I have half a message",
//! and cannot: whatever a read returns goes into a
//! [`FrameDecoder`](crate::domain::FrameDecoder), and a frame comes out when it
//! is complete. A caller of this trait never sees a partial line, never has to
//! know that a read boundary can fall inside a UTF-8 character, and never has to
//! know what the ceiling is — although the implementor does, and is the one that
//! must set it.
//!
//! # The distinction this trait has to be careful about
//!
//! `Ok(None)` means **the peer closed**, and nothing else. It does not mean "no
//! frame is ready". The decoder underneath answers `None` for exactly that
//! second thing, so the two meanings are opposites and an implementor that
//! forwards the decoder's answer straight up has inverted them. An implementor
//! awaits more bytes instead; this method resolves only on a complete frame, an
//! end of stream, or a failure, and a caller can therefore treat `None` as "the
//! session is over" without also having to ask whether anything was pending.
//!
//! # Two traits, because one of them cannot be both
//!
//! [`FrameSource`] is a native `async fn`, which is a return-position impl trait
//! and therefore **not** object-safe. A dispatch loop that is generic over its
//! source takes `impl FrameSource` and the call monomorphises to nothing. The
//! CLI bridge, which holds a source of an unknown concrete type behind one
//! handle, needs `Arc<dyn DynFrameSource>` and cannot have it from this trait.
//!
//! [`DynFrameSource`] is the object-safe spelling, written out by hand. A
//! blanket impl with `async-trait` would put a boxed future on the generic path
//! too, and one allocation per inbound frame is what the generic form exists to
//! avoid. The box is confined to the callers that asked for it.
//!
//! # Examples
//!
//! ```
//! use std::sync::Arc;
//!
//! use protocol_droid::application::jsonrpc::{DynFrameSource, FrameSource, SourceError};
//! use protocol_droid::domain::{FrameDecoder, MaxFrameSize};
//!
//! /// A source backed by a fixed buffer: everything a read would have produced.
//! struct Replay {
//! decoder: std::sync::Mutex<FrameDecoder>,
//! }
//!
//! impl Replay {
//! fn new(wire: &[u8]) -> Self {
//! let mut decoder = FrameDecoder::new(MaxFrameSize::DEFAULT);
//! // A test's fixture is trusted, so a refusal here is the fixture's
//! // problem and is ignored rather than unwrapped. A real implementor
//! // would have nowhere to put the error either — it has no frame to
//! // report it against — and would surface it on the first `next_frame`.
//! let _ = decoder.push(wire);
//! Self {
//! decoder: std::sync::Mutex::new(decoder),
//! }
//! }
//! }
//!
//! impl FrameSource for Replay {
//! async fn next_frame(&self) -> Result<Option<String>, SourceError> {
//! let mut decoder = self.decoder.lock().map_err(|_| SourceError::Transport)?;
//! decoder
//! .next_frame()
//! .map(|frame| frame.map(str::to_owned))
//! .map_err(SourceError::from)
//! }
//! }
//!
//! let runtime = tokio::runtime::Builder::new_current_thread()
//! .build()
//! .map_err(|error| error.to_string())?;
//!
//! // The generic form: the dispatch loop is written once and monomorphises.
//! let generic = Replay::new(b"{\"jsonrpc\":\"2.0\"}\n");
//! assert_eq!(
//! runtime.block_on(FrameSource::next_frame(&generic)),
//! Ok(Some(String::from("{\"jsonrpc\":\"2.0\"}")))
//! );
//!
//! // The boxed form: the same implementation, behind a trait object.
//! let boxed: Arc<dyn DynFrameSource> = Arc::new(Replay::new(b"{\"id\":1}\n"));
//! assert_eq!(
//! runtime.block_on(boxed.next_frame()),
//! Ok(Some(String::from("{\"id\":1}")))
//! );
//! # Ok::<(), String>(())
//! ```
use Future;
use Pin;
use Error;
use crateFramingError;
/// An inbound frame stream from a peer.
///
/// A stream of whole frames, protocol-neutral: nothing here names a method, a
/// revision, or a message kind, because routing a frame to a method is the next
/// layer's job and the next layer is the one that knows the protocol.
///
/// Implemented by a transport. Consumed by the loop that routes. One method, for
/// the same reason [`FrameSink`](crate::application::session::frame_sink::FrameSink) has
/// one.
///
/// # Examples
///
/// ```
/// use protocol_droid::application::jsonrpc::{FrameSource, SourceError};
///
/// /// A source with nothing behind it, which reports a closed stream at once.
/// struct Closed;
///
/// impl FrameSource for Closed {
/// async fn next_frame(&self) -> Result<Option<String>, SourceError> {
/// Ok(None)
/// }
/// }
/// ```
/// A [`FrameSource`] that can sit behind a trait object.
///
/// The hand-written spelling of the same method, and the only reason
/// [`FrameSource`] does not use `async-trait`: the box belongs to the callers
/// that need dynamic dispatch, not to the ones that do not.
/// Why the next inbound frame did not arrive.
///
/// Domain types only. An adapter maps its own `io::Error` into
/// [`Transport`](Self::Transport) at the boundary, so nothing in `application/`
/// names a type from a runtime or from the operating system.