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
#![forbid(unsafe_code)]
#![forbid(warnings)]
#![forbid(missing_docs)]
//! GhostActor makes it simple, ergonomic, and idiomatic to implement
//! async / concurrent code using an Actor model.
//!
//! GhostActor uses only safe code, and is futures executor agnostic--use
//! tokio, futures, async-std, whatever you want. The following examples use
//! tokio.
//!
//! # What does it do?
//!
//! The GhostActor struct is a `'static + Send + Sync` cheaply clone-able
//! handle for managing rapid, efficient, sequential, mutable access to
//! internal state data.
//!
//! # Using the raw type:
//!
//! ```
//! # use ghost_actor::*;
//! # #[tokio::main]
//! # async fn main() {
//! // set our initial state
//! let (a, driver) = GhostActor::new(42_u32);
//!
//! // spawn the driver--using tokio here as an example
//! tokio::task::spawn(driver);
//!
//! // invoke some logic on the internal state (just reading here)
//! let result: Result<u32, GhostError> = a.invoke(|a| Ok(*a)).await;
//!
//! // assert the result
//! assert_eq!(42, result.unwrap());
//! # }
//! ```
//!
//! # Best Practice: Internal state in a New Type:
//!
//! GhostActor is easiest to work with when you have an internal state struct,
//! wrapped in a new type of a GhostActor:
//!
//! ```
//! # use ghost_actor::*;
//! # #[tokio::main]
//! # async fn main() {
//! struct InnerState {
//!     age: u32,
//!     name: String,
//! }
//!
//! #[derive(Clone, PartialEq, Eq, Hash)]
//! pub struct Person(GhostActor<InnerState>);
//!
//! impl Person {
//!     pub fn new(age: u32, name: String) -> Self {
//!         let (actor, driver) = GhostActor::new(InnerState { age, name });
//!         tokio::task::spawn(driver);
//!         Self(actor)
//!     }
//!
//!     pub async fn birthday(&self) -> String {
//!         self.0.invoke(|inner| {
//!             inner.age += 1;
//!             let msg = format!(
//!                 "Happy birthday {}, you are {} years old.",
//!                 inner.name,
//!                 inner.age,
//!             );
//!             <Result::<String, GhostError>>::Ok(msg)
//!         }).await.unwrap()
//!     }
//! }
//!
//! let bob = Person::new(42, "Bob".to_string());
//! assert_eq!(
//!     "Happy birthday Bob, you are 43 years old.",
//!     &bob.birthday().await,
//! );
//! # }
//! ```
//!
//! # Using traits (and GhostFuture) to provide dynamic actor types:
//!
//! ```
//! # use ghost_actor::*;
//! # #[tokio::main]
//! # async fn main() {
//! pub trait Fruit {
//!     // until async traits are available in rust, you can use GhostFuture
//!     fn eat(&self) -> GhostFuture<String, GhostError>;
//!
//!     // allows implementing clone on BoxFruit
//!     fn box_clone(&self) -> BoxFruit;
//! }
//!
//! pub type BoxFruit = Box<dyn Fruit>;
//!
//! impl Clone for BoxFruit {
//!     fn clone(&self) -> Self {
//!         self.box_clone()
//!     }
//! }
//!
//! #[derive(Clone, PartialEq, Eq, Hash)]
//! pub struct Banana(GhostActor<u32>);
//!
//! impl Banana {
//!     pub fn new() -> BoxFruit {
//!         let (actor, driver) = GhostActor::new(0);
//!         tokio::task::spawn(driver);
//!         Box::new(Self(actor))
//!     }
//! }
//!
//! impl Fruit for Banana {
//!     fn eat(&self) -> GhostFuture<String, GhostError> {
//!         let fut = self.0.invoke(|count| {
//!             *count += 1;
//!             <Result<u32, GhostError>>::Ok(*count)
//!         });
//!
//!         // 'resp()' is a helper function that builds a GhostFuture
//!         // from any other future that has a matching Output.
//!         resp(async move {
//!             Ok(format!("ate {} bananas", fut.await.unwrap()))
//!         })
//!     }
//!
//!     fn box_clone(&self) -> BoxFruit {
//!         Box::new(self.clone())
//!     }
//! }
//!
//! // we could implement a similar 'Apple' struct
//! // that could be interchanged here:
//! let fruit: BoxFruit = Banana::new();
//! assert_eq!("ate 1 bananas", &fruit.eat().await.unwrap());
//! # }
//! ```
//!
//! # Custom GhostActor error types:
//!
//! The `GhostActor::invoke()` function takes a generic error type.
//! The only requirement is that it must implement `From<GhostError>`:
//!
//! ```
//! # use ghost_actor::*;
//! # #[tokio::main]
//! # async fn main() {
//! #[derive(Debug)]
//! struct MyError;
//! impl std::error::Error for MyError {}
//! impl std::fmt::Display for MyError {
//!     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
//!         write!(f, "{:?}", self)
//!     }
//! }
//! impl From<GhostError> for MyError {
//!     fn from(_: GhostError) -> Self {
//!         Self
//!     }
//! }
//!
//! let (actor, driver) = GhostActor::new(42_u32);
//! tokio::task::spawn(driver);
//! assert_eq!(42, actor.invoke(|inner| {
//!     <Result<u32, MyError>>::Ok(*inner)
//! }).await.unwrap());
//! # }
//! ```
//!
//! # Code Examples:
//!
//! - [Bounce](https://github.com/holochain/ghost_actor/blob/master/examples/bounce.rs): `cargo run --example bounce`
//!
//! # Contributing:
//!
//! This repo uses `cargo-task`.
//!
//! ```ignore
//! cargo install cargo-task
//! cargo task
//! ```

/// Re-exported dependencies.
pub mod dependencies {
    pub use futures;
    pub use tracing;
}

mod error;
pub use error::*;
mod as_ghost_actor;
use as_ghost_actor::ghost_actor_trait::*;
pub use as_ghost_actor::*;
mod driver;
pub use driver::*;
mod future;
pub use future::*;
mod config;
pub use config::*;
mod actor;
pub use actor::*;

#[cfg(test)]
mod test;