From d42e09f72b825ca45ba3e08cf0614eef9acecca1 Mon Sep 17 00:00:00 2001 From: Kyle Simpson Date: Sat, 2 Jan 2021 23:43:28 +0000 Subject: [PATCH] Tracks: Add TypeMap to Handles. Adds a shared TypeMap per TrackHandle. This should greatly simplify the user experience for attaching additional per-track state which the driver does not care for. --- Cargo.toml | 5 +++++ src/lib.rs | 2 ++ src/tracks/handle.rs | 44 ++++++++++++++++++++++++++++++++++++-------- src/tracks/mod.rs | 5 ++++- 4 files changed, 47 insertions(+), 9 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 8817c9a..ea5bc16 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -91,6 +91,10 @@ optional = true version = "0.2" default-features = false +[dependencies.typemap_rev] +optional = true +version = "0.1" + [dependencies.url] optional = true version = "2" @@ -140,6 +144,7 @@ driver = [ "tokio/rt-core", "tokio/sync", "tokio/time", + "typemap_rev", "url", "uuid", "xsalsa20poly1305", diff --git a/src/lib.rs b/src/lib.rs index 40cd306..177472d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -66,6 +66,8 @@ pub use audiopus::{self as opus, Bitrate}; pub use discortp as packet; #[cfg(feature = "driver")] pub use serenity_voice_model as model; +#[cfg(feature = "driver")] +pub use typemap_rev as typemap; #[cfg(test)] use utils as test_utils; diff --git a/src/tracks/handle.rs b/src/tracks/handle.rs index d076c23..2800cc9 100644 --- a/src/tracks/handle.rs +++ b/src/tracks/handle.rs @@ -3,29 +3,45 @@ use crate::{ events::{Event, EventData, EventHandler}, input::Metadata, }; -use std::{sync::Arc, time::Duration}; -use tokio::sync::{mpsc::UnboundedSender, oneshot}; +use std::{fmt, sync::Arc, time::Duration}; +use tokio::sync::{mpsc::UnboundedSender, oneshot, RwLock}; +use typemap_rev::TypeMap; use uuid::Uuid; #[derive(Clone, Debug)] -/// Handle for safe control of a [`Track`] track from other threads, outside +/// Handle for safe control of a [`Track`] from other threads, outside /// of the audio mixing and voice handling context. /// -/// Almost all method calls here are fallible; in most cases, this will be because +/// These are cheap to clone, using `Arc<...>` internally. +/// +/// Many method calls here are fallible; in most cases, this will be because /// the underlying [`Track`] object has been discarded. Those which aren't refer -/// to immutable properties of the underlying stream. +/// to immutable properties of the underlying stream, or shared data not used +/// by the driver. /// /// [`Track`]: Track pub struct TrackHandle { inner: Arc, } -#[derive(Clone, Debug)] struct InnerHandle { command_channel: UnboundedSender, seekable: bool, - metadata: Box, uuid: Uuid, + metadata: Box, + 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("seekable", &self.seekable) + .field("uuid", &self.uuid) + .field("metadata", &self.metadata) + .field("typemap", &"") + .finish() + } } impl TrackHandle { @@ -42,8 +58,9 @@ impl TrackHandle { let inner = Arc::new(InnerHandle { command_channel, seekable, - metadata, uuid, + metadata, + typemap: RwLock::new(TypeMap::new()), }); Self { inner } @@ -209,6 +226,17 @@ impl TrackHandle { &self.inner.metadata } + /// Allows access to this track's attached TypeMap. + /// + /// TypeMaps allow 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. + pub fn typemap(&self) -> &RwLock { + &self.inner.typemap + } + #[inline] /// Send a raw command to the [`Track`] object. /// diff --git a/src/tracks/mod.rs b/src/tracks/mod.rs index fe060ea..911729e 100644 --- a/src/tracks/mod.rs +++ b/src/tracks/mod.rs @@ -382,9 +382,12 @@ pub fn create_player(source: Input) -> (Track, TrackHandle) { create_player_with_uuid(source, Uuid::new_v4()) } -/// Refer to the documentation for [`create_player`] however, allows for a custom uuid to be inserted into the Track and Handle +/// Creates a [`Track`] and [`TrackHandle`] as in [`create_player`], allowing +/// a custom UUID to be set. /// /// [`create_player`]: create_player +/// [`Track`]: Track +/// [`TrackHandle`]: TrackHandle pub fn create_player_with_uuid(source: Input, uuid: Uuid) -> (Track, TrackHandle) { let (tx, rx) = mpsc::unbounded_channel(); let can_seek = source.is_seekable();