#[ cfg( feature = "streaming-control" ) ]
mod private
{
use crate::error::{ Result, HuggingFaceError };
use tokio::sync::mpsc;
use futures_core::Stream;
use core::{ pin::Pin, task::{ Context, Poll } };
#[ derive( Debug, Clone, Copy, PartialEq, Eq ) ]
pub enum StreamControl
{
Pause,
Resume,
Cancel,
}
#[ derive( Debug, Clone, Copy, PartialEq, Eq ) ]
enum StreamState
{
Running,
Paused,
Cancelled,
}
#[ derive( Debug, Clone ) ]
pub struct ControlHandle
{
control_tx : mpsc::Sender< StreamControl >,
}
impl ControlHandle
{
#[ inline ]
#[ must_use ]
pub( crate ) fn new( control_tx : mpsc::Sender< StreamControl > ) -> Self
{
Self { control_tx }
}
#[ inline ]
pub async fn pause( &self ) -> Result< () >
{
self.control_tx
.send( StreamControl::Pause )
.await
.map_err( | _ | HuggingFaceError::Stream( "Control channel closed".to_string() ) )
}
#[ inline ]
pub async fn resume( &self ) -> Result< () >
{
self.control_tx
.send( StreamControl::Resume )
.await
.map_err( | _ | HuggingFaceError::Stream( "Control channel closed".to_string() ) )
}
#[ inline ]
pub async fn cancel( &self ) -> Result< () >
{
self.control_tx
.send( StreamControl::Cancel )
.await
.map_err( | _ | HuggingFaceError::Stream( "Control channel closed".to_string() ) )
}
#[ inline ]
pub fn try_pause( &self ) -> Result< () >
{
self.control_tx
.try_send( StreamControl::Pause )
.map_err( | _ | HuggingFaceError::Stream( "Control channel full or closed".to_string() ) )
}
#[ inline ]
pub fn try_resume( &self ) -> Result< () >
{
self.control_tx
.try_send( StreamControl::Resume )
.map_err( | _ | HuggingFaceError::Stream( "Control channel full or closed".to_string() ) )
}
#[ inline ]
pub fn try_cancel( &self ) -> Result< () >
{
self.control_tx
.try_send( StreamControl::Cancel )
.map_err( | _ | HuggingFaceError::Stream( "Control channel full or closed".to_string() ) )
}
}
pub struct ControlledStream
{
inner : mpsc::Receiver< Result< String > >,
control_rx : mpsc::Receiver< StreamControl >,
state : StreamState,
}
impl ControlledStream
{
#[ inline ]
#[ must_use ]
pub( crate ) fn new(
inner : mpsc::Receiver< Result< String > >,
control_rx : mpsc::Receiver< StreamControl >,
) -> Self
{
Self
{
inner,
control_rx,
state : StreamState::Running,
}
}
#[ inline ]
#[ must_use ]
pub fn is_paused( &self ) -> bool
{
matches!( self.state, StreamState::Paused )
}
#[ inline ]
#[ must_use ]
pub fn is_cancelled( &self ) -> bool
{
matches!( self.state, StreamState::Cancelled )
}
#[ inline ]
#[ must_use ]
pub fn is_running( &self ) -> bool
{
matches!( self.state, StreamState::Running )
}
}
impl Stream for ControlledStream
{
type Item = Result< String >;
#[ inline ]
fn poll_next( mut self : Pin< &mut Self >, cx : &mut Context< '_ > ) -> Poll< Option< Self::Item > >
{
loop
{
match self.control_rx.poll_recv( cx )
{
Poll::Ready( Some( control ) ) =>
{
match control
{
StreamControl::Pause =>
{
self.state = StreamState::Paused;
},
StreamControl::Resume =>
{
self.state = StreamState::Running;
},
StreamControl::Cancel =>
{
self.state = StreamState::Cancelled;
return Poll::Ready( None );
},
}
},
Poll::Ready( None ) =>
{
self.state = StreamState::Cancelled;
return Poll::Ready( None );
},
Poll::Pending => break,
}
}
if matches!( self.state, StreamState::Paused )
{
let _ = self.control_rx.poll_recv( cx );
return Poll::Pending;
}
if matches!( self.state, StreamState::Cancelled )
{
return Poll::Ready( None );
}
self.inner.poll_recv( cx )
}
}
impl core::fmt::Debug for ControlledStream
{
#[ inline ]
fn fmt( &self, f : &mut core::fmt::Formatter< '_ > ) -> core::fmt::Result
{
f.debug_struct( "ControlledStream" )
.field( "state", &self.state )
.finish_non_exhaustive()
}
}
#[ inline ]
#[ must_use ]
pub fn wrap_stream(
receiver : mpsc::Receiver< Result< String > >,
) -> ( ControlledStream, ControlHandle )
{
let ( control_tx, control_rx ) = mpsc::channel( 10 );
let stream = ControlledStream::new( receiver, control_rx );
let handle = ControlHandle::new( control_tx );
( stream, handle )
}
}
#[ cfg( feature = "streaming-control" ) ]
crate::mod_interface!
{
exposed use private::StreamControl;
exposed use private::ControlHandle;
exposed use private::ControlledStream;
exposed use private::wrap_stream;
}