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
//! The traits a generated face implements: the fixed methods of the
//! consumer and provider faces the Rust backend emits (ADR-0023 decision 7,
//! ADR-0021 decision 19).
//!
//! A generated `Client` or `Publisher` has two kinds of method. A member
//! method is derived from the interface — one per signal, event, command and
//! query, named after the member — and is an inherent method of the type. A
//! fixed method is the emitter's own — `new`, `next_event`, `with_timeout`,
//! `set_timeout`, `commit` — and is a method of one of the four traits here.
//! Rust gives one type one inherent namespace, so a member whose snake case
//! is `new` or `commit` could not sit beside a fixed inherent method of that
//! name (rustc E0592); a trait method lives in the trait's namespace, so the
//! member and the fixed method coexist, and the fixed method stays reachable
//! through the trait's path. The two derived methods a face adds beside a
//! member — `subscribe_<event>` and `invalidate_<signal>` — are methods of
//! two traits the emitter generates inside each interface module,
//! `Subscribe` and `Invalidate`, for the same reason.
//!
//! Which of the two a dot call reaches follows Rust's method probe: it tries
//! the receiver by value, then by `&`, then by `&mut`, and at each step an
//! inherent method before a trait method. A member takes `&self` (a signal
//! read) or `&mut self` (every other member); [`Bind::new`] takes no receiver
//! and is reached by a path call, and every other trait method here takes
//! `&mut self` except [`Timeout::with_timeout`], which takes `self` by value.
//! So the member keeps the dot call for every fixed and derived method but
//! `with_timeout`: beside a member named `withTimeout`,
//! `client.with_timeout(x)` on a blocking client held by value reaches the
//! trait method, because the by-value step comes first, and the consumer
//! reaches the member through the inherent path
//! `blocking::Client::with_timeout(&mut client, x)` (`&client` for a signal
//! read). `with_timeout` takes `self` so that
//! `Client::new(port).with_timeout(t)` stays one expression.
//!
//! A consumer of a generated face writes `use <crate>::<iface>::prelude::*;`
//! for each interface whose face it uses: the generated `prelude` re-exports
//! the traits here that the interface's types implement, and the interface's
//! two generated traits as `_`. rustc reports a prelude as an unused import
//! when the other imported preludes already bring every item it would add,
//! and that import can then be dropped. With the
//! prelude in scope every call site is the one an inherent method had —
//! `Client::new(port)`, `client.next_event()`, `publisher.commit()`. Only
//! when a member of the interface is itself named `new` does
//! `Client::new(port)` resolve to the member, because a path call finds an
//! inherent item first; the consumer then writes
//! `<Client<_> as Bind>::new(port)` or `let c: Client<_> = Bind::new(port)`.
//!
//! [`Timeout`] is under the `std` feature, because its only implementor is
//! the generated `blocking` module, which the emitted crate's `std` feature
//! enables together with this crate's. The other three traits are
//! unconditional and `no_std`, like the rest of the crate. Nothing here is
//! implemented by a runtime: a runtime implements the [`port`](crate::port)
//! traits, and generated code implements these.
/// Binds a face to the port it holds: the `new` of a generated `Client`,
/// `blocking::Client` and `Publisher`.
///
/// `Port` is the type the face is generic over — a runtime's handle, or a
/// `&mut` borrow of one — and `new` holds it by value.
///
/// ```
/// use ridl_rt::face::Bind;
///
/// struct Client<P> { port: P }
/// impl<P> Bind for Client<P> {
/// type Port = P;
/// fn new(port: P) -> Self { Client { port } }
/// }
///
/// let client = Client::new(7u32);
/// assert_eq!(client.port, 7);
/// ```
/// Takes the next occurrence of a subscribed event: the `next_event` of a
/// generated `Client` and `blocking::Client`.
///
/// `Next` is generic over the borrow of `self`, so one trait serves both
/// clients: the async client's `Next<'a>` is its event future, which borrows
/// the client's port, and the blocking client's is the owned
/// `Result<Option<Event>, ReadError>`. The trait gives the method a namespace
/// of its own and nothing more: `Next` carries no bound, so code generic over
/// `Events` cannot use what `next_event` returns.
///
/// ```
/// use ridl_rt::face::Events;
///
/// struct Client { queue: Vec<u8> }
/// impl Events for Client {
/// type Next<'a> = Option<u8> where Self: 'a;
/// fn next_event(&mut self) -> Option<u8> { self.queue.pop() }
/// }
///
/// let mut client = Client { queue: vec![1] };
/// assert_eq!(client.next_event(), Some(1));
/// assert_eq!(client.next_event(), None);
/// ```
/// Bounds every waiting method of a blocking face by a wall-clock timeout:
/// the `with_timeout` and `set_timeout` of a generated `blocking::Client`.
///
/// The timeout is `None` until one of the two sets it; with none, a waiting
/// method returns only with its outcome. `core::time::Duration` is the type
/// `std::time::Duration` re-exports, so a consumer passes either.
///
/// ```
/// use core::time::Duration;
/// use ridl_rt::face::Timeout;
///
/// struct Client { timeout: Option<Duration> }
/// impl Timeout for Client {
/// fn with_timeout(mut self, timeout: Duration) -> Self {
/// self.timeout = Some(timeout);
/// self
/// }
/// fn set_timeout(&mut self, timeout: Option<Duration>) { self.timeout = timeout; }
/// }
///
/// let mut client = Client { timeout: None }.with_timeout(Duration::from_millis(5));
/// assert_eq!(client.timeout, Some(Duration::from_millis(5)));
/// client.set_timeout(None);
/// assert_eq!(client.timeout, None);
/// ```
/// Publishes every staged signal change: the `commit` of a generated
/// `Publisher`.
///
/// ```
/// use ridl_rt::face::Publish;
///
/// struct Publisher { staged: u8, published: u8 }
/// impl Publish for Publisher {
/// fn commit(&mut self) { self.published = self.staged; }
/// }
///
/// let mut publisher = Publisher { staged: 3, published: 0 };
/// publisher.commit();
/// assert_eq!(publisher.published, 3);
/// ```