// Copyright 2020 The ChromiumOS Authors1// Use of this source code is governed by a BSD-style license that can be2// found in the LICENSE file.34use std::time::Duration;56pub use base_event_token_derive::*;7use smallvec::SmallVec;89use crate::descriptor::AsRawDescriptor;10use crate::platform::EventContext;11use crate::RawDescriptor;12use crate::Result;1314/// Trait that can be used to associate events with arbitrary enums when using15/// `WaitContext`.16///17/// Simple enums that have no or primitive variant data data can use the `#[derive(EventToken)]`18/// custom derive to implement this trait. See19/// [event_token_derive::event_token](../base_event_token_derive/fn.event_token.html) for details.20pub trait EventToken {21/// Converts this token into a u64 that can be turned back into a token via `from_raw_token`.22fn as_raw_token(&self) -> u64;2324/// Converts a raw token as returned from `as_raw_token` back into a token.25///26/// It is invalid to give a raw token that was not returned via `as_raw_token` from the same27/// `Self`. The implementation can expect that this will never happen as a result of its usage28/// in `WaitContext`.29fn from_raw_token(data: u64) -> Self;30}3132impl EventToken for usize {33fn as_raw_token(&self) -> u64 {34*self as u6435}3637fn from_raw_token(data: u64) -> Self {38data as Self39}40}4142impl EventToken for u64 {43fn as_raw_token(&self) -> u64 {44*self45}4647fn from_raw_token(data: u64) -> Self {48data as Self49}50}5152impl EventToken for u32 {53fn as_raw_token(&self) -> u64 {54u64::from(*self)55}5657fn from_raw_token(data: u64) -> Self {58data as Self59}60}6162impl EventToken for u16 {63fn as_raw_token(&self) -> u64 {64u64::from(*self)65}6667fn from_raw_token(data: u64) -> Self {68data as Self69}70}7172impl EventToken for u8 {73fn as_raw_token(&self) -> u64 {74u64::from(*self)75}7677fn from_raw_token(data: u64) -> Self {78data as Self79}80}8182impl EventToken for () {83fn as_raw_token(&self) -> u64 {84085}8687fn from_raw_token(_data: u64) -> Self {}88}8990/// Represents an event that has been signaled and waited for via a wait function.91#[derive(Copy, Clone, Debug)]92pub struct TriggeredEvent<T: EventToken> {93pub token: T,94pub is_readable: bool,95pub is_writable: bool,96pub is_hungup: bool,97}9899/// Represents types of events to watch for.100#[derive(Copy, Clone, Debug, PartialEq, Eq)]101pub enum EventType {102// Used to to temporarily stop waiting for events without103// removing the associated descriptor from the WaitContext.104// In most cases if a descriptor no longer needs to be105// waited on, prefer removing it entirely with106// WaitContext#delete107None,108Read,109Write,110ReadWrite,111}112113/// Used to wait for multiple objects which are eligible for waiting.114///115/// # Example116///117/// ```118/// use base::{Event, EventToken, Result, WaitContext};119///120/// #[derive(EventToken, Copy, Clone, Debug, PartialEq, Eq)]121/// enum ExampleToken {122/// SomeEvent(u32),123/// AnotherEvent,124/// }125///126/// let evt1 = Event::new()?;127/// let evt2 = Event::new()?;128/// let another_evt = Event::new()?;129///130/// let ctx: WaitContext<ExampleToken> = WaitContext::build_with(&[131/// (&evt1, ExampleToken::SomeEvent(1)),132/// (&evt2, ExampleToken::SomeEvent(2)),133/// (&another_evt, ExampleToken::AnotherEvent),134/// ])?;135///136/// // Trigger one of the `SomeEvent` events.137/// evt2.signal()?;138///139/// // Wait for an event to fire. `wait()` will return immediately in this example because `evt2`140/// // has already been triggered, but in normal use, `wait()` will block until at least one event141/// // is signaled by another thread or process.142/// let events = ctx.wait()?;143/// let tokens: Vec<ExampleToken> = events.iter().filter(|e| e.is_readable)144/// .map(|e| e.token).collect();145/// assert_eq!(tokens, [ExampleToken::SomeEvent(2)]);146///147/// // Reset evt2 so it doesn't trigger again in the next `wait()` call.148/// let _ = evt2.reset()?;149///150/// // Trigger a different event.151/// another_evt.signal()?;152///153/// let events = ctx.wait()?;154/// let tokens: Vec<ExampleToken> = events.iter().filter(|e| e.is_readable)155/// .map(|e| e.token).collect();156/// assert_eq!(tokens, [ExampleToken::AnotherEvent]);157///158/// let _ = another_evt.reset()?;159/// # Ok::<(), base::Error>(())160/// ```161pub struct WaitContext<T: EventToken>(pub(crate) EventContext<T>);162163impl<T: EventToken> WaitContext<T> {164/// Creates a new WaitContext.165pub fn new() -> Result<WaitContext<T>> {166EventContext::new().map(WaitContext)167}168169/// Creates a new WaitContext with the the associated triggers.170pub fn build_with(triggers: &[(&dyn AsRawDescriptor, T)]) -> Result<WaitContext<T>> {171let ctx = WaitContext::new()?;172ctx.add_many(triggers)?;173Ok(ctx)174}175176/// Adds a trigger to the WaitContext.177pub fn add(&self, descriptor: &dyn AsRawDescriptor, token: T) -> Result<()> {178self.add_for_event(descriptor, EventType::Read, token)179}180181/// Adds a trigger to the WaitContext watching for a specific type of event182pub fn add_for_event(183&self,184descriptor: &dyn AsRawDescriptor,185event_type: EventType,186token: T,187) -> Result<()> {188self.0.add_for_event(descriptor, event_type, token)189}190191/// Adds multiple triggers to the WaitContext.192pub fn add_many(&self, triggers: &[(&dyn AsRawDescriptor, T)]) -> Result<()> {193for trigger in triggers {194self.add(trigger.0, T::from_raw_token(trigger.1.as_raw_token()))?195}196Ok(())197}198199/// Modifies a trigger already added to the WaitContext. If the descriptor is200/// already registered, its associated token will be updated.201pub fn modify(202&self,203descriptor: &dyn AsRawDescriptor,204event_type: EventType,205token: T,206) -> Result<()> {207self.0.modify(descriptor, event_type, token)208}209210/// Removes the given handle from triggers registered in the WaitContext if211/// present.212pub fn delete(&self, descriptor: &dyn AsRawDescriptor) -> Result<()> {213self.0.delete(descriptor)214}215216/// Waits for one or more of the registered triggers to become signaled.217pub fn wait(&self) -> Result<SmallVec<[TriggeredEvent<T>; 16]>> {218self.wait_timeout(Duration::new(i64::MAX as u64, 0))219}220221/// Waits for one or more of the registered triggers to become signaled, failing if no triggers222/// are signaled before the designated timeout has elapsed.223pub fn wait_timeout(&self, timeout: Duration) -> Result<SmallVec<[TriggeredEvent<T>; 16]>> {224self.0.wait_timeout(timeout)225}226}227228impl<T: EventToken> AsRawDescriptor for WaitContext<T> {229fn as_raw_descriptor(&self) -> RawDescriptor {230self.0.as_raw_descriptor()231}232}233234#[cfg(test)]235mod tests {236use base_event_token_derive::EventToken;237238use super::*;239240#[test]241#[allow(dead_code)]242fn event_token_derive() {243#[derive(EventToken)]244enum EmptyToken {}245246#[derive(PartialEq, Debug, EventToken)]247enum Token {248Alpha,249Beta,250// comments251Gamma(u32),252Delta { index: usize },253Omega,254}255256assert_eq!(257Token::from_raw_token(Token::Alpha.as_raw_token()),258Token::Alpha259);260assert_eq!(261Token::from_raw_token(Token::Beta.as_raw_token()),262Token::Beta263);264assert_eq!(265Token::from_raw_token(Token::Gamma(55).as_raw_token()),266Token::Gamma(55)267);268assert_eq!(269Token::from_raw_token(Token::Delta { index: 100 }.as_raw_token()),270Token::Delta { index: 100 }271);272assert_eq!(273Token::from_raw_token(Token::Omega.as_raw_token()),274Token::Omega275);276}277}278279280