From 3ab86b6452deddf14757f13b8d137d34775db8fb Mon Sep 17 00:00:00 2001 From: Gnome! Date: Sun, 21 Jan 2024 19:45:48 +0000 Subject: [PATCH] Tracks: Replace RwLock data store with Arc (#219) --- Cargo.toml | 2 -- src/lib.rs | 2 -- src/tracks/handle.rs | 43 +++++++++++++++++++++---------------------- src/tracks/mod.rs | 28 +++++++++++++++++++++++----- 4 files changed, 44 insertions(+), 31 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0b3d08543..bb73bdf4f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -50,7 +50,6 @@ tracing = { version = "0.1", features = ["log"] } tracing-futures = "0.2" twilight-gateway = { default-features = false, optional = true, version = "0.15.0" } twilight-model = { default-features = false, optional = true, version = "0.15.0" } -typemap_rev = { optional = true, version = "0.3" } url = { optional = true, version = "2" } uuid = { features = ["v4"], optional = true, version = "1" } @@ -101,7 +100,6 @@ driver = [ "dep:tokio", "dep:tokio-tungstenite", "dep:tokio-util", - "dep:typemap_rev", "dep:url", "dep:uuid", "tokio?/fs", diff --git a/src/lib.rs b/src/lib.rs index aace20479..b4b9a754b 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -111,8 +111,6 @@ mod ws; pub use discortp as packet; #[cfg(feature = "driver")] pub use serenity_voice_model as model; -#[cfg(feature = "driver")] -pub use typemap_rev as typemap; // Re-export serde-json APIs locally to minimise conditional config elsewhere. #[cfg(not(feature = "simd-json"))] diff --git a/src/tracks/handle.rs b/src/tracks/handle.rs index a0c96028e..858df806f 100644 --- a/src/tracks/handle.rs +++ b/src/tracks/handle.rs @@ -1,9 +1,7 @@ use super::*; use crate::events::{Event, EventData, EventHandler}; use flume::{Receiver, Sender}; -use std::{fmt, sync::Arc, time::Duration}; -use tokio::sync::RwLock; -use typemap_rev::TypeMap; +use std::{any::Any, sync::Arc, time::Duration}; use uuid::Uuid; #[derive(Clone, Debug)] @@ -19,20 +17,11 @@ pub struct TrackHandle { inner: Arc, } +#[derive(Debug)] struct InnerHandle { command_channel: Sender, uuid: Uuid, - typemap: RwLock, -} - -impl fmt::Debug for InnerHandle { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("InnerHandle") - .field("command_channel", &self.command_channel) - .field("uuid", &self.uuid) - .field("typemap", &"") - .finish() - } + data: Arc, } impl TrackHandle { @@ -40,11 +29,15 @@ impl TrackHandle { /// /// [`Input`]: crate::input::Input #[must_use] - pub(crate) fn new(command_channel: Sender, uuid: Uuid) -> Self { + pub(crate) fn new( + command_channel: Sender, + uuid: Uuid, + data: Arc, + ) -> Self { let inner = Arc::new(InnerHandle { command_channel, uuid, - typemap: RwLock::new(TypeMap::new()), + data, }); Self { inner } @@ -198,16 +191,22 @@ impl TrackHandle { self.inner.uuid } - /// Allows access to this track's attached [`TypeMap`]. + /// Allows access to this track's attached Data. /// - /// [`TypeMap`]s allow additional, user-defined data shared by all handles + /// Data allows additional, user-defined data shared by all handles /// to be attached to any track. /// - /// Driver code will never attempt to lock access to this map, - /// preventing deadlock/stalling. + /// # Panics + /// This method will panic if the Data has not been initialised, or the type + /// provided does not equal the type passed to [`Track::new_with_data`]. #[must_use] - pub fn typemap(&self) -> &RwLock { - &self.inner.typemap + pub fn data(&self) -> Arc + where + Data: Send + Sync + 'static, + { + Arc::clone(&self.inner.data) + .downcast() + .expect("TrackHandle::data generic does not match type set in TrackHandle::set_data") } #[inline] diff --git a/src/tracks/mod.rs b/src/tracks/mod.rs index 23b1a43e4..72f956d12 100644 --- a/src/tracks/mod.rs +++ b/src/tracks/mod.rs @@ -41,7 +41,7 @@ pub use self::{ pub(crate) use command::*; use crate::{constants::*, driver::tasks::message::*, events::EventStore, input::Input}; -use std::time::Duration; +use std::{any::Any, sync::Arc, time::Duration}; use uuid::Uuid; /// Initial state for audio playback. @@ -104,20 +104,37 @@ pub struct Track { /// /// Defaults to a random 128-bit number. pub uuid: Uuid, + + /// Any data to be associated with the track. + pub user_data: Arc, } impl Track { /// Create a new track directly from an [`Input`] and a random [`Uuid`]. #[must_use] pub fn new(input: Input) -> Self { - let uuid = Uuid::new_v4(); - - Self::new_with_uuid(input, uuid) + Self::new_with_uuid(input, Uuid::new_v4()) } /// Create a new track directly from an [`Input`] with a custom [`Uuid`]. #[must_use] pub fn new_with_uuid(input: Input, uuid: Uuid) -> Self { + Self::new_with_uuid_and_data(input, uuid, Arc::new(())) + } + + /// Create a new track directly from an [`Input`], user data to be associated with the track, and a random [`Uuid`]. + #[must_use] + pub fn new_with_data(input: Input, user_data: Arc) -> Self { + Self::new_with_uuid_and_data(input, Uuid::new_v4(), user_data) + } + + /// Create a new track directly from an [`Input`], user data to be associated with the track, and a custom [`Uuid`]. + #[must_use] + pub fn new_with_uuid_and_data( + input: Input, + uuid: Uuid, + user_data: Arc, + ) -> Self { Self { playing: PlayMode::default(), volume: 1.0, @@ -125,6 +142,7 @@ impl Track { events: EventStore::new_local(), loops: LoopState::Finite(0), uuid, + user_data, } } @@ -180,7 +198,7 @@ impl Track { pub(crate) fn into_context(self) -> (TrackHandle, TrackContext) { let (tx, receiver) = flume::unbounded(); - let handle = TrackHandle::new(tx, self.uuid); + let handle = TrackHandle::new(tx, self.uuid, self.user_data.clone()); let context = TrackContext { handle: handle.clone(),