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
//! Model components.
//!
//! # Model trait
//!
//! Every model must implement the [`Model`] trait. This trait defines an
//! asynchronous initialization method, [`Model::init()`], which main purpose is
//! to enable models to perform specific actions only once all models have been
//! connected and migrated to the simulation, but before the simulation actually
//! starts.
//!
//! #### Examples
//!
//! A model that does not require initialization can simply use the default
//! implementation of the `Model` trait:
//!
//! ```
//! use asynchronix::model::Model;
//!
//! pub struct MyModel {
//! // ...
//! }
//! impl Model for MyModel {}
//! ```
//!
//! Otherwise, a custom `init()` method can be implemented:
//!
//! ```
//! use std::future::Future;
//! use std::pin::Pin;
//!
//! use asynchronix::model::{InitializedModel, Model};
//! use asynchronix::time::Scheduler;
//!
//! pub struct MyModel {
//! // ...
//! }
//! impl Model for MyModel {
//! fn init(
//! mut self,
//! scheduler: &Scheduler<Self>
//! ) -> Pin<Box<dyn Future<Output = InitializedModel<Self>> + Send + '_>>{
//! Box::pin(async move {
//! println!("...initialization...");
//!
//! self.into()
//! })
//! }
//! }
//! ```
//!
//! # Events and queries
//!
//! Models can exchange data via *events* and *queries*.
//!
//! Events are send-and-forget messages that can be broadcast from an *output
//! port* to an arbitrary number of *input ports* with a matching event type.
//!
//! Queries actually involve two messages: a *request* that can be broadcast
//! from a *requestor port* to an arbitrary number of *replier ports* with a
//! matching request type, and a *reply* sent in response to such request. The
//! response received by a requestor port is an iterator that yields as many
//! items (replies) as there are connected replier ports.
//!
//!
//! ### Output and requestor ports
//!
//! Output and requestor ports can be added to a model using composition, adding
//! [`Output`] and [`Requestor`] objects as members. They are parametrized by
//! the event, request and reply types.
//!
//! Models are expected to expose their output and requestor ports as public
//! members so they can be connected to input and replier ports when assembling
//! the simulation bench.
//!
//! #### Example
//!
//! ```
//! use asynchronix::model::{Model, Output, Requestor};
//!
//! pub struct MyModel {
//! pub my_output: Output<String>,
//! pub my_requestor: Requestor<u32, bool>,
//! }
//! impl MyModel {
//! // ...
//! }
//! impl Model for MyModel {}
//! ```
//!
//!
//! ### Input and replier ports
//!
//! Input ports and replier ports are methods that implement the [`InputFn`] or
//! [`ReplierFn`] traits with appropriate bounds on their argument and return
//! types.
//!
//! In practice, an input port method for an event of type `T` may have any of
//! the following signatures, where the futures returned by the `async` variants
//! must implement `Send`:
//!
//! ```ignore
//! fn(&mut self) // argument elided, implies `T=()`
//! fn(&mut self, T)
//! fn(&mut self, T, &Scheduler<Self>)
//! async fn(&mut self) // argument elided, implies `T=()`
//! async fn(&mut self, T)
//! async fn(&mut self, T, &Scheduler<Self>)
//! where
//! Self: Model,
//! T: Clone + Send + 'static,
//! R: Send + 'static,
//! ```
//!
//! The scheduler argument is useful for methods that need access to the
//! simulation time or that need to schedule an action at a future date.
//!
//! A replier port for a request of type `T` with a reply of type `R` may in
//! turn have any of the following signatures, where the futures must implement
//! `Send`:
//!
//! ```ignore
//! async fn(&mut self) -> R // argument elided, implies `T=()`
//! async fn(&mut self, T) -> R
//! async fn(&mut self, T, &Scheduler<Self>) -> R
//! where
//! Self: Model,
//! T: Clone + Send + 'static,
//! R: Send + 'static,
//! ```
//!
//! Output and replier ports will normally be exposed as public methods so they
//! can be connected to input and requestor ports when assembling the simulation
//! bench. However, input ports may instead be defined as private methods if
//! they are only used by the model itself to schedule future actions (see the
//! [`Scheduler`](crate::time::Scheduler) examples).
//!
//! Changing the signature of an input or replier port is not considered to
//! alter the public interface of a model provided that the event, request and
//! reply types remain the same.
//!
//! #### Example
//!
//! ```
//! use asynchronix::model::Model;
//! use asynchronix::time::Scheduler;
//!
//! pub struct MyModel {
//! // ...
//! }
//! impl MyModel {
//! pub fn my_input(&mut self, input: String, scheduler: &Scheduler<Self>) {
//! // ...
//! }
//! pub async fn my_replier(&mut self, request: u32) -> bool { // scheduler argument elided
//! // ...
//! # unimplemented!()
//! }
//! }
//! impl Model for MyModel {}
//! ```
//!
use Future;
use Pin;
use crateScheduler;
pub use ;
pub use ;
/// Trait to be implemented by all models.
///
/// This trait enables models to perform specific actions in the
/// [`Model::init()`] method only once all models have been connected and
/// migrated to the simulation bench, but before the simulation actually starts.
/// A common use for `init` is to send messages to connected models at the
/// beginning of the simulation.
///
/// The `init` function converts the model to the opaque `InitializedModel` type
/// to prevent an already initialized model from being added to the simulation
/// bench.
/// Opaque type containing an initialized model.
///
/// A model can be converted to an `InitializedModel` using the `Into`/`From`
/// traits. The implementation of the simulation guarantees that the
/// [`Model::init()`] method will never be called on a model after conversion to
/// an `InitializedModel`.
M);