Tracks: Replace RwLock<TypeMap> data store with Arc<dyn Any> (#219)

This commit is contained in:
Gnome!
2024-01-21 19:45:48 +00:00
committed by Kyle Simpson
parent 2bcc5223fe
commit 0d6a226910
4 changed files with 45 additions and 31 deletions

View File

@@ -54,7 +54,6 @@ tracing = { version = "0.1", features = ["log"] }
tracing-futures = "0.2" tracing-futures = "0.2"
twilight-gateway = { default-features = false, optional = true, version = "0.15.0" } twilight-gateway = { default-features = false, optional = true, version = "0.15.0" }
twilight-model = { 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" }
typenum = { optional = true, version = "1.17.0" } typenum = { optional = true, version = "1.17.0" }
url = { optional = true, version = "2" } url = { optional = true, version = "2" }
uuid = { features = ["v4"], optional = true, version = "1" } uuid = { features = ["v4"], optional = true, version = "1" }
@@ -111,7 +110,6 @@ driver = [
"dep:tokio", "dep:tokio",
"dep:tokio-tungstenite", "dep:tokio-tungstenite",
"dep:tokio-util", "dep:tokio-util",
"dep:typemap_rev",
"dep:typenum", "dep:typenum",
"dep:url", "dep:url",
"dep:uuid", "dep:uuid",

View File

@@ -112,8 +112,6 @@ mod ws;
pub use discortp as packet; pub use discortp as packet;
#[cfg(feature = "driver")] #[cfg(feature = "driver")]
pub use serenity_voice_model as model; 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. // Re-export serde-json APIs locally to minimise conditional config elsewhere.
#[cfg(not(feature = "simd-json"))] #[cfg(not(feature = "simd-json"))]

View File

@@ -1,9 +1,8 @@
use super::*; use super::*;
use crate::events::{Event, EventData, EventHandler}; use crate::events::{Event, EventData, EventHandler};
use flume::{Receiver, Sender}; use flume::{Receiver, Sender};
use std::{fmt, sync::Arc}; use std::{any::Any, sync::Arc, time::Duration};
use tokio::sync::RwLock; use uuid::Uuid;
use typemap_rev::TypeMap;
#[derive(Clone, Debug)] #[derive(Clone, Debug)]
/// Handle for safe control of a [`Track`] from other threads, outside /// Handle for safe control of a [`Track`] from other threads, outside
@@ -18,20 +17,11 @@ pub struct TrackHandle {
inner: Arc<InnerHandle>, inner: Arc<InnerHandle>,
} }
#[derive(Debug)]
struct InnerHandle { struct InnerHandle {
command_channel: Sender<TrackCommand>, command_channel: Sender<TrackCommand>,
uuid: Uuid, uuid: Uuid,
typemap: RwLock<TypeMap>, data: Arc<dyn Any + Send + Sync + 'static>,
}
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", &"<LOCK>")
.finish()
}
} }
impl TrackHandle { impl TrackHandle {
@@ -39,11 +29,15 @@ impl TrackHandle {
/// ///
/// [`Input`]: crate::input::Input /// [`Input`]: crate::input::Input
#[must_use] #[must_use]
pub(crate) fn new(command_channel: Sender<TrackCommand>, uuid: Uuid) -> Self { pub(crate) fn new(
command_channel: Sender<TrackCommand>,
uuid: Uuid,
data: Arc<dyn Any + Send + Sync + 'static>,
) -> Self {
let inner = Arc::new(InnerHandle { let inner = Arc::new(InnerHandle {
command_channel, command_channel,
uuid, uuid,
typemap: RwLock::new(TypeMap::new()), data,
}); });
Self { inner } Self { inner }
@@ -197,16 +191,22 @@ impl TrackHandle {
self.inner.uuid 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. /// to be attached to any track.
/// ///
/// Driver code will never attempt to lock access to this map, /// # Panics
/// preventing deadlock/stalling. /// 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] #[must_use]
pub fn typemap(&self) -> &RwLock<TypeMap> { pub fn data<Data>(&self) -> Arc<Data>
&self.inner.typemap 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] #[inline]

View File

@@ -41,7 +41,7 @@ pub use self::{
pub(crate) use command::*; pub(crate) use command::*;
use crate::{constants::*, driver::tasks::message::*, events::EventStore, input::Input}; 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; use uuid::Uuid;
/// Initial state for audio playback. /// Initial state for audio playback.
@@ -104,20 +104,37 @@ pub struct Track {
/// ///
/// Defaults to a random 128-bit number. /// Defaults to a random 128-bit number.
pub uuid: Uuid, pub uuid: Uuid,
/// Any data to be associated with the track.
pub user_data: Arc<dyn Any + Send + Sync>,
} }
impl Track { impl Track {
/// Create a new track directly from an [`Input`] and a random [`Uuid`]. /// Create a new track directly from an [`Input`] and a random [`Uuid`].
#[must_use] #[must_use]
pub fn new(input: Input) -> Self { pub fn new(input: Input) -> Self {
let uuid = Uuid::new_v4(); Self::new_with_uuid(input, Uuid::new_v4())
Self::new_with_uuid(input, uuid)
} }
/// Create a new track directly from an [`Input`] with a custom [`Uuid`]. /// Create a new track directly from an [`Input`] with a custom [`Uuid`].
#[must_use] #[must_use]
pub fn new_with_uuid(input: Input, uuid: Uuid) -> Self { 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<dyn Any + Send + Sync + 'static>) -> 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<dyn Any + Send + Sync + 'static>,
) -> Self {
Self { Self {
playing: PlayMode::default(), playing: PlayMode::default(),
volume: 1.0, volume: 1.0,
@@ -125,6 +142,7 @@ impl Track {
events: EventStore::new_local(), events: EventStore::new_local(),
loops: LoopState::Finite(0), loops: LoopState::Finite(0),
uuid, uuid,
user_data,
} }
} }
@@ -180,7 +198,7 @@ impl Track {
pub(crate) fn into_context(self) -> (TrackHandle, TrackContext) { pub(crate) fn into_context(self) -> (TrackHandle, TrackContext) {
let (tx, receiver) = flume::unbounded(); 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 { let context = TrackContext {
handle: handle.clone(), handle: handle.clone(),