ltk/event_loop/
sources.rsuse std::time::Duration;
#[ cfg( not( queued_sources ) ) ]
use calloop::channel::Event;
#[ cfg( not( queued_sources ) ) ]
use calloop::timer::{ TimeoutAction, Timer };
#[ cfg( not( queued_sources ) ) ]
use calloop::{ LoopHandle, RegistrationToken };
use crate::app::ChannelSender;
#[ cfg( not( queued_sources ) ) ]
pub( crate ) struct Sources<D: 'static>
{
handle: LoopHandle<'static, D>,
}
#[ cfg( not( queued_sources ) ) ]
pub( crate ) struct TimerToken( RegistrationToken );
#[ cfg( not( queued_sources ) ) ]
impl<D: 'static> Sources<D>
{
pub( crate ) fn new( handle: LoopHandle<'static, D> ) -> Self
{
Self { handle }
}
pub( crate ) fn insert_timer( &self, delay: Duration, mut tick: impl FnMut( &mut D ) -> Option<Duration> + 'static ) -> Result<TimerToken, String>
{
self.handle.insert_source( Timer::from_duration( delay ), move |_, _, data|
{
match tick( data )
{
Some( next ) => TimeoutAction::ToDuration( next ),
None => TimeoutAction::Drop,
}
} )
.map( TimerToken )
.map_err( |e| format!( "{e:?}" ) )
}
pub( crate ) fn remove( &self, token: TimerToken )
{
self.handle.remove( token.0 );
}
pub( crate ) fn channel<T: 'static>( &self, mut on_msg: impl FnMut( T, &mut D ) + 'static ) -> Result<ChannelSender<T>, String>
{
let ( sender, messages ) = calloop::channel::channel::<T>();
self.handle.insert_source( messages, move |event, _, data|
{
if let Event::Msg( msg ) = event { on_msg( msg, data ); }
} )
.map_err( |e| format!( "{e:?}" ) )?;
Ok( ChannelSender::from_calloop( sender ) )
}
}
#[ cfg( queued_sources ) ]
pub( crate ) type Tick<D> = Box<dyn FnMut( &mut D ) -> Option<Duration>>;
#[ cfg( queued_sources ) ]
pub( crate ) type Drain<D> = Box<dyn FnMut( &mut D )>;
#[ cfg( queued_sources ) ]
struct Armed<D>
{
id: u64,
due: crate::time::Instant,
tick: Tick<D>,
}
#[ cfg( queued_sources ) ]
pub( crate ) struct Sources<D: 'static>
{
wake: fn(),
next_id: std::cell::Cell<u64>,
armed: std::cell::RefCell<Vec<Armed<D>>>,
running: std::cell::RefCell<Vec<u64>>,
cancelled: std::cell::RefCell<Vec<u64>>,
channels: std::cell::RefCell<Vec<Drain<D>>>,
}
#[ cfg( queued_sources ) ]
pub( crate ) struct TimerToken( u64 );
#[ cfg( queued_sources ) ]
impl<D: 'static> Sources<D>
{
pub( crate ) fn new( wake: fn() ) -> Self
{
Self
{
wake,
next_id: std::cell::Cell::new( 0 ),
armed: std::cell::RefCell::new( Vec::new() ),
running: std::cell::RefCell::new( Vec::new() ),
cancelled: std::cell::RefCell::new( Vec::new() ),
channels: std::cell::RefCell::new( Vec::new() ),
}
}
pub( crate ) fn insert_timer( &self, delay: Duration, tick: impl FnMut( &mut D ) -> Option<Duration> + 'static ) -> Result<TimerToken, String>
{
let id = self.next_id.get();
self.next_id.set( id + 1 );
self.armed.borrow_mut().push( Armed { id, due: crate::time::Instant::now() + delay, tick: Box::new( tick ) } );
Ok( TimerToken( id ) )
}
pub( crate ) fn remove( &self, token: TimerToken )
{
let mut armed = self.armed.borrow_mut();
if let Some( i ) = armed.iter().position( |t| t.id == token.0 )
{
armed.remove( i );
} else if self.running.borrow().contains( &token.0 ) {
self.cancelled.borrow_mut().push( token.0 );
}
}
pub( crate ) fn channel<T: 'static>( &self, mut on_msg: impl FnMut( T, &mut D ) + 'static ) -> Result<ChannelSender<T>, String>
{
let ( sender, messages ) = crate::channel::channel::<T>( self.wake );
self.channels.borrow_mut().push( Box::new( move |data|
{
while let Ok( msg ) = messages.try_recv() { on_msg( msg, data ); }
} ) );
Ok( sender )
}
pub( crate ) fn take_due( &self, now: crate::time::Instant ) -> Vec<( u64, Tick<D> )>
{
let ( due, later ): ( Vec<_>, Vec<_> ) = std::mem::take( &mut *self.armed.borrow_mut() ).into_iter().partition( |t| t.due <= now );
self.armed.borrow_mut().extend( later );
self.running.borrow_mut().extend( due.iter().map( |t| t.id ) );
due.into_iter().map( |t| ( t.id, t.tick ) ).collect()
}
pub( crate ) fn rearm( &self, id: u64, tick: Tick<D>, next: Option<Duration> )
{
self.running.borrow_mut().retain( |r| *r != id );
let mut cancelled = self.cancelled.borrow_mut();
if let Some( i ) = cancelled.iter().position( |c| *c == id )
{
cancelled.remove( i );
return;
}
if let Some( next ) = next
{
self.armed.borrow_mut().push( Armed { id, due: crate::time::Instant::now() + next, tick } );
}
}
pub( crate ) fn next_due( &self ) -> Option<crate::time::Instant>
{
self.armed.borrow().iter().map( |t| t.due ).min()
}
pub( crate ) fn take_channels( &self ) -> Vec<Drain<D>>
{
std::mem::take( &mut *self.channels.borrow_mut() )
}
pub( crate ) fn restore_channels( &self, mut drains: Vec<Drain<D>> )
{
let mut channels = self.channels.borrow_mut();
drains.append( &mut channels );
*channels = drains;
}
}
#[ cfg( queued_sources ) ]
impl<A: crate::app::App, P: crate::platform::Platform> super::AppData<A, P>
{
pub( crate ) fn dispatch_sources( &mut self )
{
for ( id, mut tick ) in self.sources.take_due( crate::time::Instant::now() )
{
let next = tick( self );
self.sources.rearm( id, tick, next );
}
let mut drains = self.sources.take_channels();
for drain in &mut drains
{
drain( self );
}
self.sources.restore_channels( drains );
}
}