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
//! How a handler talks back to the peer.
//!
//! [`CallbackExchange`] is the port a transport implements to answer the
//! server-originated requests a handler makes — sampling, elicitation, roots —
//! and [`DynExchange`] is its boxed form for the callers that need dynamic
//! dispatch. [`ExchangeError`] is what either returns when an exchange does
//! not complete.
//!
//! It lives here rather than beside the adapters that implement it because
//! these are port traits and a port belongs to its consumer. The consumer is
//! [`PeerSession`](super::context::PeerSession), which hands one to every
//! request; a transport's `impl` should be written against the shape that
//! consumer asked for, and reading the consumer and the port in one file is
//! what makes that check possible.
use crateJsonObject;
/// Why a server-initiated request could not complete.
///
/// Distinct from [`GatedError`](super::error::GatedError): the gate already
/// passed by the time an exchange runs, so this is the transport or the peer
/// failing rather than the capability being absent. They are separate types
/// because a handler that sees one should retry and a handler that sees the
/// other should not.
/// A round trip to the peer that a server-initiated request needs.
///
/// The port belongs to the consumer. It is declared here rather than in an
/// adapter because the shape of what a server needs to ask a peer is a decision
/// this module makes: a method name, a params object, and an answer back. A
/// transport implements it; nothing in `adapters/` defines it.
///
/// Not object-safe by design — it is an RPITIT `async fn`, so a caller that
/// knows its concrete exchange gets it inlined with no allocation. Callers that
/// genuinely need a boxed one get [`DynExchange`].
/// The boxed spelling of [`CallbackExchange`], for a caller holding a transport
/// of unknown concrete type.
///
/// # Examples
///
/// ```
/// use std::sync::Arc;
///
/// use protocol_droid::application::server::context::{DynExchange, ExchangeError};
/// use protocol_droid::domain::ir::JsonObject;
///
/// let exchange: Arc<dyn DynExchange> = Arc::new(MyExchange);
/// // ...handed to a PeerSession, which calls it through the trait object.
/// # struct MyExchange;
/// # impl DynExchange for MyExchange {
/// # fn exchange_boxed<'a>(&'a self, method: &'a str, params: &'a JsonObject)
/// # -> std::pin::Pin<Box<dyn Future<Output = Result<JsonObject, ExchangeError>> + Send + 'a>>
/// # { Box::pin(async move { let _ = (method, params); Err(ExchangeError::new("unimplemented")) }) }
/// # }
/// ```