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
//! The Veecle OS runtime.
//!
//! This crate contains the main building blocks for any Veecle OS application. Veecle OS applications are composed of [`Actor`]s,
//! that use the [`Reader`] and [`Writer`] types to communicate with each other within the runtime.
//!
//! This crate is meant to be used with asynchronous programming, which means that actors are expected to be async
//! functions. For example, it will be ensured that an actor does not update a value till all its readers had the
//! chance to read its latest state.
//!
//! # Example
//!
//! The following Veecle OS application consists of two actors, `PingActor` and `PongActor`, that communicate with each
//! other.
//!
//! ```rust
//! use std::convert::Infallible;
//! use std::fmt::Debug;
//!
//! use veecle_os_runtime::{Reader, Storable, Writer};
//!
//! #[derive(Debug, Clone, PartialEq, Eq, Default, Storable)]
//! pub struct Ping {
//! value: u32,
//! }
//!
//! #[derive(Debug, Clone, PartialEq, Eq, Default, Storable)]
//! pub struct Pong {
//! value: u32,
//! }
//!
//! #[veecle_os_runtime::actor]
//! async fn ping_actor(mut ping: Writer<'_, Ping>, pong: Reader<'_, Pong>) -> Infallible {
//! let mut value = 0;
//! ping.write(Ping { value }).await;
//!
//! let mut pong = pong.wait_init().await;
//! loop {
//! ping.write(Ping { value }).await;
//! value += 1;
//!
//! pong.wait_for_update().await.read(|pong| {
//! println!("Pong: {}", pong.value);
//! });
//! # // Exit the application to allow doc-tests to complete.
//! # std::process::exit(0);
//! }
//! }
//!
//! #[veecle_os_runtime::actor]
//! async fn pong_actor(mut pong: Writer<'_, Pong>, ping: Reader<'_, Ping>) -> Infallible {
//! let mut ping = ping.wait_init().await;
//! loop {
//! let ping = ping.wait_for_update().await.read_cloned();
//! println!("Ping: {}", ping.value);
//!
//! let data = Pong { value: ping.value };
//! pong.write(data).await;
//! }
//! }
//!
//! futures::executor::block_on(
//! veecle_os_runtime::execute! {
//! store: [Ping, Pong],
//! actors: [
//! PingActor,
//! PongActor,
//! ]
//! }
//! )
//! ```
//!
//! ## Output
//!
//! The expected output for this example would be a sequence of ping/pong messages like the following:
//!
//! ```shell
//! Ping: 1
//! Pong: 1
//! Ping: 2
//! Pong: 2
//! Ping: 3
//! Pong: 3
//! ...
//! ```
//!
//! ## Execution
//!
//! See how the `PongActor` waits for `Ping` to be written by the `PingActor`.
//! If that were not the behavior, we would see `Ping: 0` as the very first output, since `Ping` defaults to zero.
//! The same would happen with the `PingActor`: if it were not waiting for `Pong` updates, its immediate action after
//! writing `Ping` would be to display `Pong: 0`. Waiting for updates ensures us that only written values are read.
//!
//! On the other hand, writing always yields for other woken futures to be executed before performing the write
//! operation. The only exception is the very first write, since there is no latest value for readers to read.
extern crate std;
pub
pub
pub use ;
pub use ;
/// Internal exports for proc-macro and `macro_rules!` purposes.