Tracks: Replace RwLock<TypeMap> data store with Arc<dyn Any> (#219)
This commit is contained in:
@@ -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",
|
||||
|
||||
@@ -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"))]
|
||||
|
||||
@@ -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]
|
||||
|
||||
@@ -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(),
|
||||
|
||||
Reference in New Issue
Block a user