use std::{collections::vec_deque::VecDeque, time::Duration}; use super::filter::Filter; #[cfg(unix)] use super::source::unix::UnixInternalEventSource; #[cfg(windows)] use super::source::windows::WindowsEventSource; use super::{source::EventSource, timeout::PollTimeout, InternalEvent, Result}; /// Can be used to read `InternalEvent`s. pub(crate) struct InternalEventReader { events: VecDeque, source: Option>, skipped_events: Vec, } impl Default for InternalEventReader { fn default() -> Self { #[cfg(windows)] let source = WindowsEventSource::new(); #[cfg(unix)] let source = UnixInternalEventSource::new(); let source = source.ok().map(|x| Box::new(x) as Box); InternalEventReader { source, events: VecDeque::with_capacity(32), skipped_events: Vec::with_capacity(32), } } } impl InternalEventReader { #[cfg(feature = "event-stream")] pub(crate) fn wake(&self) { if let Some(source) = self.source.as_ref() { source.wake(); } } pub(crate) fn poll(&mut self, timeout: Option, filter: &F) -> Result where F: Filter, { for event in &self.events { if filter.eval(&event) { return Ok(true); } } let event_source = match self.source.as_mut() { Some(source) => source, None => { return Err(std::io::Error::new( std::io::ErrorKind::Other, "Failed to initialize input reader", ) .into()) } }; let poll_timeout = PollTimeout::new(timeout); loop { let maybe_event = match event_source.try_read(timeout)? { None => None, Some(event) => { if filter.eval(&event) { Some(event) } else { self.skipped_events.push(event); None } } }; if poll_timeout.elapsed() || maybe_event.is_some() { self.events.extend(self.skipped_events.drain(..)); if let Some(event) = maybe_event { self.events.push_front(event); return Ok(true); } return Ok(false); } } } pub(crate) fn read(&mut self, filter: &F) -> Result where F: Filter, { let mut skipped_events = VecDeque::new(); loop { while let Some(event) = self.events.pop_front() { if filter.eval(&event) { while let Some(event) = skipped_events.pop_front() { self.events.push_back(event); } return Ok(event); } else { // We can not directly write events back to `self.events`. // If we did, we would put our self's into an endless loop // that would enqueue -> dequeue -> enqueue etc. // This happens because `poll` in this function will always return true if there are events in it's. // And because we just put the non-fulfilling event there this is going to be the case. // Instead we can store them into the temporary buffer, // and then when the filter is fulfilled write all events back in order. skipped_events.push_back(event); } } let _ = self.poll(None, filter)?; } } } #[cfg(test)] mod tests { use std::collections::VecDeque; use std::time::Duration; use crate::ErrorKind; #[cfg(unix)] use super::super::filter::CursorPositionFilter; use super::{ super::{filter::InternalEventFilter, Event}, {EventSource, InternalEvent, InternalEventReader}, }; #[test] fn test_poll_fails_without_event_source() { let mut reader = InternalEventReader { events: VecDeque::new(), source: None, skipped_events: Vec::with_capacity(32), }; assert!(reader.poll(None, &InternalEventFilter).is_err()); assert!(reader .poll(Some(Duration::from_secs(0)), &InternalEventFilter) .is_err()); assert!(reader .poll(Some(Duration::from_secs(10)), &InternalEventFilter) .is_err()); } #[test] fn test_poll_returns_true_for_matching_event_in_queue_at_front() { let mut reader = InternalEventReader { events: vec![InternalEvent::Event(Event::Resize(10, 10))].into(), source: None, skipped_events: Vec::with_capacity(32), }; assert!(reader.poll(None, &InternalEventFilter).unwrap()); } #[test] #[cfg(unix)] fn test_poll_returns_true_for_matching_event_in_queue_at_back() { let mut reader = InternalEventReader { events: vec![ InternalEvent::Event(Event::Resize(10, 10)), InternalEvent::CursorPosition(10, 20), ] .into(), source: None, skipped_events: Vec::with_capacity(32), }; assert!(reader.poll(None, &CursorPositionFilter).unwrap()); } #[test] fn test_read_returns_matching_event_in_queue_at_front() { const EVENT: InternalEvent = InternalEvent::Event(Event::Resize(10, 10)); let mut reader = InternalEventReader { events: vec![EVENT].into(), source: None, skipped_events: Vec::with_capacity(32), }; assert_eq!(reader.read(&InternalEventFilter).unwrap(), EVENT); } #[test] #[cfg(unix)] fn test_read_returns_matching_event_in_queue_at_back() { const CURSOR_EVENT: InternalEvent = InternalEvent::CursorPosition(10, 20); let mut reader = InternalEventReader { events: vec![InternalEvent::Event(Event::Resize(10, 10)), CURSOR_EVENT].into(), source: None, skipped_events: Vec::with_capacity(32), }; assert_eq!(reader.read(&CursorPositionFilter).unwrap(), CURSOR_EVENT); } #[test] #[cfg(unix)] fn test_read_does_not_consume_skipped_event() { const SKIPPED_EVENT: InternalEvent = InternalEvent::Event(Event::Resize(10, 10)); const CURSOR_EVENT: InternalEvent = InternalEvent::CursorPosition(10, 20); let mut reader = InternalEventReader { events: vec![SKIPPED_EVENT, CURSOR_EVENT].into(), source: None, skipped_events: Vec::with_capacity(32), }; assert_eq!(reader.read(&CursorPositionFilter).unwrap(), CURSOR_EVENT); assert_eq!(reader.read(&InternalEventFilter).unwrap(), SKIPPED_EVENT); } #[test] fn test_poll_timeouts_if_source_has_no_events() { let source = FakeSource::default(); let mut reader = InternalEventReader { events: VecDeque::new(), source: Some(Box::new(source)), skipped_events: Vec::with_capacity(32), }; assert!(!reader .poll(Some(Duration::from_secs(0)), &InternalEventFilter) .unwrap()); } #[test] fn test_poll_returns_true_if_source_has_at_least_one_event() { let source = FakeSource::with_events(&[InternalEvent::Event(Event::Resize(10, 10))]); let mut reader = InternalEventReader { events: VecDeque::new(), source: Some(Box::new(source)), skipped_events: Vec::with_capacity(32), }; assert!(reader.poll(None, &InternalEventFilter).unwrap()); assert!(reader .poll(Some(Duration::from_secs(0)), &InternalEventFilter) .unwrap()); } #[test] fn test_reads_returns_event_if_source_has_at_least_one_event() { const EVENT: InternalEvent = InternalEvent::Event(Event::Resize(10, 10)); let source = FakeSource::with_events(&[EVENT]); let mut reader = InternalEventReader { events: VecDeque::new(), source: Some(Box::new(source)), skipped_events: Vec::with_capacity(32), }; assert_eq!(reader.read(&InternalEventFilter).unwrap(), EVENT); } #[test] fn test_read_returns_events_if_source_has_events() { const EVENT: InternalEvent = InternalEvent::Event(Event::Resize(10, 10)); let source = FakeSource::with_events(&[EVENT, EVENT, EVENT]); let mut reader = InternalEventReader { events: VecDeque::new(), source: Some(Box::new(source)), skipped_events: Vec::with_capacity(32), }; assert_eq!(reader.read(&InternalEventFilter).unwrap(), EVENT); assert_eq!(reader.read(&InternalEventFilter).unwrap(), EVENT); assert_eq!(reader.read(&InternalEventFilter).unwrap(), EVENT); } #[test] fn test_poll_returns_false_after_all_source_events_are_consumed() { const EVENT: InternalEvent = InternalEvent::Event(Event::Resize(10, 10)); let source = FakeSource::with_events(&[EVENT, EVENT, EVENT]); let mut reader = InternalEventReader { events: VecDeque::new(), source: Some(Box::new(source)), skipped_events: Vec::with_capacity(32), }; assert_eq!(reader.read(&InternalEventFilter).unwrap(), EVENT); assert_eq!(reader.read(&InternalEventFilter).unwrap(), EVENT); assert_eq!(reader.read(&InternalEventFilter).unwrap(), EVENT); assert!(!reader .poll(Some(Duration::from_secs(0)), &InternalEventFilter) .unwrap()); } #[test] fn test_poll_propagates_error() { let source = FakeSource::with_error(ErrorKind::ResizingTerminalFailure("Foo".to_string())); let mut reader = InternalEventReader { events: VecDeque::new(), source: Some(Box::new(source)), skipped_events: Vec::with_capacity(32), }; assert_eq!( reader .poll(Some(Duration::from_secs(0)), &InternalEventFilter) .err() .map(|e| format!("{:?}", &e)), Some(format!( "{:?}", ErrorKind::ResizingTerminalFailure("Foo".to_string()) )) ); } #[test] fn test_read_propagates_error() { let source = FakeSource::with_error(ErrorKind::ResizingTerminalFailure("Foo".to_string())); let mut reader = InternalEventReader { events: VecDeque::new(), source: Some(Box::new(source)), skipped_events: Vec::with_capacity(32), }; assert_eq!( reader .read(&InternalEventFilter) .err() .map(|e| format!("{:?}", &e)), Some(format!( "{:?}", ErrorKind::ResizingTerminalFailure("Foo".to_string()) )) ); } #[test] fn test_poll_continues_after_error() { const EVENT: InternalEvent = InternalEvent::Event(Event::Resize(10, 10)); let source = FakeSource::new( &[EVENT, EVENT], ErrorKind::ResizingTerminalFailure("Foo".to_string()), ); let mut reader = InternalEventReader { events: VecDeque::new(), source: Some(Box::new(source)), skipped_events: Vec::with_capacity(32), }; assert_eq!(reader.read(&InternalEventFilter).unwrap(), EVENT); assert!(reader.read(&InternalEventFilter).is_err()); assert!(reader .poll(Some(Duration::from_secs(0)), &InternalEventFilter) .unwrap()); } #[test] fn test_read_continues_after_error() { const EVENT: InternalEvent = InternalEvent::Event(Event::Resize(10, 10)); let source = FakeSource::new( &[EVENT, EVENT], ErrorKind::ResizingTerminalFailure("Foo".to_string()), ); let mut reader = InternalEventReader { events: VecDeque::new(), source: Some(Box::new(source)), skipped_events: Vec::with_capacity(32), }; assert_eq!(reader.read(&InternalEventFilter).unwrap(), EVENT); assert!(reader.read(&InternalEventFilter).is_err()); assert_eq!(reader.read(&InternalEventFilter).unwrap(), EVENT); } #[derive(Default)] struct FakeSource { events: VecDeque, error: Option, } impl FakeSource { fn new(events: &[InternalEvent], error: ErrorKind) -> FakeSource { FakeSource { events: events.to_vec().into(), error: Some(error), } } fn with_events(events: &[InternalEvent]) -> FakeSource { FakeSource { events: events.to_vec().into(), error: None, } } fn with_error(error: ErrorKind) -> FakeSource { FakeSource { events: VecDeque::new(), error: Some(error), } } } impl EventSource for FakeSource { fn try_read( &mut self, _timeout: Option, ) -> Result, ErrorKind> { // Return error if set in case there's just one remaining event if self.events.len() == 1 { if let Some(error) = self.error.take() { return Err(error); } } // Return all events from the queue if let Some(event) = self.events.pop_front() { return Ok(Some(event)); } // Return error if there're no more events if let Some(error) = self.error.take() { return Err(error); } // Timeout Ok(None) } fn wake(&self) {} } }