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
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
//! Actor based asynchronous runtime
//!
//! # Table of Contents
//! 1. [Introduction](#introduction)
//! 2. [Perspective features](#perspective-features)
//! 3. [Architecture elements](#architecture-elements)
//! 4. [Basic operations](#basic-operations)
//! 5. [Lifetime hooks](#lifetime-hooks)
//! 6. [Stopping actors](#stopping-actors)
//! 7. [Actor communications](#actor-communications)
//! 8. [ActorRef sharing](#actorref-sharing)
//! 9. [More about DeadLetters](#more-about-deadletters)
//!
//! # Introduction
//! This runtime is realize the classical actor paradigm actively used in the actor based languages,
//! such as Erlang and actors framework, such as Akka. To be frank, this module is heavily relies on
//! the last and actively use principles and abstractions submitted in this framework.
//!
//! At this moment, module presents next features:
//! * Untyped actors with exchanged the messages derived from Any trait
//! * Actor lifetime management
//! * DeadLetters
//!
//! # Perspective features:
//! Under this features already exists architectural basis, and their implementation is a question
//! of my free time.
//!
//! * Mailboxes with user defined functional
//! * Various dispatchers realizations
//! * Watching
//! * Supervising
//! * Timers
//! * FSM
//! * TestKit
//!
//! # Architecture elements
//!
//! Before we go to the concrete examples of usage, you mast understand the internal architecture of
//! the actors runtime. Without this, you will do not understand many of errors which may cause at
//! work with the library and it will be seems for you as bags, but it's doesn't.
//!
//! Actor runtime contains three big elements:
//! * Runtime - contains objects used of actor at execution
//! * System -  environment of actors representation . Controls actors lifetime (start, stop, and
//! etc.). Contains default and other system elements.
//! * Actor - objects providing actor execution in the runtime
//!
//! Runtime consists two object:
//! * Mailbox - queue protected from race condition. This is an interface, which presents set of
//! some basic methods for work with the internal queue. In this queue drops all messages passed
//! to the actor before his actual processing. In the library exists few standard realization of
//! this interface:
//!
//!     * UnboundedMailbox - mailbox without any queue size restrictions. This mailbox is used by
//! default at the time of actor creation, if other mailbox type, does not specified explicitly.
//!
//! * Dispatcher - entity which process the messages. Message processing may be planned in it, and
//! after that, dispatcher decides himself, how and when run his processing. Message processing is
//! the operation, when receive method of actor is called with processed message and prepared
//! context. Dispatcher is an interface, and him concrete behavior base on it's implementation. In
//! the library exists few standard realization of this interface:
//!
//!     * DefaultDispatcher - threads pinned dispatcher, in which message of each concrete actor,
//! processed in only one OS thread. This feature allows actors has internal state without any
//! protections from race condition. This dispatcher is used by default at the time of actor
//! creation, if other dispatcher type, does not specified explicitly.
//!
//!  Runtime consists five object:
//! * Actor - user defined structure implemented with the Actor trait. This object contains
//! application logic of program constructed in the actors style. Him has one mandatory function for
//! realization (receive) and few optional (preStart, postStop an others).
//! * ActorRef - representation of the actor link. This is an interface, through which users code
//! may interact with underlayed actor. This interface is an encapsulate of interaction with the
//! underlying ActorCell (described below). ActorRef may be cloned as many time as you want, safe
//! shared between actors and other thread. This feature ensured by the fact, that all instances of
//! the cloned ref, will link to the single protected ActorCell object.
//! * ActorCell - system actor representation. Coordinates all interaction with actor from the
//! outside. This object contains the current lifetime state of an actor. In him stored mailbox and
//! link to the dispatcher, in which will be processed messages from the mailbox. Functional it
//! performs, start, stop and suspend actor. Interacts with dispatcher for planning messages
//! processing and etc. Need make a comment about the mailbox and dispatcher instances. ActorCell
//! has always it's own instance if the mailbox, which will created with the other elements of the
//! actor at the creation stage of him. Unique of the dispatcher depends on it's type. Some
//! dispatchers has a shared nature. They may be user with few actors at the same time. Others is
//! unique for each actor instance. Example of the first type dispatcher is DefaultDispatcher.
//! Second is PinnedDispatcher (in developing stage, used in the strategy - os thread per actor).
//! * ActorPath - representation of the actor path in the actors system. This object is used for
//! comparing actor references, paths printing in the debug messages and other internal needs.
//! * ActorContext - actor environment at processing message. This struct conatins message sender
//! reference, self actor reference, link to the system on witch actor is executed and other useful
//! values and methods.
//!
//! System consists two object:
//! * ActorSystem - object represents the actor system. It used for creating, stopping actors and
//! some other service operations performing.
//! * Dead Letter - special sort of the mailbox in which all enqueued messages is logged and after
//! that destroyed. Never is planned. Used to dispose of undelivered messages for various reasons.
//!
//! # Basic operations
//!
//! Now, after we will learn set of the basis framework elements, let's try write some practical
//! code. First, we need some implementation of the actor. Let's create actor to which we may send
//! the message with some text, and actor will print it. As side-effect, actor will be count of
//! printed characters.
//!
//! ```
//! use crate::actors::actor::Actor;
//! use crate::actors::actor_context::ActorContext;
//! use crate::actors::props::Props;
//! use std::any::Any;
//! use std::sync::{Mutex, Arc};
//! use match_downcast::*;
//!
//! pub fn props() -> Props {
//!    Props::new(tsafe!(BasicActor::new()))
//! }
//!
//! pub struct Print {
//!     pub text: String,
//! }
//!
//! pub struct BasicActor {
//!     printed_chars: usize
//! }
//!
//! impl BasicActor {
//!     pub fn new() -> BasicActor {
//!         BasicActor {
//!             printed_chars: 0
//!         }
//!     }
//! }
//!
//! impl Actor for BasicActor {
//!
//!     fn receive(self: &mut Self, msg: &Box<Any + Send>, ctx: ActorContext) -> bool {
//!         match_downcast_ref!(msg, {
//!             m: Print => {
//!                 self.printed_chars = self.printed_chars + m.text.len();
//!                 println!("{}", m.text);
//!             },
//!             _ => return false
//!         });
//!
//!         true
//!     }
//! 
//! }
//! ```
//!
//! Next we write the code which use this actor
//!
//! ```
//! let mut system = LocalActorSystem::new();
//!
//! let mut printer = system.lock().unwrap()
//!     .actor_of(basic_actor::props(), Some("printer"));
//!
//! let msg = Box::new(basic_actor::Print { text: String::from("Hello world!") });
//! printer.tell(msg, None);
//! ```
//!
//! At first line, we create new actor system. Internally, this operation creates default dispatcher
//! and DeadLetter synthetic actor. Should pay attention on the following fact. ActorSystem have type
//! TSafe<LocalActorSystem>. TSafe is macro which expands to Arc<Mutex\<T\>>. Last is the standard rust
//! thread safe shared pointer. This fact means for as, that we will mast lock this pointer before
//! use it. Omissions in the logic of the this pointers unlocking, when we use in outside of the
//! actor system, will guaranteed lead to some sort of deadlocks. For this reason, you must pay
//! extreme attention for lock management of this object if you plan to use this pointer in the
//! other places, rather than actors. In normal conditions, his is used only at the actor system
//! deploying stage. All other interactions with system will be performs in the actors, and does not
//! may cause deadlock.
//!
//! At next line, we create the early defined actor. actor_of functions is receive Pops object as
//! first argument, and actor name as second. Actor name is optional, and it may be set to None.
//! In this case, name will be generated automatically. Props object is indicates the system, which
//! actor to create, and with whitch params. We will come across this structure more than once as
//! the material is presented. For now, we simple creates new actor instance and put it's to the
//! Props object. As a result of the actor_off call, we will receive actor link object - ActorRef.
//! Internally this call, besides the ActorRef, will create next objects: ActorCell, Mailbox and
//! Dispatcher if it was specified and has unique nature. After performs all internal operations,
//! library code will call preStart function, which will be described later in this doc.
//!
//! And at last stage, we may send the Print message to the actor. We create new Print structure,
//! box it and send it to the actor through tell function. Tell function receive message as first
//! argument and sender actor reference as second. Last is optional, because if we send message
//! outside of the actor system we do not someone whom may be represents as sender. If you perform
//! this operation from the actor, you should be set ctx.self_ to this value. But about this we
//! say later. When you call tell function, ActorCell get passed message to the mailbox and
//! indicates dispatcher schedule this message for processing.
//!
//! Ok, message in the mailbox, what happens with him further? Next, the dispatcher executor, when they
//! will be ready for it, extract him from the mailbox and message processing stage is starts.
//! First, the message is heading to the internal receive function. His task, determine service message
//! (such as PoisonPill, witch stops the actor). If it is, it will be processed, some service
//! actions will be performed and message will dropped. He will does not reach the  receive function
//! of the target actor. If this message is not a service message, actor.receive function will be
//! called. This function must return a boolean value, which indicates fact, was  handled message or
//! not. If the message was handled, message processing logic is end, else the message will be dropped
//! to the DeadLetter.
//!
//! Now consider the the function of messages receive of our actor. It have three args. First arg
//! is the link to self object which state is fully mutable. Second args is the received message.
//! Last arg is the message processing context. Message represents as boxed Any type and may be
//! matched be any comfortable way for you. I use for this the crate 'match-downcast' which allows
//! keep code clear at downcast operations. From the context, for now, only one object is
//! interesting - sender. What does he point to? At DeadLetter, because at tell operation, we was
//! specify None as sender reference.
//!
//! # Lifetime hooks
//! Actor has few lifetime hooks which may be used for various operations:
//! * preStart - called after full actor initialization and before allowing reception of
//! messages. At this stage already exists actor context, which may be used for creating new actors
//! or sending message for himself. Also is available actor's internal state for mutating.
//! * postStop - called after full stop of actor. This means, that all message passed to the actor
//! was processed or dropped and it will not receive any new messages further. This is the last
//! point of interaction with internal actor's state. At this stage actor context also exists and
//! may be user to perform various operations.
//!
//! For example let's add this hooks to our basic actor:
//!
//! ```
//! ...
//!
//! fn pre_start(self: &mut Self, ctx: ActorContext) {
//!     println!("BasicActor is started")
//! }
//!
//! fn post_stop(self: &mut Self, ctx: ActorContext) {
//!     println!("BasicActor is stopped")
//! }
//!
//! ...
//! ```
//!
//! After you run this modified example, before printing the passed message, in the stdout you will
//! see 'BasicActor is started'. postTop  will triggered after actor will be stopped. This operation
//! we will learn below.
//!
//! # Stopping actors
//! Actor can  be stopped in two way:
//! * Send PoisonPill - this is a special service message, located in the actor submodule.
//! If you send this message to an actor, it will be enqueued as an any regular message. But when
//! dispatcher will face with him, he will drop all messages in the mailbox after it, and starts
//! actor stopping procedure.
//!
//!     ```
//!     bench.tell(Box::new(actor::PoisonPill { }), None);
//!     ```
//!
//! * ActorSystem::stop(ActorRef) - this call immediately stops the specified actor. He lead to block mailbox
//! of the actor, flush all it's messages and mark him as stopped. If this call happens from a
//! message handler, current message will be processed, but all subsequent does not. Internally this
//! call does the following. He suspends the actor, clean his mailbox and prepend to it ths single
//! PoisonPill message. This will lead to that after processing the current message dispatcher will
//! immediately come across a message PoisonPill and stops the actor. Similar situation will be
//! happened and if this call occurs outside of actor system. In this case, if target actor is in
//! process of some message, it will be processed and after that actor will be stopped.
//!
//!     ```
//!     system.lock().unwrap().stop(bench);
//!     ```
//!
//! # Actor communications
//! For consideration of this topic, we need some more complicated example. In the 'example'
//! submodule located module named logger. This is more complex program then basic example, but this
//! much more real world example of actors usage. Here contains three actors which realize logger,
//! in which we may indicate logging target. Log target may be StdOut or File. Logger actor contains
//! links to the writers, whom directly realize logging logic to him target. Task of the logger
//! actor is  receive Log message, determine target writer actor and send Write message to him.
//! Writer actor receive this message, performs write and respond to the sender with Ok message.
//! Logger actor receive this message, increment internal counter of write chars and print info
//! text about this action to console. Below are given 'receive' functions of this actors.
//! Surrounding code is redundant for this doc, and you may see him in in the source files.
//!
//! ```
//!// Logger
//!fn receive(self: &mut Self, msg: &Box<Any + Send>, ctx: ActorContext) -> bool {
//!    match_downcast_ref!(msg, {
//!            m: Log => {
//!                match m.target {
//!                    LogTarget::File => {
//!                        let msg = Box::new(file_writer::Write { text: m.text.to_string() });
//!                        self.file_writer.tell(msg , Some(ctx.self_))
//!                    },
//!                    LogTarget::StdOut => {
//!                        let msg = Box::new(stdout_writer::Write { text: m.text.to_string() });
//!                        self.stdout_writer.tell(msg, Some(ctx.self_))
//!                    }
//!                };
//!            },
//!            m: file_writer::Ok => {
//!                println!("File logger write '{}' chars", m.chars_count);
//!                self.chars_counter = self.chars_counter + m.chars_count;
//!            },
//!            m: stdout_writer::Ok => {
//!                 println!("Stout logger write '{}' chars", m.chars_count);
//!                self.chars_counter = self.chars_counter + m.chars_count;
//!            },
//!            _ => return false
//!        });
//!
//!    true
//!}
//!
//!
//!//StdoutWriter
//!fn receive(self: &mut Self, msg: &Box<Any + Send>, mut ctx: ActorContext) -> bool {
//!    match_downcast_ref!(msg, {
//!            m: Write => {
//!               println!("{}", m.text);
//!               let resp = Box::new(Ok { chars_count: m.text.len() });
//!               ctx.sender.tell(resp, Some(ctx.self_));
//!            },
//!            _ => return false
//!        });
//!
//!    true
//!}
//!
//!
//! //FileWriter
//!fn receive(self: &mut Self, msg: &Box<Any + Send>, mut ctx: ActorContext) -> bool {
//!    match_downcast_ref!(msg, {
//!            m: Write => {
//!               fs::write(&self.file, m.text.as_bytes());
//!               let resp = Box::new(Ok { chars_count: m.text.len() });
//!               ctx.sender.tell(resp, Some(ctx.self_));
//!            },
//!            _ => return false
//!        });
//!
//!    true
//!}
//! ```
//!
//! And code which use this actors:
//!
//! ```
//! let mut system = LocalActorSystem::new();
//!
//! let mut logger =  {
//!     let mut system = system.lock().unwrap();
//!     let file_writer = system.actor_of(file_writer::props("/tmp/log"), Some("file_writer"));
//!     let stdout_writer = system.actor_of(stdout_writer::props(), Some("stdout_writer"));
//!     system.actor_of(logger::props(file_writer, stdout_writer), Some("logger"))
//! };
//!
//! logger.tell(Box::new(logger::Log { text: String::from("To file log"), target: logger::LogTarget::File }), None);
//! logger.tell(Box::new(logger::Log { text: String::from("To stdout log"), target: logger::LogTarget::StdOut }), None);
//! ```
//!
//! This code demonstrate two patterns and operation as part of this library:
//! * Dependency Injection - at deploying stage of the system, we create two actors (writers) and
//! inject it to the logger actor through him constructor (which is hidden by the props function).
//! * Context using - demonstrated actor context usage for sending messages to another actor and
//! respond to messages.
//!
//! # ActorRef sharing
//! In the previous example we was moved created references to the logging writers to the
//! constructor of logger actor. But what about if you want to use this references later in your
//! code? For this, ActorRef's may by simply cloned.
//!
//! ```
//!let (mut logger, mut file_writer, mut stdout_writer) = {
//!     let mut system = system.lock().unwrap();
//!     let file_writer = system.actor_of(file_writer::props("/tmp/log"), Some("file_writer"));
//!     let stdout_writer = system.actor_of(stdout_writer::props(), Some("stdout_writer"));
//!     let logger = system.actor_of(logger::props(file_writer.clone(), stdout_writer.clone()), Some("logger"));
//!     (logger, file_writer, stdout_writer)
//! };
//! ```
//! # More about DeadLetters
//! In the previous text will be described what is the DeadLetters. Now will be described why it
//! exists and how it use. Basic idea of the actors message passing, consists in that all message
//! must be delivered to the target actor and consumed. If this is not happens, and message not
//! consumed be the receiver, this is an semantic error in the your program. Main task of the
//! DeadLetters, is quite aggressive indicates to you, that this error type was occurs in your
//! program. For this, DeadLetter log each received by him message to the stdout.
//!
//! ```text
//! DeadLetter receive some message ... from 'ActorRef (/stdout_writer)' to 'ActorRef (/logger)'
//! ```
//!
//! This feature is unable to disable be the ideological reasons. Because not processed messages is
//! an error! In practical, this prints is very useful for actor system debug , when something goes
//! wrong and work improperly. 90% of errors in actor-based programs linked to the problem of not
//! delivered messages and DeadLetters allows to you fastly determine bags.
//!
//! Also, you may encounter with situation, when you may want to interact with DeadLetters directly.
//! This is may be performed by obtaining the DeadLetter actor reference. This reference stored in
//! the ActorSystem and may by cloned from it by the special function:
//!
//! ```
//! let mut deadLetters = system.dead_letters();
//! ```
//!
//! This is a regular actor reference, but all messages passed through it, will be dropped directly
//! to the DeadLetter.


pub mod dispatcher;
pub mod default_dispatcher;
pub mod actor_cell;
pub mod envelope;
pub mod mailbox;
pub mod unbound_mailbox;
pub mod actor;
pub mod local_actor_system;
pub mod abstract_actor_ref;
pub mod props;
pub mod actor_path;
pub mod actor_context;
pub mod dead_letters;
pub mod synthetic_actor;
pub mod actor_ref_factory;
pub mod abstract_actor_system;
pub mod local_actor_ref;