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"
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" }
typenum = { optional = true, version = "1.17.0" }
url = { optional = true, version = "2" }
uuid = { features = ["v4"], optional = true, version = "1" }
@@ -111,7 +110,6 @@ driver = [
"dep:tokio",
"dep:tokio-tungstenite",
"dep:tokio-util",
"dep:typemap_rev",
"dep:typenum",
"dep:url",
"dep:uuid",

View File

@@ -112,8 +112,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"))]

View File

@@ -1,9 +1,8 @@
use super::*;
use crate::events::{Event, EventData, EventHandler};
use flume::{Receiver, Sender};
use std::{fmt, sync::Arc};
use tokio::sync::RwLock;
use typemap_rev::TypeMap;
use std::{any::Any, sync::Arc, time::Duration};
use uuid::Uuid;
#[derive(Clone, Debug)]
/// Handle for safe control of a [`Track`] from other threads, outside
@@ -18,20 +17,11 @@ pub struct TrackHandle {
inner: Arc<InnerHandle>,
}
#[derive(Debug)]
struct InnerHandle {
command_channel: Sender<TrackCommand>,
uuid: Uuid,
typemap: RwLock<TypeMap>,
}
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()
}
data: Arc<dyn Any + Send + Sync + 'static>,
}
impl TrackHandle {
@@ -39,11 +29,15 @@ impl TrackHandle {
///
/// [`Input`]: crate::input::Input
#[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 {
command_channel,
uuid,
typemap: RwLock::new(TypeMap::new()),
data,
});
Self { inner }
@@ -197,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<TypeMap> {
&self.inner.typemap
pub fn data<Data>(&self) -> Arc<Data>
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]

View File

@@ -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<dyn Any + Send + Sync>,
}
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<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 {
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(),