@@ -413,7 +413,7 @@ impl Drop for TrackRequest {
413413 }
414414}
415415
416- /// A pending info lookup returned by [`TrackConsumer ::info`].
416+ /// A pending info lookup returned by [`TrackPending ::info`].
417417///
418418/// Resolves once the track's immutable [`Track`] is known: synchronously if a
419419/// producer already exists or the info is cached, otherwise once the dynamic
@@ -478,46 +478,46 @@ impl std::future::Future for InfoPending {
478478 }
479479}
480480
481- /// A pending subscription returned by [`TrackConsumer ::subscribe`].
481+ /// A pending subscription returned by [`TrackPending ::subscribe`].
482482///
483483/// The subscription isn't live until the publisher accepts it (for the wire,
484484/// SUBSCRIBE_OK). It implements [`Future`], so `.await` it to get the
485485/// [`TrackSubscriber`] (or an error). Poll-based callers can instead drive it
486486/// with [`Self::poll_ok`] inside a `kio` poll loop.
487- pub struct TrackPending {
488- inner : TrackPendingInner ,
487+ pub struct SubscribePending {
488+ inner : SubscribePendingInner ,
489489 /// Kept alive between `Future::poll` calls so its registration in the
490490 /// resolver channel stays valid until the next poll replaces it.
491491 waiter : Option < kio:: Waiter > ,
492492}
493493
494- enum TrackPendingInner {
494+ enum SubscribePendingInner {
495495 /// Resolved synchronously: the track already existed, or it failed immediately.
496496 Ready ( Result < TrackSubscriber , Error > ) ,
497497 /// Waiting for the publisher to accept or deny via the dynamic handler.
498498 Waiting ( kio:: Consumer < PendingSlot > ) ,
499499}
500500
501- impl TrackPending {
501+ impl SubscribePending {
502502 fn ready ( result : Result < TrackSubscriber , Error > ) -> Self {
503503 Self {
504- inner : TrackPendingInner :: Ready ( result) ,
504+ inner : SubscribePendingInner :: Ready ( result) ,
505505 waiter : None ,
506506 }
507507 }
508508
509509 fn waiting ( consumer : kio:: Consumer < PendingSlot > ) -> Self {
510510 Self {
511- inner : TrackPendingInner :: Waiting ( consumer) ,
511+ inner : SubscribePendingInner :: Waiting ( consumer) ,
512512 waiter : None ,
513513 }
514514 }
515515
516516 /// Poll for the resolved [`TrackSubscriber`], without blocking.
517517 pub fn poll_ok ( & self , waiter : & kio:: Waiter ) -> Poll < Result < TrackSubscriber , Error > > {
518518 match & self . inner {
519- TrackPendingInner :: Ready ( result) => Poll :: Ready ( result. clone ( ) ) ,
520- TrackPendingInner :: Waiting ( consumer) => match consumer. poll ( waiter, |slot| match & * * slot {
519+ SubscribePendingInner :: Ready ( result) => Poll :: Ready ( result. clone ( ) ) ,
520+ SubscribePendingInner :: Waiting ( consumer) => match consumer. poll ( waiter, |slot| match & * * slot {
521521 Some ( result) => Poll :: Ready ( result. clone ( ) ) ,
522522 None => Poll :: Pending ,
523523 } ) {
@@ -533,7 +533,7 @@ impl TrackPending {
533533 }
534534}
535535
536- impl std:: future:: Future for TrackPending {
536+ impl std:: future:: Future for SubscribePending {
537537 type Output = Result < TrackSubscriber , Error > ;
538538
539539 fn poll ( self : std:: pin:: Pin < & mut Self > , cx : & mut std:: task:: Context < ' _ > ) -> Poll < Self :: Output > {
@@ -725,40 +725,40 @@ impl Deref for BroadcastConsumer {
725725impl BroadcastConsumer {
726726 /// Get a handle to a track on this broadcast.
727727 ///
728- /// This is a cheap, synchronous lookup that returns a [`TrackConsumer `] bound
728+ /// This is a cheap, synchronous lookup that returns a [`TrackPending `] bound
729729 /// to `name`. Nothing is sent to the publisher yet: call
730- /// [`TrackConsumer ::subscribe`] to open a live subscription (blocking on
730+ /// [`TrackPending ::subscribe`] to open a live subscription (blocking on
731731 /// SUBSCRIBE_OK), or hold the handle and subscribe later.
732- pub fn consume_track ( & self , name : & str ) -> TrackConsumer {
733- TrackConsumer {
732+ pub fn consume_track ( & self , name : & str ) -> TrackPending {
733+ TrackPending {
734734 broadcast : self . clone ( ) ,
735735 name : name. to_string ( ) ,
736736 }
737737 }
738738
739- /// Register a subscription for `name` and return a [`TrackPending `] that
739+ /// Register a subscription for `name` and return a [`SubscribePending `] that
740740 /// resolves once the publisher accepts it.
741741 ///
742742 /// Reuses a live producer if one is already publishing the track (the pending
743743 /// resolves right away), otherwise queues a dynamic request served via
744744 /// [`BroadcastDynamic::requested_track`] and [`TrackRequest::accept`] (for the
745745 /// wire this is SUBSCRIBE_OK). Resolves to [`Error::NotFound`] if no dynamic
746746 /// producer exists to handle the request.
747- fn request_subscribe ( & self , name : & str , subscription : Subscription ) -> TrackPending {
747+ fn request_subscribe ( & self , name : & str , subscription : Subscription ) -> SubscribePending {
748748 // Upgrade to a temporary producer so we can modify the state.
749749 let Some ( producer) = self . state . produce ( ) else {
750750 let err = self . state . read ( ) . abort . clone ( ) . unwrap_or ( Error :: Dropped ) ;
751- return TrackPending :: ready ( Err ( err) ) ;
751+ return SubscribePending :: ready ( Err ( err) ) ;
752752 } ;
753753 let mut state = match modify ( & producer) {
754754 Ok ( state) => state,
755- Err ( err) => return TrackPending :: ready ( Err ( err) ) ,
755+ Err ( err) => return SubscribePending :: ready ( Err ( err) ) ,
756756 } ;
757757
758758 // Reuse a live producer if one is already publishing the track.
759759 if let Some ( weak) = state. tracks . get ( name) {
760760 if !weak. is_closed ( ) {
761- return TrackPending :: ready ( Ok ( weak. subscribe ( subscription) ) ) ;
761+ return SubscribePending :: ready ( Ok ( weak. subscribe ( subscription) ) ) ;
762762 }
763763 // Drop the stale entry and fall through to a fresh request.
764764 state. tracks . remove ( name) ;
@@ -771,7 +771,7 @@ impl BroadcastConsumer {
771771 // Coalesce onto an in-flight request for the same name.
772772 pending. resolvers . push ( ( subscription, slot) ) ;
773773 } else if state. dynamic == 0 {
774- return TrackPending :: ready ( Err ( Error :: NotFound ) ) ;
774+ return SubscribePending :: ready ( Err ( Error :: NotFound ) ) ;
775775 } else {
776776 state. requests . insert (
777777 name. to_string ( ) ,
@@ -783,7 +783,7 @@ impl BroadcastConsumer {
783783 state. request_order . push_back ( name. to_string ( ) ) ;
784784 }
785785
786- TrackPending :: waiting ( consumer)
786+ SubscribePending :: waiting ( consumer)
787787 }
788788
789789 /// Resolve a track's immutable info, returning an [`InfoPending`].
@@ -841,6 +841,16 @@ impl BroadcastConsumer {
841841 InfoPending :: waiting ( consumer)
842842 }
843843
844+ /// The live producer's weak handle for `name`, if one is currently publishing.
845+ pub ( crate ) fn track_weak ( & self , name : & str ) -> Option < TrackWeak > {
846+ self . state
847+ . read ( )
848+ . tracks
849+ . get ( name)
850+ . filter ( |weak| !weak. is_closed ( ) )
851+ . cloned ( )
852+ }
853+
844854 /// Block until the broadcast is closed and return the cause.
845855 ///
846856 /// Returns [`Error::Dropped`] if every producer was dropped without an
@@ -878,29 +888,29 @@ impl BroadcastConsumer {
878888/// to multiple times, and clones are cheap.
879889// TODO: add `fetch` for one-shot retrieval of a past group range.
880890#[ derive( Clone ) ]
881- pub struct TrackConsumer {
891+ pub struct TrackPending {
882892 broadcast : BroadcastConsumer ,
883893 name : String ,
884894}
885895
886- impl TrackConsumer {
896+ impl TrackPending {
887897 /// The track name this handle is bound to.
888898 pub fn name ( & self ) -> & str {
889899 & self . name
890900 }
891901
892902 /// Open a live subscription.
893903 ///
894- /// Returns a [`TrackPending `] that resolves once the publisher accepts the
904+ /// Returns a [`SubscribePending `] that resolves once the publisher accepts the
895905 /// subscription (SUBSCRIBE_OK on the wire). `.await` it for the
896906 /// [`TrackSubscriber`], which carries the publisher's [`Track`] and reads its
897- /// groups; or drive it with [`TrackPending ::poll_ok`] from a poll loop.
907+ /// groups; or drive it with [`SubscribePending ::poll_ok`] from a poll loop.
898908 ///
899909 /// `subscription` is this subscriber's preferences and feeds the producer's
900910 /// [`TrackProducer::subscription`] aggregate; pass `None` for
901911 /// [`Subscription::default`]. Concurrent subscribers to the same name coalesce
902912 /// onto one request.
903- pub fn subscribe ( & self , subscription : impl Into < Option < Subscription > > ) -> TrackPending {
913+ pub fn subscribe ( & self , subscription : impl Into < Option < Subscription > > ) -> SubscribePending {
904914 self . broadcast
905915 . request_subscribe ( & self . name , subscription. into ( ) . unwrap_or_default ( ) )
906916 }
@@ -914,6 +924,43 @@ impl TrackConsumer {
914924 pub fn info ( & self ) -> InfoPending {
915925 self . broadcast . request_info ( & self . name )
916926 }
927+
928+ /// Resolve the track, returning a [`TrackConsumer`] once its producer exists.
929+ ///
930+ /// Elicits the track (like [`Self::info`]) and waits for the publisher to
931+ /// accept it. `await`ing the [`TrackPending`] itself is equivalent.
932+ pub async fn ok ( & self ) -> Result < TrackConsumer , Error > {
933+ // Resolving info means the producer was accepted (and its weak inserted).
934+ self . info ( ) . await ?;
935+ self . broadcast
936+ . track_weak ( & self . name )
937+ . map ( |weak| TrackConsumer { weak } )
938+ . ok_or ( Error :: Cancel )
939+ }
940+ }
941+
942+ /// A resolved track: its producer exists and its immutable [`Track`] is known, so
943+ /// subscribing and reading info are immediate. Obtained from [`TrackPending::ok`].
944+ #[ derive( Clone ) ]
945+ pub struct TrackConsumer {
946+ weak : TrackWeak ,
947+ }
948+
949+ impl TrackConsumer {
950+ /// The track name.
951+ pub fn name ( & self ) -> & str {
952+ & self . weak . info . name
953+ }
954+
955+ /// The track's immutable publisher properties.
956+ pub fn info ( & self ) -> Track {
957+ self . weak . info . clone ( )
958+ }
959+
960+ /// Open a live subscription. Pass `None` for [`Subscription::default`].
961+ pub fn subscribe ( & self , subscription : impl Into < Option < Subscription > > ) -> TrackSubscriber {
962+ self . weak . subscribe ( subscription. into ( ) . unwrap_or_default ( ) )
963+ }
917964}
918965
919966#[ cfg( test) ]
@@ -932,7 +979,7 @@ mod test {
932979 use super :: * ;
933980
934981 /// Subscribe and assert the result hasn't resolved yet (it stays pending until
935- /// a publisher accepts). Returns the [`TrackPending `] to resolve after accepting.
982+ /// a publisher accepts). Returns the [`SubscribePending `] to resolve after accepting.
936983 macro_rules! subscribe_pending {
937984 ( $consumer: expr, $name: expr) => { {
938985 let pending = $consumer. consume_track( $name) . subscribe( None ) ;
0 commit comments