#[cfg(target_os = "linux")]
mod linux;
#[cfg(target_os = "linux")]
use linux::Impl;
#[cfg(target_os = "freebsd")]
mod freebsd;
#[cfg(target_os = "freebsd")]
use freebsd::Impl;
mod fallback;
#[cfg(not(any(target_os = "linux", target_os = "freebsd")))]
use fallback::Impl;
use std::{
fmt, io,
os::{
fd::{AsFd, AsRawFd, IntoRawFd, RawFd},
unix::prelude::BorrowedFd,
},
path::{Path, PathBuf},
};
use crate::{Evdev, util::set_nonblocking};
trait HotplugImpl: Sized + AsRawFd + IntoRawFd {
fn open() -> io::Result<Self>;
fn read(&self) -> io::Result<HotplugEvent>;
}
pub struct HotplugMonitor {
imp: Impl,
}
impl fmt::Debug for HotplugMonitor {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_struct("HotplugMonitor")
.field("fd", &self.as_raw_fd())
.finish()
}
}
impl AsRawFd for HotplugMonitor {
#[inline]
fn as_raw_fd(&self) -> RawFd {
self.imp.as_raw_fd()
}
}
impl IntoRawFd for HotplugMonitor {
#[inline]
fn into_raw_fd(self) -> RawFd {
self.imp.into_raw_fd()
}
}
impl AsFd for HotplugMonitor {
#[inline]
fn as_fd(&self) -> BorrowedFd<'_> {
unsafe { BorrowedFd::borrow_raw(self.as_raw_fd()) }
}
}
impl HotplugMonitor {
pub fn new() -> io::Result<Self> {
Ok(Self { imp: Impl::open()? })
}
pub fn set_nonblocking(&self, nonblocking: bool) -> io::Result<bool> {
set_nonblocking(self.as_raw_fd(), nonblocking)
}
#[inline]
pub fn iter(&self) -> Iter<'_> {
Iter(self)
}
}
impl IntoIterator for HotplugMonitor {
type Item = io::Result<HotplugEvent>;
type IntoIter = IntoIter;
#[inline]
fn into_iter(self) -> Self::IntoIter {
IntoIter(self)
}
}
impl<'a> IntoIterator for &'a HotplugMonitor {
type Item = io::Result<HotplugEvent>;
type IntoIter = Iter<'a>;
#[inline]
fn into_iter(self) -> Self::IntoIter {
Iter(self)
}
}
#[derive(Debug)]
pub struct IntoIter(HotplugMonitor);
impl Iterator for IntoIter {
type Item = io::Result<HotplugEvent>;
fn next(&mut self) -> Option<Self::Item> {
match self.0.imp.read() {
Ok(ev) => Some(Ok(ev)),
Err(e) if e.kind() == io::ErrorKind::WouldBlock => None,
Err(e) => Some(Err(e)),
}
}
}
#[derive(Debug)]
pub struct Iter<'a>(&'a HotplugMonitor);
impl<'a> Iterator for Iter<'a> {
type Item = io::Result<HotplugEvent>;
fn next(&mut self) -> Option<Self::Item> {
match self.0.imp.read() {
Ok(ev) => Some(Ok(ev)),
Err(e) if e.kind() == io::ErrorKind::WouldBlock => None,
Err(e) => Some(Err(e)),
}
}
}
#[derive(Debug, Clone)]
pub struct HotplugEvent {
path: PathBuf,
}
impl HotplugEvent {
#[inline]
pub fn path(&self) -> &Path {
&self.path
}
#[inline]
pub fn into_path(self) -> PathBuf {
self.path
}
pub fn open(&self) -> io::Result<Evdev> {
Evdev::open(&self.path)
}
}