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
//! Custom state types that can be used across a bot instance.
//!
//! This module only contains the [`StateBound`] trait, which defines the boundaries for state
//! types that can be used in a bot instance. Those are `Clone + Send + Sync + 'static`.
//!
//! It's common to use this state to store things like database connections, caches, and any other
//! data that you want to be accessible everywhere in your bot. It's also common to wrap such state
//! in an [`Arc`](std::sync::Arc) to make cloning cheap (because your state is constantly being
//! cloned and sent across threads).
//!
//! For example, you can define a custom state type like this:
//!
//! ```
//! use std::sync::Arc;
//!
//! struct AppState {
//! db: DatabaseConnection,
//! cache: Cache,
//! }
//!
//! impl AppState {
//! fn new(db: DatabaseConnection, cache: Cache) -> State {
//! Arc::new(AppState { db, cache })
//! }
//! }
//!
//! type State = Arc<AppState>;
//! ```
//!
//! And then use it in your bot instance like this:
//!
//! ```
//! let state = AppState::new(db_connection, cache);
//! let bot = Bot::new(state);
//! ```
//!
//! Note that once you customize your bot's state type, you need to pass it as a generic parameter
//! to all contexts and handlers. For example, in a command handler and an event handler:
//!
//! ```
//! use std::sync::Arc;
//!
//! struct AppState {
//! db: DatabaseConnection,
//! cache: Cache,
//! }
//!
//! type State = Arc<AppState>;
//!
//! async fn command(ctx: CommandContext<State>) {
//! // ...
//! }
//!
//! async fn on_message(ctx: EventContext<State, MessageCreate>) {
//! // ...
//! }
//! ```
//!
//! # Example
//!
//! To demonstrate how to use custom states, let's build a bot that keeps track of how many
//! messages it has received.
//!
//! To start with, let's define our custom state type. We'll use an [`Arc`](std::sync::Arc) holding
//! an [`AtomicUsize`](std::sync::atomic::AtomicUsize) to keep track of the message count in a
//! thread-safe way.
//!
//! ```
//! #[derive(Default, Clone)]
//! struct CounterState {
//! counter: Arc<AtomicUsize>,
//! }
//! ```
//!
//! Great! Now, let's create a bot instance using this custom state. We'll initialize the counter
//! to zero, which is the default.
//!
//! ```
//! let bot = Bot::new(CounterState::default());
//! ```
//!
//! To be able to count the messages and to run commands, we need the message content and guild
//! message intents. So, let's make sure to enable those when creating the bot instance:
//!
//! ```
//! let bot = Bot::new(CounterState::default())
//! .intents(Intents::GUILD_MESSAGES)
//! .intents(Intents::MESSAGE_CONTENT);
//! ```
//!
//! Let's now add an event handler to count the messages. We'll listen for the `MessageCreate`
//! event and increment our counter every time a message is created.
//!
//! ```
//! async fn on_message(ctx: EventContext<CounterState, MessageCreate>) {
//! ctx.state.counter.fetch_add(1, Ordering::SeqCst);
//! }
//!
//! let bot = Bot::new(CounterState::default())
//! .intents(Intents::GUILD_MESSAGES)
//! .intents(Intents::MESSAGE_CONTENT)
//! .on_event(On::message_create(on_message)); // Don't forget to add the event handler to the bot instance!
//! ```
//!
//! Finally, let's add a command to check the current message count. We'll create a simple command
//! called `!count` that responds with the current count of messages.
//!
//! ```
//! async fn count_command(ctx: CommandContext<CounterState>) {
//! let count = ctx.state.counter.load(Ordering::SeqCst);
//! ctx.reply(format!("Message count: {}", count)).await.unwrap();
//! }
//!```
//!
//! Let's add that command to the bot instance and set a prefix, and that should be it.
//!
//! ```
//! let bot = Bot::new(CounterState::default())
//! .intents(Intents::GUILD_MESSAGES)
//! .intents(Intents::MESSAGE_CONTENT)
//! .with_prefix("!")
//! .command(Command::new("count", count_command))
//! .on_event(On::message_create(on_message));
//!
//! bot.run("your_token_here").await.unwrap();
//! ```
//!
//! That's it! Try sending some messages in a channel where the bot is present and then use the
//! `!count` command to see the state updating. Nice, isn't it?
/// Defines the boundaries for the state that can be used in a bot instance.