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
//! Defines the [`Launch`] trait, a generic strategy abstraction for starting Actors.
//!
//! This module provides an extensible mechanism to customize the Actor startup process.
//! Most users will directly use the convenience methods provided by
//! [`ActorExt`](crate::ActorExt) (such as `.start()`), which are themselves
//! concrete implementations of a [`Launch`] strategy.
//!
//! ## Motivation
//!
//! The primary goal of the `Launch` trait is to decouple **the Actor's business logic**
//! (`Actor` trait) from **the Actor's startup and runtime environment configuration**
//! (e.g., what type of message channel to use, how to spawn the `tokio` task, etc.).
//!
//! By implementing the `Launch` trait, you can create custom launchers for:
//! - Using different MPSC Channel implementations (e.g., `flume` or `crossbeam`).
//! - Executing setup or logging before the Actor starts.
//! - Configuring specific properties of the `tokio` task (e.g., using `spawn_blocking`).
//! - Returning a custom handle instead of just an `Outbox`.
use crateActor;
/// A trait that encapsulates the strategy for launching an Actor.
///
/// A type implementing this trait defines how to create the message channel (mailbox)
/// for an Actor, how to spawn the Actor as an asynchronous task, and what handle
/// to return for interacting with that Actor.
///
/// This is an application of the "Strategy Pattern," allowing users to inject
/// custom startup behavior. Typically, a `Launch` instance is passed to the
/// [`ActorExt::with`](crate::ActorExt::with) method to launch the Actor.
///
/// ## Generic Associated Type (GAT)
///
/// Note the use of `type Result<A>`. This is a Generic Associated Type, which
/// allows the type of the launch result to depend on the concrete Actor type `A`
/// being launched.
///
/// ## Example: A Custom Launcher
///
/// The following example creates a `CustomLauncher` that prints a log message
/// upon starting the Actor and uses a fixed bounded channel capacity.
///
/// ```
/// use acty::{Actor, ActorExt, AsyncClose, Launch, BoundedOutbox};
/// use futures::{Stream, StreamExt};
/// use std::pin::pin;
/// use std::marker::PhantomData;
/// use tokio_stream::wrappers::ReceiverStream;
///
/// // 1. Define a simple Actor
/// struct MySimpleActor;
/// impl Actor for MySimpleActor {
///
/// type Message = u32;
///
/// async fn run(self, inbox: impl Stream<Item = Self::Message> + Send) {
/// let count = inbox.count().await;
/// println!("MySimpleActor processed {} messages and is finishing.", count);
/// }
/// }
///
/// // 2. Define the custom launcher
/// struct CustomLauncher<M> {
/// buffer_size: usize,
/// _phantom: PhantomData<M>
/// }
///
/// // 3. Implement the Launch trait for the launcher
/// impl<M: Send + 'static> Launch for CustomLauncher<M> {
///
/// type Message = M;
/// // Returns a Bounded Outbox after launch
/// type Result<A> = BoundedOutbox<Self::Message>;
///
/// fn launch<A>(self, actor: A) -> Self::Result<A>
/// where
/// A: Actor<Message = Self::Message>,
/// {
/// println!("Using CustomLauncher to start an actor!");
///
/// let (sender, receiver) = tokio::sync::mpsc::channel(self.buffer_size);
/// let inbox_stream = ReceiverStream::new(receiver);
/// let join_handle = tokio::spawn(actor.run(inbox_stream));
///
/// BoundedOutbox::new(sender, join_handle)
/// }
/// }
///
/// #[tokio::main]
/// async fn main() {
/// let actor = MySimpleActor;
/// let launcher = CustomLauncher { buffer_size: 5, _phantom: PhantomData };
///
/// // 4. Use actor.with() and the custom launcher to launch the Actor
/// let outbox = actor.with(launcher);
///
/// outbox.send(10).await.unwrap();
/// outbox.send(20).await.unwrap();
///
/// // Close the outbox so the Actor can finish
/// outbox.close().await;
/// }
/// ```