mod r#async;
#[cfg_attr(docsrs, doc(cfg(any(feature = "tokio", feature = "async-io"))))]
#[cfg(any(feature = "tokio", feature = "async-io"))]
pub use r#async::{AsyncEvents, AsyncReports};
#[cfg(test)]
mod tests;
use std::{
collections::VecDeque,
fmt, io,
iter::{self, FusedIterator, zip},
ops::RangeInclusive,
os::fd::{AsFd, AsRawFd, BorrowedFd, IntoRawFd, RawFd},
slice,
sync::Arc,
time::{Instant, SystemTime},
};
use crate::{
Evdev, Slot,
bits::{BitSet, BitValue},
drop::on_drop,
event::{
Abs, AbsEvent, EventKind, EventType, InputEvent, Key, KeyEvent, KeyState, Led, LedEvent,
Sound, SoundEvent, Switch, SwitchEvent, Syn, SynEvent,
},
raw::input::EVIOCGMTSLOTS,
read_raw,
};
const MAX_MT_SLOTS: i32 = 60;
#[derive(Clone, PartialEq)]
struct MtStorage {
data: Vec<i32>,
slots: u32,
codes: u32,
active_slot: u32,
}
impl fmt::Debug for MtStorage {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
struct FmtData<'a> {
data: &'a [i32],
slots: usize,
}
impl fmt::Debug for FmtData<'_> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let mut list = f.debug_list();
for chunk in self.data.chunks(self.slots + 1) {
list.entry(&Abs::from_raw(chunk[0] as u16));
list.entries(&chunk[1..]);
}
list.finish()
}
}
f.debug_struct("MtStorage")
.field("slots", &self.slots)
.field("codes", &self.codes)
.field("active_slot", &self.active_slot)
.field(
"data",
&FmtData {
data: &self.data,
slots: self.slots as usize,
},
)
.finish()
}
}
impl MtStorage {
fn empty() -> Self {
Self {
data: Vec::new(),
slots: 0,
codes: 0,
active_slot: 0,
}
}
fn current(evdev: &Evdev, abs_axes: &BitSet<Abs>) -> io::Result<Self> {
let mut this = Self {
data: Vec::new(),
slots: 0,
codes: 0,
active_slot: 0,
};
if !abs_axes.contains(Abs::MT_SLOT) {
return Ok(this);
}
if !abs_axes.contains(Abs::MT_TRACKING_ID) {
log::warn!(
"device {} advertises support for `ABS_MT_SLOT` but not `ABS_MT_TRACKING_ID`; multitouch support will not work",
evdev
.name()
.unwrap_or_else(|e| format!("(failed to fetch name: {e})")),
);
return Ok(this);
}
let mt_slot_info = evdev.abs_info(Abs::MT_SLOT)?;
if mt_slot_info.minimum() != 0 {
log::warn!("`ABS_MT_SLOT` has a non-0 minimum: {:?}", mt_slot_info);
}
let slot_count = mt_slot_info.maximum().saturating_add(1);
if mt_slot_info.maximum() > MAX_MT_SLOTS {
log::warn!(
"`ABS_MT_SLOT` declares too many slots: {:?} (only the first {} will be used)",
mt_slot_info,
MAX_MT_SLOTS,
);
}
this.slots = slot_count.clamp(0, MAX_MT_SLOTS) as u32;
this.active_slot = mt_slot_info.value().max(0) as u32;
this.data.clear();
this.codes = 0;
for mt_code in Abs::MT_SLOT.raw() + 1..Abs::MAX.raw() {
if !abs_axes.contains(Abs::from_raw(mt_code)) {
continue;
}
this.codes += 1;
let start_idx = this.data.len();
this.data
.resize(this.data.len() + 1 + this.slots as usize, 0);
this.data[start_idx] = mt_code.into();
unsafe {
evdev.ioctl(
"EVIOCGMTSLOTS",
EVIOCGMTSLOTS((this.slots as usize + 1) * 4),
this.data[start_idx..].as_mut_ptr().cast(),
)?;
}
}
this.data.shrink_to_fit();
Ok(this)
}
fn resync_from(
&mut self,
src: &MtStorage,
queue: &mut VecDeque<InputEvent>,
last_event: SystemTime,
) {
let mut emit = |ev: InputEvent| {
queue.push_back(ev.with_time(last_event));
};
assert!(
self.data.is_empty() || self.data.len() == src.data.len(),
"`self` must either be empty or have the same layout as `src`",
);
let was_empty = self.data.is_empty();
self.slots = src.slots;
self.codes = src.codes;
self.data.resize(src.data.len(), 0);
let chunk_size = self.slots as usize + 1;
for slot in 0..self.slots {
let mut slot_active = false;
for code in 0..self.codes {
let dest_chunk = &mut self.data[code as usize * chunk_size..][..chunk_size];
let src_chunk = &src.data[code as usize * chunk_size..][..chunk_size];
if dest_chunk[0] == 0 {
dest_chunk[0] = src_chunk[0];
} else {
assert_eq!(dest_chunk[0], src_chunk[0]);
}
let abs = Abs::from_raw(src_chunk[0] as _);
let dest = &mut dest_chunk[slot as usize + 1];
let src = &src_chunk[slot as usize + 1];
if *dest != *src {
if abs == Abs::MT_TRACKING_ID && *src == -1 && was_empty {
*dest = *src;
continue;
}
*dest = *src;
if !slot_active {
slot_active = true;
emit(AbsEvent::new(Abs::MT_SLOT, slot as _).into());
}
emit(AbsEvent::new(abs, *src as _).into());
}
}
}
if self.active_slot != src.active_slot {
self.active_slot = src.active_slot;
emit(AbsEvent::new(Abs::MT_SLOT, src.active_slot as _).into());
}
}
fn groups(&self) -> impl Iterator<Item = &[i32]> + '_ {
self.data
.chunks((self.slots + 1) as usize)
.take(self.codes as usize)
}
fn groups_mut(&mut self) -> impl Iterator<Item = &mut [i32]> + '_ {
self.data
.chunks_mut((self.slots + 1) as usize)
.take(self.codes as usize)
}
fn group_for_code(&self, code: Abs) -> Option<&[i32]> {
if code.raw() <= Abs::MT_SLOT.raw() || code.raw() > Abs::MAX.raw() {
return None;
}
self.groups().find_map(|grp| {
if grp[0] == i32::from(code.raw()) {
Some(&grp[1..])
} else {
None
}
})
}
fn mut_group_for_code(&mut self, code: Abs) -> Option<&mut [i32]> {
if code.raw() <= Abs::MT_SLOT.raw() || code.raw() > Abs::MAX.raw() {
return None;
}
self.groups_mut().find_map(|grp| {
if grp[0] == i32::from(code.raw()) {
Some(&mut grp[1..])
} else {
None
}
})
}
fn valid_slots(&self) -> ValidSlots<'_> {
ValidSlots {
iter: self
.group_for_code(Abs::MT_TRACKING_ID)
.unwrap_or(&[])
.iter()
.enumerate(),
}
}
}
#[derive(Debug)]
pub struct ValidSlots<'a> {
iter: iter::Enumerate<slice::Iter<'a, i32>>,
}
impl<'a> Iterator for ValidSlots<'a> {
type Item = Slot;
fn next(&mut self) -> Option<Self::Item> {
loop {
let (slot, &id) = self.iter.next()?;
if id >= 0 {
return Some(Slot::from_raw(slot as i32));
}
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
let upper = self.iter.len();
(0, Some(upper))
}
}
impl<'a> FusedIterator for ValidSlots<'a> {
}
#[derive(Debug)]
struct DeviceState {
keys: BitSet<Key>,
leds: BitSet<Led>,
sounds: BitSet<Sound>,
switches: BitSet<Switch>,
abs: [i32; Abs::MT_SLOT.raw() as usize],
abs_axes: BitSet<Abs>, mt_storage: MtStorage,
last_event: SystemTime,
}
impl DeviceState {
fn new(abs_axes: BitSet<Abs>) -> Self {
Self {
keys: BitSet::new(),
leds: BitSet::new(),
sounds: BitSet::new(),
switches: BitSet::new(),
abs: [0; Abs::MT_SLOT.raw() as usize],
abs_axes,
mt_storage: MtStorage::empty(),
last_event: SystemTime::now(),
}
}
fn current(evdev: &Evdev) -> io::Result<Self> {
let abs_axes = evdev.supported_abs_axes()?;
let mut abs = [0; Abs::MT_SLOT.raw() as usize];
for (i, value) in abs.iter_mut().enumerate() {
let axis = Abs::from_raw(i as _);
if abs_axes.contains(axis) {
let info = evdev.abs_info(axis)?;
*value = info.raw_value();
}
}
Ok(Self {
keys: evdev.key_state()?,
leds: evdev.led_state()?,
sounds: evdev.sound_state()?,
switches: evdev.switch_state()?,
abs,
abs_axes,
mt_storage: MtStorage::current(evdev, &abs_axes)?,
last_event: SystemTime::now(),
})
}
fn resync_from(&mut self, src: &DeviceState, queue: &mut VecDeque<InputEvent>) {
fn sync_bitset<V: BitValue>(
dest: &mut BitSet<V>,
src: BitSet<V>,
mut cb: impl FnMut(V, /* became set */ bool),
) {
for value in dest.symmetric_difference(&src) {
cb(value, src.contains(value));
}
*dest = src;
}
queue.clear();
let mut emit = |ev: InputEvent| {
queue.push_back(ev.with_time(self.last_event));
};
sync_bitset(&mut self.keys, src.keys, |key, on| {
let state = if on {
KeyState::PRESSED
} else {
KeyState::RELEASED
};
emit(KeyEvent::new(key, state).into());
});
sync_bitset(&mut self.leds, src.leds, |led, on| {
emit(LedEvent::new(led, on).into());
});
sync_bitset(&mut self.sounds, src.sounds, |snd, playing| {
emit(SoundEvent::new(snd, playing).into());
});
sync_bitset(&mut self.switches, src.switches, |sw, on| {
emit(SwitchEvent::new(sw, on).into());
});
for (abs, (dest, src)) in zip(&mut self.abs, src.abs).enumerate() {
if *dest != src {
emit(AbsEvent::new(Abs::from_raw(abs as u16), src).into());
*dest = src;
}
}
if self.abs_axes.contains(Abs::MT_SLOT) {
self.mt_storage
.resync_from(&src.mt_storage, queue, self.last_event);
}
if !queue.is_empty() {
log::debug!(
"resync injected {} events -> adding SYN_REPORT",
queue.len()
);
assert_ne!(queue.back().unwrap().event_type(), EventType::SYN);
queue.push_back(SynEvent::new(Syn::REPORT).with_time(self.last_event));
}
}
fn resync(&mut self, evdev: &Evdev, queue: &mut VecDeque<InputEvent>) -> io::Result<()> {
let now = Instant::now();
let _d = on_drop(|| log::debug!("`EventReader::resync` took {:?}", now.elapsed()));
let mut reads = 0;
const READ_LIMIT: usize = 16;
const READ_SIZE: usize = 128;
while evdev.is_readable()? && reads < READ_LIMIT {
let mut out = [InputEvent::zeroed(); READ_SIZE];
read_raw(&evdev.file, &mut out)?;
reads += 1;
}
if reads >= READ_LIMIT {
log::warn!("resync: kernel buffer not empty after {reads}x{READ_SIZE} reads");
}
self.resync_from(&DeviceState::current(evdev)?, queue);
Ok(())
}
fn update_state(&mut self, ev: InputEvent) {
match ev.kind() {
EventKind::Abs(ev) => {
if ev.abs().raw() < Abs::MT_SLOT.raw() {
self.abs[ev.abs().raw() as usize] = ev.value();
} else if ev.abs() == Abs::MT_SLOT {
self.mt_storage.active_slot = ev.value() as u32;
} else {
let slot = self.mt_storage.active_slot;
if let Some(group) = self.mt_storage.mut_group_for_code(ev.abs()) {
if let Some(slot) = group.get_mut(slot as usize) {
*slot = ev.value();
}
}
}
}
EventKind::Key(ev) => match ev.state() {
KeyState::PRESSED => {
self.keys.insert(ev.key());
}
KeyState::RELEASED => {
self.keys.remove(ev.key());
}
_ => {}
},
EventKind::Led(ev) => {
if ev.is_on() {
self.leds.insert(ev.led());
} else {
self.leds.remove(ev.led());
}
}
EventKind::Switch(ev) => {
if ev.is_pressed() {
self.switches.insert(ev.switch());
} else {
self.switches.remove(ev.switch());
}
}
EventKind::Sound(ev) => {
if ev.is_playing() {
self.sounds.insert(ev.sound());
} else {
self.sounds.remove(ev.sound());
}
}
_ => {}
}
}
}
#[derive(Debug)]
struct Impl {
state: DeviceState,
incoming: Arc<VecDeque<InputEvent>>,
skip: usize,
discard_events: bool,
}
impl Impl {
fn new(abs_axes: BitSet<Abs>) -> Self {
Self {
state: DeviceState::new(abs_axes),
incoming: Arc::default(),
skip: 0,
discard_events: false,
}
}
fn abs_state(&self, abs: Abs) -> i32 {
self.state.abs[abs.raw() as usize]
}
fn valid_slots(&self) -> ValidSlots<'_> {
self.state.mt_storage.valid_slots()
}
fn slot_state(&self, slot: impl TryInto<Slot>, code: Abs) -> Option<i32> {
assert!(
code.raw() > Abs::MT_SLOT.raw(),
"`slot_state` requires an `ABS_MT_*` value above `ABS_MT_SLOT`"
);
let slot: Slot = slot.try_into().ok()?;
self.state
.mt_storage
.group_for_code(code)?
.get(slot.raw() as usize)
.copied()
}
fn current_slot(&self) -> Slot {
Slot::from_raw(self.state.mt_storage.active_slot as i32)
}
fn skip(&mut self) {
if self.skip == 0 {
return;
}
Arc::make_mut(&mut self.incoming).drain(..self.skip);
self.skip = 0;
}
fn next_report(&mut self, iface: &mut impl Interface) -> io::Result<Report> {
let end: usize = match self
.incoming
.iter()
.skip(self.skip)
.position(report_or_dropped)
{
Some(i) => i,
None => self.refill(iface)?,
};
self.incoming
.range(self.skip..=self.skip + end)
.for_each(|ev| self.state.update_state(*ev));
let skip = self.skip;
self.skip += end + 1;
Ok(Report {
queue: self.incoming.clone(),
range: skip..=skip + end,
})
}
fn next_report_len(&mut self, iface: &mut impl Interface) -> io::Result<usize> {
self.skip();
let idx = match self.incoming.iter().position(report_or_dropped) {
Some(i) => Ok(i),
None => self.refill(iface),
};
idx.map(|i| i + 1)
}
fn next_event(&mut self) -> InputEvent {
self.skip();
let ev = Arc::make_mut(&mut self.incoming)
.pop_front()
.expect("`next_event` called with no events in queue");
self.state.update_state(ev);
ev
}
fn refill(&mut self, i: &mut impl Interface) -> io::Result<usize> {
const BATCH_READ_SIZE: usize = 21;
const PLACEHOLDER: InputEvent = InputEvent::new(EventType::from_raw(0xffff), 0xffff, -1);
self.skip();
let incoming = Arc::make_mut(&mut self.incoming);
loop {
let len_before = incoming.len();
incoming.reserve(BATCH_READ_SIZE);
incoming.extend(iter::repeat(PLACEHOLDER).take(BATCH_READ_SIZE));
let (first, second) = incoming.as_mut_slices();
let dest = if first.len() <= len_before {
&mut second[len_before - first.len()..]
} else {
&mut first[len_before..]
};
let res = i.read(dest);
let count = *res.as_ref().ok().unwrap_or(&0);
incoming.truncate(len_before + count);
debug_assert!(
!incoming.contains(&PLACEHOLDER),
"should not contain placeholders: {:?}",
incoming
);
res?;
let end = match incoming.range(len_before..).position(report_or_dropped) {
Some(i) => len_before + i,
None => continue, };
let ev = incoming[end];
let syn = match ev.kind() {
EventKind::Syn(ev) => ev,
_ => unreachable!("got invalid event at the end of a batch: {ev:?}"),
};
self.state.last_event = ev.time();
match syn.syn() {
Syn::REPORT => {
if self.discard_events {
self.discard_events = false;
drop(incoming.drain(..=end));
continue;
} else {
return Ok(end);
}
}
Syn::DROPPED => {
log::warn!("SYN_DROPPED: input events were lost! resyncing");
self.discard_events = true;
incoming.clear();
i.resync(&mut self.state, incoming)?;
if !incoming.is_empty() {
return Ok(incoming.len() - 1);
}
}
_ => unreachable!("unexpected SYN event at the end of a batch: {syn:?}"),
}
}
}
}
trait Interface {
fn read(&mut self, dest: &mut [InputEvent]) -> io::Result<usize>;
fn resync(&self, state: &mut DeviceState, queue: &mut VecDeque<InputEvent>) -> io::Result<()>;
}
impl Interface for Evdev {
fn read(&mut self, dest: &mut [InputEvent]) -> io::Result<usize> {
read_raw(&self.file, dest)
}
fn resync(&self, state: &mut DeviceState, queue: &mut VecDeque<InputEvent>) -> io::Result<()> {
let now = Instant::now();
let _d = on_drop(|| log::debug!("`EventReader::resync` took {:?}", now.elapsed()));
let mut reads = 0;
const READ_LIMIT: usize = 16;
const READ_SIZE: usize = 128;
while self.is_readable()? && reads < READ_LIMIT {
let mut out = [InputEvent::zeroed(); READ_SIZE];
read_raw(&self.file, &mut out)?;
reads += 1;
}
if reads >= READ_LIMIT {
log::warn!("resync: kernel buffer not empty after {reads}x{READ_SIZE} reads");
}
state.resync_from(&DeviceState::current(self)?, queue);
Ok(())
}
}
#[derive(Debug)]
pub struct EventReader {
evdev: Evdev,
imp: Impl,
}
impl AsFd for EventReader {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
self.evdev.as_fd()
}
}
impl AsRawFd for EventReader {
#[inline]
fn as_raw_fd(&self) -> RawFd {
self.evdev.as_raw_fd()
}
}
impl IntoRawFd for EventReader {
#[inline]
fn into_raw_fd(self) -> RawFd {
self.evdev.into_raw_fd()
}
}
impl EventReader {
pub(crate) fn new(evdev: Evdev) -> io::Result<Self> {
let abs_axes = evdev.supported_abs_axes()?;
let mut this = Self {
evdev,
imp: Impl::new(abs_axes),
};
this.imp
.state
.resync(&this.evdev, Arc::make_mut(&mut this.imp.incoming))?;
Ok(this)
}
#[inline]
pub fn into_evdev(self) -> Evdev {
self.evdev
}
#[inline]
pub fn evdev(&self) -> &Evdev {
&self.evdev
}
pub fn update(&mut self) -> io::Result<()> {
const MAX_REPORTS: usize = 512;
let now = Instant::now();
let was_nonblocking = self.evdev.set_nonblocking(true)?;
let mut count = 0;
let mut reports = self.reports();
let mut err = None;
for _ in 0..MAX_REPORTS {
match reports.next() {
None => break,
Some(Ok(_)) => count += 1,
Some(Err(e)) => {
err = Some(e);
break;
}
}
}
log::trace!(
"`EventReader::update` processed {count} reports in {:?}",
now.elapsed()
);
let res = if !was_nonblocking {
self.evdev.set_nonblocking(false).map(drop)
} else {
Ok(())
};
match err {
Some(e) => Err(e),
None => res,
}
}
#[inline]
pub fn key_state(&self) -> &BitSet<Key> {
&self.imp.state.keys
}
#[inline]
pub fn led_state(&self) -> &BitSet<Led> {
&self.imp.state.leds
}
#[inline]
pub fn sound_state(&self) -> &BitSet<Sound> {
&self.imp.state.sounds
}
#[inline]
pub fn switch_state(&self) -> &BitSet<Switch> {
&self.imp.state.switches
}
#[inline]
pub fn abs_state(&self, abs: Abs) -> i32 {
self.imp.abs_state(abs)
}
#[inline]
pub fn valid_slots(&self) -> ValidSlots<'_> {
self.imp.valid_slots()
}
#[inline]
pub fn slot_state(&self, slot: impl TryInto<Slot>, code: Abs) -> Option<i32> {
self.imp.slot_state(slot, code)
}
#[inline]
pub fn current_slot(&self) -> Slot {
self.imp.current_slot()
}
#[inline]
pub fn events(&mut self) -> Events<'_> {
Events {
reader: self,
remaining: 0,
}
}
#[inline]
pub fn reports(&mut self) -> Reports<'_> {
Reports(self)
}
#[cfg_attr(docsrs, doc(cfg(any(feature = "tokio", feature = "async-io"))))]
#[cfg(any(feature = "tokio", feature = "async-io"))]
pub fn async_events(&mut self) -> io::Result<AsyncEvents<'_>> {
AsyncEvents::new(self)
}
#[cfg_attr(docsrs, doc(cfg(any(feature = "tokio", feature = "async-io"))))]
#[cfg(any(feature = "tokio", feature = "async-io"))]
pub fn async_reports(&mut self) -> io::Result<AsyncReports<'_>> {
AsyncReports::new(self)
}
fn next_report(&mut self) -> io::Result<Report> {
self.imp.next_report(&mut self.evdev)
}
fn next_report_len(&mut self) -> io::Result<usize> {
self.imp.next_report_len(&mut self.evdev)
}
fn next_event(&mut self) -> InputEvent {
self.imp.next_event()
}
}
fn report_or_dropped(ev: &InputEvent) -> bool {
match ev.kind() {
EventKind::Syn(ev) => ev.syn() == Syn::REPORT || ev.syn() == Syn::DROPPED,
_ => false,
}
}
impl<'a> IntoIterator for &'a mut EventReader {
type Item = io::Result<InputEvent>;
type IntoIter = Events<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
self.events()
}
}
impl IntoIterator for EventReader {
type Item = io::Result<InputEvent>;
type IntoIter = IntoEvents;
#[inline]
fn into_iter(self) -> Self::IntoIter {
IntoEvents {
reader: self,
remaining: 0,
}
}
}
#[derive(Debug)]
pub struct Events<'a> {
reader: &'a mut EventReader,
remaining: usize,
}
impl Iterator for Events<'_> {
type Item = io::Result<InputEvent>;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
self.remaining = match self.reader.next_report_len() {
Ok(n) => n,
Err(e) if e.kind() == io::ErrorKind::WouldBlock => return None,
Err(e) => return Some(Err(e)),
};
}
self.remaining -= 1;
Some(Ok(self.reader.next_event()))
}
}
#[derive(Debug)]
pub struct IntoEvents {
reader: EventReader,
remaining: usize,
}
impl IntoEvents {
#[inline]
pub fn into_reader(self) -> EventReader {
self.reader
}
}
impl Iterator for IntoEvents {
type Item = io::Result<InputEvent>;
fn next(&mut self) -> Option<Self::Item> {
if self.remaining == 0 {
self.remaining = match self.reader.next_report_len() {
Ok(n) => n,
Err(e) if e.kind() == io::ErrorKind::WouldBlock => return None,
Err(e) => return Some(Err(e)),
};
}
self.remaining -= 1;
Some(Ok(self.reader.next_event()))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
(self.remaining, None)
}
}
#[derive(Debug)]
pub struct Reports<'a>(&'a mut EventReader);
impl<'a> Iterator for Reports<'a> {
type Item = io::Result<Report>;
fn next(&mut self) -> Option<Self::Item> {
match self.0.next_report() {
Ok(report) => Some(Ok(report)),
Err(e) if e.kind() == io::ErrorKind::WouldBlock => None,
Err(e) => Some(Err(e)),
}
}
}
#[derive(Debug)]
pub struct Report {
queue: Arc<VecDeque<InputEvent>>,
range: RangeInclusive<usize>,
}
impl Report {
#[inline]
pub fn iter(&self) -> ReportIter<'_> {
self.into_iter()
}
#[inline]
pub fn len(&self) -> usize {
*self.range.end() - *self.range.start() + 1
}
}
impl<'a> IntoIterator for &'a Report {
type Item = InputEvent;
type IntoIter = ReportIter<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
ReportIter {
queue: &self.queue,
range: self.range.clone(),
}
}
}
impl IntoIterator for Report {
type Item = InputEvent;
type IntoIter = ReportIntoIter;
#[inline]
fn into_iter(self) -> Self::IntoIter {
ReportIntoIter {
queue: self.queue,
range: self.range.clone(),
}
}
}
#[derive(Debug)]
pub struct ReportIntoIter {
queue: Arc<VecDeque<InputEvent>>,
range: RangeInclusive<usize>,
}
impl Iterator for ReportIntoIter {
type Item = InputEvent;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let Some(i) = self.range.next() else {
return None;
};
Some(self.queue[i])
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.range.size_hint()
}
}
impl ExactSizeIterator for ReportIntoIter {}
impl FusedIterator for ReportIntoIter {}
#[derive(Debug)]
pub struct ReportIter<'a> {
queue: &'a VecDeque<InputEvent>,
range: RangeInclusive<usize>,
}
impl<'a> Iterator for ReportIter<'a> {
type Item = InputEvent;
#[inline]
fn next(&mut self) -> Option<Self::Item> {
let Some(i) = self.range.next() else {
return None;
};
Some(self.queue[i])
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.range.size_hint()
}
}
impl ExactSizeIterator for ReportIter<'_> {}
impl FusedIterator for ReportIter<'_> {}