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
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
//! A small and lightweight crate to hide most of the burden of setting up long-living threads.
//!
//! # Philosophy
//!
//! This crate sees threads as unique entities called [`Workers`] which may (or may not) live as long as the program lives. [`Workers`] are spawned in [`Runtimes`] that manage them.
//!
//! [`Runtimes`]: crate::Runtime
//! [`Workers`]: crate::Worker
//!
//! # Usage
//!
//! Here's a small example that spawns a worker that prints "Hello, World!" every 100ms for 1 second.
//!
//! ```
//! # use employees::{Runtime, Worker, ControlFlow};
//! # use std::time::Duration;
//! struct WorkerThatPrints;
//! impl Worker for WorkerThatPrints {
//! fn on_update(&mut self) -> ControlFlow {
//! println!("Hello, World!");
//! std::thread::sleep(Duration::from_millis(100));
//! ControlFlow::Continue
//! }
//! }
//!
//! let mut runtime = Runtime::new();
//!
//! runtime.launch(WorkerThatPrints);
//! std::thread::sleep(Duration::from_secs(1));
//! ```
//!
//! # Features
//!
//! [`Runtimes`] and [`Workers`] comes with a set of various features and helpers to setup and run them.
//!
//! [`Runtimes`]: crate::Runtime
//! [`Workers`]: crate::Worker
//!
//! ## Runtimes and non-`'static` things
//!
//! [`Runtimes`] need `'static` lifetimes, therefore the following example won't compile.
//!
//! [`Runtimes`]: crate::Runtime
//!
//! ```compile_fail
//! # use employees::{Runtime, Worker, ControlFlow};
//! struct WorkerThatPrints<'a>(&'a str);
//! impl Worker for WorkerThatPrints<'_> {
//! fn on_update(&mut self) -> ControlFlow {
//! println!("Hello, {}!", self.0);
//! ControlFlow::Continue
//! }
//! }
//!
//! let name = String::from("Alice");
//! let worker = WorkerThatPrints(&name);
//!
//! let mut runtime = Runtime::new();
//! runtime.launch(worker); // worker isn't 'static!
//! ```
//!
//! Fortunately, this crate provides [`ScopedRuntimes`]. They are a 1 to 1 implementation of classic [`Runtimes`] except that they need a scope.
//!
//! [`Runtimes`]: crate::Runtime
//! [`ScopedRuntimes`]: crate::ScopedRuntime
//!
//! ```
//! # use employees::{ScopedRuntime, Worker, ControlFlow};
//! # struct WorkerThatPrints<'a>(&'a str);
//! # impl Worker for WorkerThatPrints<'_> {
//! # fn on_update(&mut self) -> ControlFlow {
//! # println!("Hello, {}!", self.0);
//! # ControlFlow::Break
//! # }
//! # }
//! let name = String::from("Alice");
//! let worker = WorkerThatPrints(&name);
//!
//! std::thread::scope(|scope| {
//! // Let's create a scoped runtime
//! let mut runtime = ScopedRuntime::new(scope);
//!
//! runtime.launch(worker); // Now, that works!
//! })
//! ```
//!
//! ## Configuring the threads
//!
//! Workers threads can be configured via the [`Settings`] type with users can use it to set a thread's stack size and name.
//! Then, by passing the settings alongside the actor using the [`Runtime::launch_with_settings`] function, the thread will
//! be spawned with the specified settings.
//!
//! Users can also set the thread's affinity by passing a list of CPU IDs to the [`Runtime::launch_pinned`] function.
//!
//! The [`Runtime::launch_pinned_with_settings`] can do both.
//!
//! ```
//! # use employees::{Runtime, Worker, ControlFlow, Settings};
//! # struct WorkerThatPrints;
//! # impl Worker for WorkerThatPrints {
//! # fn on_update(&mut self) -> ControlFlow {
//! # println!("Hello, World!");
//! # ControlFlow::Break
//! # }
//! # }
//! let mut runtime = Runtime::new();
//! let settings = Settings::new().name("worker");
//!
//! // The thread will be named "worker" and pinned to the CPUs #0 and #1
//! runtime.launch_pinned_with_settings(WorkerThatPrints, [0,1], settings);
//! ```
//!
//! ## Contextes
//!
//! Users may want to configure their workers via a builder pattern before spawning them in a runtime,
//! somewhat like how the [`std::process::Command`] type works. This can be done easily giving a type that implements
//! the [`Context`] trait to the [`Runtime::launch_from_context`] function. Contextes also provide thread settings.
//!
//! ```
//! # use employees::{Runtime, Worker, ControlFlow, Settings, Context, Error};
//! # struct WorkerThatPrints(String);
//! # impl Worker for WorkerThatPrints {
//! # fn on_update(&mut self) -> ControlFlow {
//! # println!("Hello, {}!", self.0);
//! # ControlFlow::Break
//! # }
//! # }
//! struct WorkerContext {
//! name: String
//! }
//!
//! impl Context for WorkerContext {
//! type Target = WorkerThatPrints;
//!
//! fn into_worker(self) -> Result<Self::Target, Error> {
//! Ok(WorkerThatPrints(self.name))
//! }
//!
//! fn settings(&self) -> Settings {
//! Settings::new().name("worker")
//! }
//!
//! fn core_pinning(&self) -> Option<Vec<usize>> {
//! Some(vec![0,1])
//! }
//! }
//!
//! let mut runtime = Runtime::new();
//! let context = WorkerContext { name: String::from("Alice") };
//!
//! runtime.launch_from_context(context);
//! ```
//!
//! ## Respawning workers that panicked
//!
//! The runtimes allow respawning workers that panicked. This can be achieved by implementing the [`RespawnableContext`] trait
//! for a type a passing that type to the [`Runtime::launch_respawnable`] function.
//!
//! By calling the [`Runtime::health_check`] function, a runtime will check every respawnable workers that panicked and will respawn
//! it using their respective contextes.
//!
//! ```
//! # use employees::{Runtime, Worker, ControlFlow, RespawnableContext, Error};
//! # use std::time::Duration;
//! // A worker that panic some time after being spawned...
//! struct PanickingWorker;
//! impl Worker for PanickingWorker {
//! fn on_update(&mut self) -> ControlFlow {
//! std::thread::sleep(Duration::from_secs(1));
//! panic!("panicking!")
//! }
//! }
//!
//! // ... and its context.
//! struct WorkerContext;
//! impl RespawnableContext<'_> for WorkerContext {
//! fn boxed_worker(&self) -> Result<Box<dyn Worker>, Error> {
//! Ok(Box::new(PanickingWorker))
//! }
//! }
//!
//! let mut runtime = Runtime::new();
//! runtime.launch_respawnable(WorkerContext);
//!
//! std::thread::sleep(Duration::from_secs(1));
//! runtime.health_check();
//! # std::thread::sleep(Duration::from_millis(500));
//! ```
//!
//! ## Inter-workers communication
//!
//! This crate exposes two traits, [`Register`] and [`Connect`], enabling the communication between two workers.
//! Those traits are channel agnostics and direction: virtually anything that can send or receive data or share states
//! can be used as a [`Register::Endpoint`].
//!
//! ```
//! # use std::sync::mpsc::{self, Sender, Receiver};
//! # use employees::{Runtime, Worker, ControlFlow, Error, Register, Connect};
//! # use std::time::Duration;
//! // A producer worker.
//! #[derive(Default)]
//! struct Producer {
//! sender: Option<Sender<u8>>,
//! }
//!
//! impl Worker for Producer {
//! fn on_update(&mut self) -> ControlFlow {
//! std::thread::sleep(Duration::from_millis(100));
//!
//! if let Some(sender) = self.sender.as_ref() {
//! sender.send(1).unwrap();
//! }
//!
//! ControlFlow::Continue
//! }
//! }
//!
//! impl Connect<Consumer> for Producer {
//! fn on_connection(&mut self, endpoint: Sender<u8>) {
//! self.sender = Some(endpoint)
//! }
//! }
//!
//! // A consumer worker
//! struct Consumer {
//! sender: Sender<u8>,
//! recver: Receiver<u8>,
//! count: u8,
//! }
//!
//! impl Consumer {
//! fn new() -> Self {
//! let (sender, recver) = mpsc::channel();
//!
//! Self {
//! sender,
//! recver,
//! count: 0,
//! }
//! }
//! }
//!
//! impl Worker for Consumer {
//! fn on_update(&mut self) -> ControlFlow {
//! let val = self.recver.recv().unwrap();
//!
//! self.count += val;
//! ControlFlow::Continue
//! }
//! }
//!
//! impl Register for Consumer {
//! type Endpoint = Sender<u8>;
//!
//! fn register(&mut self, other: &mut impl Connect<Self>) {
//! other.on_connection(self.sender.clone())
//! }
//! }
//!
//! let mut consumer = Consumer::new();
//! let mut prod1 = Producer::default();
//! let mut prod2 = Producer::default();
//! let mut prod3 = Producer::default();
//!
//! // Let's connect everything
//! consumer.register(&mut prod1);
//! consumer.register(&mut prod2);
//! consumer.register(&mut prod3);
//!
//! // Launch the workers in a runtime
//! let mut runtime = Runtime::new();
//! runtime.launch(consumer);
//! runtime.launch(prod1);
//! runtime.launch(prod2);
//! runtime.launch(prod3);
//!
//! # std::thread::sleep(Duration::from_secs(1));
//! ```
//!
//! ## Timers
//!
//! This crate re-exports all types from the [`minuteurs`] crate and implements the [`Worker`] and [`Register`] traits on
//! the [`Timer`] type, allowing it to be used in runtimes.
//!
//! Requires the `timing` feature.
//!
//! [`minuteurs`]: <https://docs.rs/minuteurs/latest/minuteurs/>
//! [`Timer`]: <https://docs.rs/minuteurs/latest/minuteurs/struct.Timer.html>
//!
//! # use std::time::Duration;
//! use employees::{Runtime, Worker, ControlFlow, Error, Register, Connect, Context};
//! use employees::minuteurs::{Timer, Watcher};
//!
//! // A worker that prints "Hello!" each times the timer ticks...
//! struct WorkerThatPrints {
//! watcher: Watcher,
//! }
//!
//! impl Worker for WorkerThatPrints {
//! fn on_update(&mut self) -> ControlFlow {
//! if self.watcher.has_ticked() {
//! println!("Hello!");
//! }
//!
//! # std::thread::sleep(Duration::from_millis(1));
//! ControlFlow::Continue
//! }
//! }
//!
//! // ... and its context.
//! struct WorkerThatPrintsContext {
//! watcher: Option<Watcher>,
//! }
//!
//! impl WorkerThatPrintsContext {
//! fn new() -> Self {
//! Self { watcher: None }
//! }
//! }
//!
//! impl Context for WorkerThatPrintsContext {
//! type Target = WorkerThatPrints;
//! fn into_worker(self) -> Result<Self::Target, Error> {
//! Ok(WorkerThatPrints { watcher: self.watcher.expect("the context must be connected") })
//! }
//! }
//!
//! impl Connect<Timer> for WorkerThatPrintsContext {
//! fn on_connection(&mut self, endpoint: Watcher) {
//! let _ = self.watcher.insert(endpoint);
//! }
//! }
//!
//! let mut runtime = Runtime::new();
//!
//! // Set a timer that ticks every 100ms
//! let mut timer = Timer::new(Duration::from_millis(100));
//! let mut worker_ctx = WorkerThatPrintsContext::new();
//!
//! // Connect the worker (or rather, its context) to the timer
//! timer.register(&mut worker_ctx);
//!
//! runtime.launch(timer).expect("failed to launch the timer");
//! runtime.launch_from_context(worker_ctx).expect("failed to launch the worker");
//!
//! # std::thread::sleep(Duration::from_secs(1));
//! ```
pub use minuteurs;
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;
pub use *;