diff --git a/Cargo.toml b/Cargo.toml index fce56e9621e..b6440b3ecf8 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -44,7 +44,6 @@ flate2 = { version = "1.0.28", optional = true } reqwest = { version = "0.11.22", default-features = false, features = ["multipart", "stream"], optional = true } static_assertions = { version = "1.1.0", optional = true } tokio-tungstenite = { version = "0.21.0", optional = true } -typemap_rev = { version = "0.3.0", optional = true } bytes = { version = "1.5.0", optional = true } percent-encoding = { version = "2.3.0", optional = true } mini-moka = { version = "0.10.2", optional = true } @@ -92,7 +91,7 @@ cache = ["fxhash", "dashmap", "parking_lot"] collector = ["gateway", "model"] # Wraps the gateway and http functionality into a single interface # TODO: should this require "gateway"? -client = ["http", "typemap_rev"] +client = ["http"] # Enables the Framework trait which is an abstraction for old-style text commands. framework = ["client", "model", "utils"] # Enables gateway support, which allows bots to listen for Discord events. diff --git a/examples/e05_command_framework/Cargo.toml b/examples/e05_command_framework/Cargo.toml index bb829733ff7..06a616b3fe1 100644 --- a/examples/e05_command_framework/Cargo.toml +++ b/examples/e05_command_framework/Cargo.toml @@ -4,6 +4,9 @@ version = "0.1.0" authors = ["my name "] edition = "2018" +[dependencies] +dashmap = "5" + [dependencies.serenity] features = ["framework", "standard_framework", "rustls_backend"] path = "../../" diff --git a/examples/e05_command_framework/src/main.rs b/examples/e05_command_framework/src/main.rs index df067bae79d..f91bbd4d5f4 100644 --- a/examples/e05_command_framework/src/main.rs +++ b/examples/e05_command_framework/src/main.rs @@ -9,10 +9,10 @@ //! ``` #![allow(deprecated)] // We recommend migrating to poise, instead of using the standard command framework. use std::borrow::Cow; -use std::collections::{HashMap, HashSet}; +use std::collections::HashSet; use std::env; use std::fmt::Write; -use std::sync::Arc; +use std::sync::{Arc, OnceLock}; use serenity::async_trait; use serenity::builder::EditChannel; @@ -43,16 +43,9 @@ use serenity::utils::{content_safe, ContentSafeOptions}; // A container type is created for inserting into the Client's `data`, which allows for data to be // accessible across all events and framework commands, or anywhere else that has a copy of the // `data` Arc. -struct ShardManagerContainer; - -impl TypeMapKey for ShardManagerContainer { - type Value = Arc; -} - -struct CommandCounter; - -impl TypeMapKey for CommandCounter { - type Value = HashMap; +struct UserData { + command_counter: dashmap::DashMap, + shard_manager: OnceLock>, } struct Handler; @@ -144,9 +137,8 @@ async fn before(ctx: &Context, msg: &Message, command_name: &str) -> bool { // Increment the number of times this command has been run once. If the command's name does not // exist in the counter, add a default value of 0. - let mut data = ctx.data.write().await; - let counter = data.get_mut::().expect("Expected CommandCounter in TypeMap."); - let entry = counter.entry(command_name.to_string()).or_insert(0); + let data = ctx.data::(); + let mut entry = data.command_counter.entry(command_name.to_string()).or_insert(0); *entry += 1; true // if `before` returns false, command processing doesn't happen. @@ -295,6 +287,11 @@ async fn main() { .owners(owners), ); + let data = UserData { + command_counter: dashmap::DashMap::new(), + shard_manager: OnceLock::new(), + }; + // For this example to run properly, the "Presence Intent" and "Server Members Intent" options // need to be enabled. // These are needed so the `required_permissions` macro works on the commands that need to use @@ -305,13 +302,13 @@ async fn main() { let mut client = Client::builder(&token, intents) .event_handler(Handler) .framework(framework) - .type_map_insert::(HashMap::default()) + .data(Arc::new(data) as _) .await .expect("Err creating client"); { - let mut data = client.data.write().await; - data.insert::(Arc::clone(&client.shard_manager)); + let data = client.data::(); + let _ = data.shard_manager.set(Arc::clone(&client.shard_manager)); } if let Err(why) = client.start().await { @@ -327,10 +324,9 @@ async fn main() { async fn commands(ctx: &Context, msg: &Message) -> CommandResult { let mut contents = "Commands used:\n".to_string(); - let data = ctx.data.read().await; - let counter = data.get::().expect("Expected CommandCounter in TypeMap."); - - for (name, amount) in counter { + let counter = &ctx.data::().command_counter; + for entry in counter { + let (name, amount) = entry.pair(); writeln!(contents, "- {name}: {amount}")?; } @@ -448,17 +444,8 @@ async fn about(ctx: &Context, msg: &Message) -> CommandResult { async fn latency(ctx: &Context, msg: &Message) -> CommandResult { // The shard manager is an interface for mutating, stopping, restarting, and retrieving // information about shards. - let data = ctx.data.read().await; - - let shard_manager = match data.get::() { - Some(v) => v, - None => { - msg.reply(ctx, "There was a problem getting the shard manager").await?; - - return Ok(()); - }, - }; - + let data = ctx.data::(); + let shard_manager = data.shard_manager.get().expect("should be init before startup"); let runners = shard_manager.runners.lock().await; // Shards are backed by a "shard runner" responsible for processing events over the shard, so @@ -472,7 +459,7 @@ async fn latency(ctx: &Context, msg: &Message) -> CommandResult { }, }; - msg.reply(ctx, &format!("The shard latency is {:?}", runner.latency)).await?; + msg.reply(ctx, format!("The shard latency is {:?}", runner.latency)).await?; Ok(()) } diff --git a/examples/e06_sample_bot_structure/src/commands/owner.rs b/examples/e06_sample_bot_structure/src/commands/owner.rs index 973679889ab..f55b6720818 100644 --- a/examples/e06_sample_bot_structure/src/commands/owner.rs +++ b/examples/e06_sample_bot_structure/src/commands/owner.rs @@ -3,21 +3,16 @@ use serenity::framework::standard::CommandResult; use serenity::model::prelude::*; use serenity::prelude::*; -use crate::ShardManagerContainer; +use crate::UserData; #[command] #[owners_only] async fn quit(ctx: &Context, msg: &Message) -> CommandResult { - let data = ctx.data.read().await; + let data = ctx.data::(); + let shard_manager = data.shard_manager.get().expect("should be init before startup"); - if let Some(manager) = data.get::() { - msg.reply(ctx, "Shutting down!").await?; - manager.shutdown_all().await; - } else { - msg.reply(ctx, "There was a problem getting the shard manager").await?; - - return Ok(()); - } + msg.reply(ctx, "Shutting down!").await?; + shard_manager.shutdown_all().await; Ok(()) } diff --git a/examples/e06_sample_bot_structure/src/main.rs b/examples/e06_sample_bot_structure/src/main.rs index 5ebcc63f47d..1f18ad17388 100644 --- a/examples/e06_sample_bot_structure/src/main.rs +++ b/examples/e06_sample_bot_structure/src/main.rs @@ -12,7 +12,7 @@ mod commands; use std::collections::HashSet; use std::env; -use std::sync::Arc; +use std::sync::{Arc, OnceLock}; use serenity::async_trait; use serenity::framework::standard::macros::group; @@ -29,10 +29,8 @@ use crate::commands::math::*; use crate::commands::meta::*; use crate::commands::owner::*; -pub struct ShardManagerContainer; - -impl TypeMapKey for ShardManagerContainer { - type Value = Arc; +struct UserData { + shard_manager: OnceLock>, } struct Handler; @@ -84,18 +82,23 @@ async fn main() { let framework = StandardFramework::new().group(&GENERAL_GROUP); framework.configure(Configuration::new().owners(owners).prefix("~")); + let user_data = UserData { + shard_manager: OnceLock::new(), + }; + let intents = GatewayIntents::GUILD_MESSAGES | GatewayIntents::DIRECT_MESSAGES | GatewayIntents::MESSAGE_CONTENT; let mut client = Client::builder(&token, intents) .framework(framework) .event_handler(Handler) + .data(Arc::new(user_data) as _) .await .expect("Err creating client"); { - let mut data = client.data.write().await; - data.insert::(client.shard_manager.clone()); + let data = client.data::(); + let _ = data.shard_manager.set(client.shard_manager.clone()); } let shard_manager = client.shard_manager.clone(); diff --git a/examples/e12_global_data/Cargo.toml b/examples/e12_global_data/Cargo.toml index 0244a75f70c..ae4318caa9b 100644 --- a/examples/e12_global_data/Cargo.toml +++ b/examples/e12_global_data/Cargo.toml @@ -7,3 +7,4 @@ edition = "2018" [dependencies] serenity = { path = "../../" } tokio = { version = "1.0", features = ["macros", "rt-multi-thread"] } +dashmap = "5" diff --git a/examples/e12_global_data/src/main.rs b/examples/e12_global_data/src/main.rs index 5311066094f..b72c0a2f2ae 100644 --- a/examples/e12_global_data/src/main.rs +++ b/examples/e12_global_data/src/main.rs @@ -2,11 +2,11 @@ //! And how to use locks correctly to avoid deadlocking the bot. #![allow(deprecated)] // We recommend migrating to poise, instead of using the standard command framework. -use std::collections::HashMap; use std::env; use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; +use dashmap::DashMap; use serenity::async_trait; use serenity::framework::standard::macros::{command, group, hook}; use serenity::framework::standard::{Args, CommandResult, Configuration, StandardFramework}; @@ -17,24 +17,9 @@ use serenity::prelude::*; // A container type is created for inserting into the Client's `data`, which allows for data to be // accessible across all events and framework commands, or anywhere else that has a copy of the // `data` Arc. These places are usually where either Context or Client is present. -// -// Documentation about TypeMap can be found here: -// https://docs.rs/typemap_rev/0.1/typemap_rev/struct.TypeMap.html -struct CommandCounter; - -impl TypeMapKey for CommandCounter { - type Value = Arc>>; -} - -struct MessageCount; - -impl TypeMapKey for MessageCount { - // While you will be using RwLock or Mutex most of the time you want to modify data, sometimes - // it's not required; like for example, with static data, or if you are using other kinds of - // atomic operators. - // - // Arc should stay, to allow for the data lock to be closed early. - type Value = Arc; +struct UserData { + message_count: AtomicUsize, + command_counter: DashMap, } #[group] @@ -45,28 +30,16 @@ struct General; async fn before(ctx: &Context, msg: &Message, command_name: &str) -> bool { println!("Running command '{}' invoked by '{}'", command_name, msg.author.tag()); - let counter_lock = { - // While data is a RwLock, it's recommended that you always open the lock as read. This is - // mainly done to avoid Deadlocks for having a possible writer waiting for multiple readers - // to close. - let data_read = ctx.data.read().await; - - // Since the CommandCounter Value is wrapped in an Arc, cloning will not duplicate the - // data, instead the reference is cloned. - // We wrap every value on in an Arc, as to keep the data lock open for the least time - // possible, to again, avoid deadlocking it. - data_read.get::().expect("Expected CommandCounter in TypeMap.").clone() - }; - - // Just like with client.data in main, we want to keep write locks open the least time - // possible, so we wrap them on a block so they get automatically closed at the end. + // We want to keep write locks open the least time possible, so we wrap them on a block so they + // get automatically closed at the end. { - // The HashMap of CommandCounter is wrapped in an RwLock; since we want to write to it, we - // will open the lock in write mode. - let mut counter = counter_lock.write().await; + // We have to provide the Data type each time we access Context::data. + let counter = &ctx.data::().command_counter; + + // The DashMap provides interior mutability, meaning we can write to it with a & reference. + let mut entry = counter.entry(command_name.to_string()).or_insert(0); // And we write the amount of times the command has been called to it. - let entry = counter.entry(command_name.to_string()).or_insert(0); *entry += 1; } @@ -83,10 +56,7 @@ impl EventHandler for Handler { && msg.content.to_lowercase().contains("owo") { // Since data is located in Context, this means you are able to use it within events! - let count = { - let data_read = ctx.data.read().await; - data_read.get::().expect("Expected MessageCount in TypeMap.").clone() - }; + let count = &ctx.data::().message_count; // Here, we are checking how many "owo" there are in the message content. let owo_in_msg = msg.content.to_ascii_lowercase().matches("owo").count(); @@ -107,6 +77,13 @@ impl EventHandler for Handler { async fn main() { let token = env::var("DISCORD_TOKEN").expect("Expected a token in the environment"); + // We setup the initial value for our user data, which we will use throughout the rest of our + // program. + let data = UserData { + message_count: AtomicUsize::new(0), + command_counter: DashMap::new(), + }; + let framework = StandardFramework::new().before(before).group(&GENERAL_GROUP); framework.configure(Configuration::new().with_whitespace(true).prefix("~")); @@ -116,37 +93,11 @@ async fn main() { let mut client = Client::builder(&token, intents) .event_handler(Handler) .framework(framework) + // We have to use `as` to turn our UserData into `dyn Any`. + .data(Arc::new(data) as _) .await .expect("Err creating client"); - // This is where we can initially insert the data we desire into the "global" data TypeMap. - // client.data is wrapped on a RwLock, and since we want to insert to it, we have to open it in - // write mode, but there's a small thing catch: There can only be a single writer to a given - // lock open in the entire application, this means you can't open a new write lock until the - // previous write lock has closed. This is not the case with read locks, read locks can be open - // indefinitely, BUT as soon as you need to open the lock in write mode, all the read locks - // must be closed. - // - // You can find more information about deadlocks in the Rust Book, ch16-03: - // https://doc.rust-lang.org/book/ch16-03-shared-state.html - // - // All of this means that we have to keep locks open for the least time possible, so we put - // them inside a block, so they get closed automatically when dropped. If we don't do this, we - // would never be able to open the data lock anywhere else. - // - // Alternatively, you can also use `ClientBuilder::type_map_insert` or - // `ClientBuilder::type_map` to populate the global TypeMap without dealing with the RwLock. - { - // Open the data lock in write mode, so keys can be inserted to it. - let mut data = client.data.write().await; - - // The CommandCounter Value has the type: Arc>> - // So, we have to insert the same type to it. - data.insert::(Arc::new(RwLock::new(HashMap::default()))); - - data.insert::(Arc::new(AtomicUsize::new(0))); - } - if let Err(why) = client.start().await { eprintln!("Client error: {why:?}"); } @@ -173,22 +124,11 @@ async fn command_usage(ctx: &Context, msg: &Message, mut args: Args) -> CommandR // Yet again, we want to keep the locks open for the least time possible. let amount = { - // Since we only want to read the data and not write to it, we open it in read mode, and - // since this is open in read mode, it means that there can be multiple locks open at the - // same time, and as mentioned earlier, it's heavily recommended that you only open the - // data lock in read mode, as it will avoid a lot of possible deadlocks. - let data_read = ctx.data.read().await; - - // Then we obtain the value we need from data, in this case, we want the command counter. - // The returned value from get() is an Arc, so the reference will be cloned, rather than - // the data. - let command_counter_lock = - data_read.get::().expect("Expected CommandCounter in TypeMap.").clone(); - - let command_counter = command_counter_lock.read().await; - // And we return a usable value from it. - // This time, the value is not Arc, so the data will be cloned. - command_counter.get(&command_name).map_or(0, |x| *x) + // We again, have to provide the UserData type. + let data = ctx.data::(); + + // We fetch the value our of the map, temporarily holding a dashmap read lock. + data.command_counter.get(&command_name).map_or(0, |x| *x) }; if amount == 0 { @@ -206,12 +146,8 @@ async fn command_usage(ctx: &Context, msg: &Message, mut args: Args) -> CommandR #[command] async fn owo_count(ctx: &Context, msg: &Message) -> CommandResult { - let raw_count = { - let data_read = ctx.data.read().await; - data_read.get::().expect("Expected MessageCount in TypeMap.").clone() - }; - - let count = raw_count.load(Ordering::Relaxed); + let data = ctx.data::(); + let count = data.message_count.load(Ordering::Relaxed); if count == 1 { msg.reply( diff --git a/src/client/context.rs b/src/client/context.rs index 380752525ce..1052f75d30b 100644 --- a/src/client/context.rs +++ b/src/client/context.rs @@ -1,9 +1,6 @@ use std::fmt; use std::sync::Arc; -use tokio::sync::RwLock; -use typemap_rev::TypeMap; - #[cfg(feature = "cache")] pub use crate::cache::Cache; use crate::gateway::ActivityData; @@ -31,7 +28,7 @@ pub struct Context { /// A clone of [`Client::data`]. Refer to its documentation for more information. /// /// [`Client::data`]: super::Client::data - pub data: Arc>, + data: Arc, /// The messenger to communicate with the shard runner. pub shard: ShardMessenger, /// The ID of the shard this context is related to. @@ -56,7 +53,7 @@ impl Context { /// Create a new Context to be passed to an event handler. #[cfg(feature = "gateway")] pub(crate) fn new( - data: Arc>, + data: Arc, runner: &ShardRunner, shard_id: ShardId, http: Arc, @@ -73,7 +70,11 @@ impl Context { } #[cfg(all(not(feature = "cache"), not(feature = "gateway")))] - pub fn easy(data: Arc>, shard_id: u32, http: Arc) -> Context { + pub fn easy( + data: Arc, + shard_id: ShardId, + http: Arc, + ) -> Context { Context { shard_id, data, @@ -81,6 +82,24 @@ impl Context { } } + /// A container for a data type that can be used across contexts. + /// + /// The purpose of the data field is to be accessible and persistent across contexts; that is, + /// data can be modified by one context, and will persist through the future and be accessible + /// through other contexts. This is useful for anything that should "live" through the program: + /// counters, database connections, custom user caches, etc. + /// + /// # Panics + /// Panics if the generic provided is not equal to the type provided in [`ClientBuilder::data`]. + /// + /// [`ClientBuilder::data`]: super::ClientBuilder::data + #[must_use] + pub fn data(&self) -> &Data { + self.data + .downcast_ref() + .expect("Type provided to Context should be the same as ClientBuilder::data.") + } + /// Sets the current user as being [`Online`]. This maintains the current activity. /// /// # Examples diff --git a/src/client/mod.rs b/src/client/mod.rs index ed3e7b94c34..a855629349d 100644 --- a/src/client/mod.rs +++ b/src/client/mod.rs @@ -31,9 +31,7 @@ use std::sync::OnceLock; use futures::channel::mpsc::UnboundedReceiver as Receiver; use futures::future::BoxFuture; use futures::StreamExt as _; -use tokio::sync::RwLock; use tracing::debug; -use typemap_rev::{TypeMap, TypeMapKey}; pub use self::context::Context; pub use self::error::Error as ClientError; @@ -66,7 +64,7 @@ use crate::utils::check_shard_total; #[cfg(feature = "gateway")] #[must_use = "Builders do nothing unless they are awaited"] pub struct ClientBuilder { - data: TypeMap, + data: Option>, http: Http, intents: GatewayIntents, #[cfg(feature = "cache")] @@ -100,9 +98,9 @@ impl ClientBuilder { /// panic. pub fn new_with_http(http: Http, intents: GatewayIntents) -> Self { Self { - data: TypeMap::new(), http, intents, + data: None, #[cfg(feature = "cache")] cache_settings: CacheSettings::default(), #[cfg(feature = "framework")] @@ -140,26 +138,9 @@ impl ClientBuilder { self.http.application_id() } - /// Sets the entire [`TypeMap`] that will be available in [`Context`]s. A [`TypeMap`] must not - /// be constructed manually: [`Self::type_map_insert`] can be used to insert one type at a - /// time. - pub fn type_map(mut self, type_map: TypeMap) -> Self { - self.data = type_map; - - self - } - - /// Gets the type map. See [`Self::type_map`] for more info. - pub fn get_type_map(&self) -> &TypeMap { - &self.data - } - - /// Insert a single `value` into the internal [`TypeMap`] that will be available in - /// [`Context::data`]. This method can be called multiple times in order to populate the - /// [`TypeMap`] with `value`s. - pub fn type_map_insert(mut self, value: T::Value) -> Self { - self.data.insert::(value); - + /// Sets the global data type that can be accessed from [`Context::data`]. + pub fn data(mut self, data: Arc) -> Self { + self.data = Some(data); self } @@ -303,7 +284,7 @@ impl IntoFuture for ClientBuilder { #[cfg_attr(feature = "tracing_instrument", instrument(skip(self)))] fn into_future(self) -> Self::IntoFuture { - let data = Arc::new(RwLock::new(self.data)); + let data = self.data.unwrap_or(Arc::new(())); #[cfg(feature = "framework")] let framework = self.framework; let event_handlers = self.event_handlers; @@ -435,97 +416,7 @@ impl IntoFuture for ClientBuilder { /// [sharding docs]: crate::gateway#sharding #[cfg(feature = "gateway")] pub struct Client { - /// A TypeMap which requires types to be Send + Sync. This is a map that can be safely shared - /// across contexts. - /// - /// The purpose of the data field is to be accessible and persistent across contexts; that is, - /// data can be modified by one context, and will persist through the future and be accessible - /// through other contexts. This is useful for anything that should "live" through the program: - /// counters, database connections, custom user caches, etc. - /// - /// In the meaning of a context, this data can be accessed through [`Context::data`]. - /// - /// # Examples - /// - /// Create a `MessageEventCounter` to track the following events: - /// - /// - [`Event::MessageCreate`] - /// - [`Event::MessageDelete`] - /// - [`Event::MessageDeleteBulk`] - /// - [`Event::MessageUpdate`] - /// - /// ```rust,ignore - /// use std::collections::HashMap; - /// use std::env; - /// - /// use serenity::model::prelude::*; - /// use serenity::prelude::*; - /// - /// struct MessageEventCounter; - /// - /// impl TypeMapKey for MessageEventCounter { - /// type Value = HashMap; - /// } - /// - /// async fn reg>(ctx: Context, name: S) { - /// let mut data = ctx.data.write().await; - /// let counter = data.get_mut::().unwrap(); - /// let entry = counter.entry(name.into()).or_insert(0); - /// *entry += 1; - /// } - /// - /// struct Handler; - /// - /// #[serenity::async_trait] - /// impl EventHandler for Handler { - /// async fn message(&self, ctx: Context, _: Message) { - /// reg(ctx, "MessageCreate").await - /// } - /// async fn message_delete(&self, ctx: Context, _: ChannelId, _: MessageId) { - /// reg(ctx, "MessageDelete").await - /// } - /// async fn message_delete_bulk(&self, ctx: Context, _: ChannelId, _: Vec) { - /// reg(ctx, "MessageDeleteBulk").await - /// } - /// - /// #[cfg(feature = "cache")] - /// async fn message_update( - /// &self, - /// ctx: Context, - /// _old: Option, - /// _new: Option, - /// _: MessageUpdateEvent, - /// ) { - /// reg(ctx, "MessageUpdate").await - /// } - /// - /// #[cfg(not(feature = "cache"))] - /// async fn message_update(&self, ctx: Context, _new_data: MessageUpdateEvent) { - /// reg(ctx, "MessageUpdate").await - /// } - /// } - /// - /// # async fn run() -> Result<(), Box> { - /// let token = std::env::var("DISCORD_TOKEN")?; - /// let mut client = Client::builder(&token, GatewayIntents::default()).event_handler(Handler).await?; - /// { - /// let mut data = client.data.write().await; - /// data.insert::(HashMap::default()); - /// } - /// - /// client.start().await?; - /// # Ok(()) - /// # } - /// ``` - /// - /// Refer to [example 05] for an example on using the [`Self::data`] field. - /// - /// [`Event::MessageCreate`]: crate::model::event::Event::MessageCreate - /// [`Event::MessageDelete`]: crate::model::event::Event::MessageDelete - /// [`Event::MessageDeleteBulk`]: crate::model::event::Event::MessageDeleteBulk - /// [`Event::MessageUpdate`]: crate::model::event::Event::MessageUpdate - /// [example 05]: https://github.com/serenity-rs/serenity/tree/current/examples/e05_command_framework - pub data: Arc>, + data: Arc, /// A HashMap of all shards instantiated by the Client. /// /// The key is the shard ID and the value is the shard itself. @@ -602,6 +493,16 @@ impl Client { ClientBuilder::new(token, intents) } + /// Fetches the data type provided to [`ClientBuilder::data`]. + /// + /// See the documentation for [`Context::data`] for more information. + #[must_use] + pub fn data(&self) -> &Data { + self.data + .downcast_ref() + .expect("Client::data generic does not match ClientBuilder::data type") + } + /// Establish the connection and start listening for events. /// /// This will start receiving events in a loop and start dispatching the events to your diff --git a/src/gateway/bridge/shard_manager.rs b/src/gateway/bridge/shard_manager.rs index 310c7d0c20a..1450c653a65 100644 --- a/src/gateway/bridge/shard_manager.rs +++ b/src/gateway/bridge/shard_manager.rs @@ -7,10 +7,9 @@ use std::time::Duration; use futures::channel::mpsc::{self, UnboundedReceiver as Receiver, UnboundedSender as Sender}; use futures::{SinkExt, StreamExt}; -use tokio::sync::{Mutex, RwLock}; +use tokio::sync::Mutex; use tokio::time::timeout; use tracing::{info, warn}; -use typemap_rev::TypeMap; #[cfg(feature = "voice")] use super::VoiceGatewayManager; @@ -67,9 +66,9 @@ use crate::model::gateway::GatewayIntents; /// # let http: Arc = unimplemented!(); /// let gateway_info = http.get_bot_gateway().await?; /// +/// let data = Arc::new(()); /// let shard_total = gateway_info.shards; /// let ws_url = Arc::from(gateway_info.url); -/// let data = Arc::new(RwLock::new(TypeMap::new())); /// let event_handler = Arc::new(Handler) as Arc; /// let max_concurrency = std::num::NonZeroU16::MIN; /// let framework = Arc::new(StandardFramework::new()) as Arc; @@ -362,7 +361,7 @@ impl Drop for ShardManager { } pub struct ShardManagerOptions { - pub data: Arc>, + pub data: Arc, pub event_handlers: Vec>, pub raw_event_handlers: Vec>, #[cfg(feature = "framework")] diff --git a/src/gateway/bridge/shard_queuer.rs b/src/gateway/bridge/shard_queuer.rs index 7b64689e9a3..27281279c07 100644 --- a/src/gateway/bridge/shard_queuer.rs +++ b/src/gateway/bridge/shard_queuer.rs @@ -6,10 +6,9 @@ use std::sync::OnceLock; use futures::channel::mpsc::UnboundedReceiver as Receiver; use futures::StreamExt; -use tokio::sync::{Mutex, RwLock}; +use tokio::sync::Mutex; use tokio::time::{sleep, timeout, Duration, Instant}; use tracing::{debug, info, warn}; -use typemap_rev::TypeMap; #[cfg(feature = "voice")] use super::VoiceGatewayManager; @@ -43,7 +42,7 @@ pub struct ShardQueuer { /// A copy of [`Client::data`] to be given to runners for contextual dispatching. /// /// [`Client::data`]: crate::Client::data - pub data: Arc>, + pub data: Arc, /// A reference to an [`EventHandler`], such as the one given to the [`Client`]. /// /// [`Client`]: crate::Client diff --git a/src/gateway/bridge/shard_runner.rs b/src/gateway/bridge/shard_runner.rs index 45c3fe44d15..96e362d94f9 100644 --- a/src/gateway/bridge/shard_runner.rs +++ b/src/gateway/bridge/shard_runner.rs @@ -2,12 +2,10 @@ use std::borrow::Cow; use std::sync::Arc; use futures::channel::mpsc::{self, UnboundedReceiver as Receiver, UnboundedSender as Sender}; -use tokio::sync::RwLock; use tokio_tungstenite::tungstenite; use tokio_tungstenite::tungstenite::error::Error as TungsteniteError; use tokio_tungstenite::tungstenite::protocol::frame::CloseFrame; use tracing::{debug, error, info, trace, warn}; -use typemap_rev::TypeMap; use super::event::ShardStageUpdateEvent; #[cfg(feature = "collector")] @@ -29,7 +27,7 @@ use crate::model::event::{Event, GatewayEvent}; /// A runner for managing a [`Shard`] and its respective WebSocket client. pub struct ShardRunner { - data: Arc>, + data: Arc, event_handlers: Vec>, raw_event_handlers: Vec>, #[cfg(feature = "framework")] @@ -482,7 +480,7 @@ impl ShardRunner { /// Options to be passed to [`ShardRunner::new`]. pub struct ShardRunnerOptions { - pub data: Arc>, + pub data: Arc, pub event_handlers: Vec>, pub raw_event_handlers: Vec>, #[cfg(feature = "framework")] diff --git a/src/prelude.rs b/src/prelude.rs index 189b6c25b1b..e3221a439f9 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -14,8 +14,6 @@ //! [`serenity::Error`]: crate::Error pub use tokio::sync::{Mutex, RwLock}; -#[cfg(feature = "client")] -pub use typemap_rev::{TypeMap, TypeMapKey}; #[cfg(feature = "client")] pub use crate::client::Context;