pub struct TransientSource<T> { /* private fields */ }
Expand description
A TransientSource
wraps a Calloop event source and manages its
registration. A user of this type only needs to perform the usual Calloop
calls (process_events()
and *register()
) and the return value of
process_events()
.
Rather than needing to check for the full set of
PostAction
values returned from process_events()
,
you can just check for Continue
or Reregister
and pass that back out
through your own process_events()
implementation. In your registration
functions, you then only need to call the same function on this type ie.
register()
inside register()
etc.
For example, say you have a source that contains a channel along with some other logic. If the channel’s sending end has been dropped, it needs to be removed from the loop. So to manage this, you use this in your struct:
struct CompositeSource {
// Event source for channel.
mpsc_receiver: TransientSource<calloop::channel::Channel<T>>,
// Any other fields go here...
}
To create the transient source, you can simply use the Into
implementation:
let (sender, source) = channel();
let mpsc_receiver: TransientSource<Channel> = source.into();
(If you want to start off with an empty TransientSource
, you can just use
Default::default()
instead.)
TransientSource
implements EventSource
and passes
through process_events()
calls, so in the parent’s process_events()
implementation you can just do this:
fn process_events<F>(
&mut self,
readiness: calloop::Readiness,
token: calloop::Token,
callback: F,
) -> Result<calloop::PostAction, Self::Error>
where
F: FnMut(Self::Event, &mut Self::Metadata) -> Self::Ret,
{
let channel_return = self.mpsc_receiver.process_events(readiness, token, callback)?;
// Perform other logic here...
Ok(channel_return)
}
Note that:
-
You can call
process_events()
on theTransientSource<Channel>
even if the channel has been unregistered and dropped. All that will happen is that you won’t get any events from it. -
The
PostAction
returned fromprocess_events()
will only ever bePostAction::Continue
orPostAction::Reregister
. You will still need to combine this with the result of any other sources (transient or not).
Once you return channel_return
from your process_events()
method (and
assuming it propagates all the way up to the event loop itself through any
other event sources), the event loop might call reregister()
on your
source. All your source has to do is:
fn reregister(
&mut self,
poll: &mut calloop::Poll,
token_factory: &mut calloop::TokenFactory,
) -> crate::Result<()> {
self.mpsc_receiver.reregister(poll, token_factory)?;
// Other registration actions...
Ok(())
}
The TransientSource
will take care of updating the registration of the
inner source, even if it actually needs to be unregistered or initially
registered.
§Replacing or removing TransientSource
s
Not properly removing or replacing TransientSource
s can cause spurious
wakeups of the event loop, and in some cases can leak file descriptors or
fail to free entries in Calloop’s internal data structures. No unsoundness
or undefined behaviour will result, but leaking file descriptors can result
in errors or panics.
If you want to remove a source before it returns PostAction::Remove
, use
the TransientSource::remove()
method. If you want to replace a source
with another one, use the TransientSource::replace()
method. Either of
these may be called at any time during processing or from outside the event
loop. Both require either returning PostAction::Reregister
from the
process_event()
call that does this, or reregistering the event source
some other way eg. via the top-level loop handle.
If, instead, you directly assign a new source to the variable holding the
TransientSource
, the inner source will be dropped before it can be
unregistered. For example:
self.mpsc_receiver = Default::default();
self.mpsc_receiver = new_channel.into();
Implementations§
source§impl<T> TransientSource<T>
impl<T> TransientSource<T>
sourcepub fn map<F, U>(&mut self, f: F) -> Option<U>
pub fn map<F, U>(&mut self, f: F) -> Option<U>
Apply a function to the enclosed source, if it exists and is not about to be removed.
sourcepub fn remove(&mut self)
pub fn remove(&mut self)
Removes the wrapped event source from the event loop and this wrapper.
If this is called from outside of the event loop, you will need to wake
up the event loop for any changes to take place. If it is called from
within the event loop, you must return PostAction::Reregister
from
your own event source’s process_events()
, and the source will be
unregistered as needed after it exits.
sourcepub fn replace(&mut self, new: T)
pub fn replace(&mut self, new: T)
Replace the currently wrapped source with the given one. No more events will be generated from the old source after this point. The old source will not be dropped immediately, it will be kept so that it can be deregistered.
If this is called from outside of the event loop, you will need to wake
up the event loop for any changes to take place. If it is called from
within the event loop, you must return PostAction::Reregister
from
your own event source’s process_events()
, and the sources will be
registered and unregistered as needed after it exits.
Trait Implementations§
source§impl<T: Debug> Debug for TransientSource<T>
impl<T: Debug> Debug for TransientSource<T>
source§impl<T: Default> Default for TransientSource<T>
impl<T: Default> Default for TransientSource<T>
source§fn default() -> TransientSource<T>
fn default() -> TransientSource<T>
source§impl<T: EventSource> EventSource for TransientSource<T>
impl<T: EventSource> EventSource for TransientSource<T>
source§type Event = <T as EventSource>::Event
type Event = <T as EventSource>::Event
source§type Error = <T as EventSource>::Error
type Error = <T as EventSource>::Error
process_events()
(not the user callback!).source§fn process_events<F>(
&mut self,
readiness: Readiness,
token: Token,
callback: F,
) -> Result<PostAction, Self::Error>
fn process_events<F>( &mut self, readiness: Readiness, token: Token, callback: F, ) -> Result<PostAction, Self::Error>
source§fn register(
&mut self,
poll: &mut Poll,
token_factory: &mut TokenFactory,
) -> Result<()>
fn register( &mut self, poll: &mut Poll, token_factory: &mut TokenFactory, ) -> Result<()>
source§fn reregister(
&mut self,
poll: &mut Poll,
token_factory: &mut TokenFactory,
) -> Result<()>
fn reregister( &mut self, poll: &mut Poll, token_factory: &mut TokenFactory, ) -> Result<()>
source§fn unregister(&mut self, poll: &mut Poll) -> Result<()>
fn unregister(&mut self, poll: &mut Poll) -> Result<()>
source§const NEEDS_EXTRA_LIFECYCLE_EVENTS: bool = false
const NEEDS_EXTRA_LIFECYCLE_EVENTS: bool = false
EventSource::before_sleep
and EventSource::before_handle_events
notifications. These are opt-in because
they require more expensive checks, and almost all sources will not need these notificationssource§fn before_sleep(&mut self) -> Result<Option<(Readiness, Token)>>
fn before_sleep(&mut self) -> Result<Option<(Readiness, Token)>>
poll
is about to begin Read moresource§fn before_handle_events(&mut self, events: EventIterator<'_>)
fn before_handle_events(&mut self, events: EventIterator<'_>)
EventSource::process_events
will
be called with the given events for this source. The iterator may be empty,
which indicates that no events were generated for this source Read more