diff --git a/fish-rust/src/fd_monitor.rs b/fish-rust/src/fd_monitor.rs index 3a94f1409..032e26afa 100644 --- a/fish-rust/src/fd_monitor.rs +++ b/fish-rust/src/fd_monitor.rs @@ -3,7 +3,8 @@ use std::sync::atomic::{AtomicU64, Ordering}; use std::sync::{Arc, Mutex}; use std::time::{Duration, Instant}; -use self::fd_monitor_ffi::{new_fd_event_signaller, FdEventSignaller, ItemWakeReason}; +pub use self::fd_monitor_ffi::ItemWakeReason; +use self::fd_monitor_ffi::{new_fd_event_signaller, FdEventSignaller}; use crate::fd_readable_set::FdReadableSet; use crate::fds::AutoCloseFd; use crate::ffi::void_ptr; @@ -93,7 +94,20 @@ unsafe impl Send for FdEventSignaller {} #[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)] pub struct FdMonitorItemId(u64); +impl From for u64 { + fn from(value: FdMonitorItemId) -> Self { + value.0 + } +} + +impl From for FdMonitorItemId { + fn from(value: u64) -> Self { + FdMonitorItemId(value) + } +} + type FfiCallback = extern "C" fn(*mut AutoCloseFd, u8, void_ptr); +type NativeCallback = Box; /// The callback type used by [`FdMonitorItem`]. It is passed a mutable reference to the /// `FdMonitorItem`'s [`FdMonitorItem::fd`] and [the reason](ItemWakeupReason) for the wakeup. The @@ -107,7 +121,7 @@ type FfiCallback = extern "C" fn(*mut AutoCloseFd, u8, void_ptr); enum FdMonitorCallback { None, #[allow(clippy::type_complexity)] - Native(Box), + Native(NativeCallback), Ffi(FfiCallback /* fn ptr */, void_ptr /* param */), } @@ -139,6 +153,11 @@ enum ItemAction { } impl FdMonitorItem { + /// Returns the id for this `FdMonitorItem` that is registered with the [`FdMonitor`]. + pub fn id(&self) -> FdMonitorItemId { + self.item_id + } + /// Return the duration until the timeout should trigger or `None`. A return of `0` means we are /// at or past the timeout. fn remaining_time(&self, now: &Instant) -> Option { @@ -208,16 +227,27 @@ impl FdMonitorItem { } } - fn new() -> Self { - Self { - callback: FdMonitorCallback::None, - fd: AutoCloseFd::empty(), - timeout: None, - last_time: None, + pub fn new( + fd: AutoCloseFd, + timeout: Option, + callback: Option, + ) -> Self { + FdMonitorItem { + fd, + timeout, + callback: match callback { + Some(callback) => FdMonitorCallback::Native(callback), + None => FdMonitorCallback::None, + }, item_id: FdMonitorItemId(0), + last_time: None, } } + pub fn set_callback(&mut self, callback: NativeCallback) { + self.callback = FdMonitorCallback::Native(callback); + } + fn set_callback_ffi(&mut self, callback: *const u8, param: *const u8) { // Safety: we are just marshalling our function pointers with identical definitions on both // sides of the ffi bridge as void pointers to keep cxx bridge happy. Whether we invoke the @@ -228,6 +258,18 @@ impl FdMonitorItem { } } +impl Default for FdMonitorItem { + fn default() -> Self { + Self { + callback: FdMonitorCallback::None, + fd: AutoCloseFd::empty(), + timeout: None, + last_time: None, + item_id: FdMonitorItemId(0), + } + } +} + // cxx bridge does not support "static member functions" in C++ or rust, so we need a top-level fn. fn new_fd_monitor_ffi() -> Box { Box::new(FdMonitor::new()) @@ -245,7 +287,7 @@ fn new_fd_monitor_item_ffi( // raw function as a void pointer or as a typed fn that helps us keep track of what we're // doing is unsafe in all cases, so might as well make the best of it. let callback = unsafe { std::mem::transmute(callback) }; - let mut item = FdMonitorItem::new(); + let mut item = FdMonitorItem::default(); item.fd.reset(fd); item.callback = FdMonitorCallback::Ffi(callback, param.into()); if timeout_usecs != FdReadableSet::kNoTimeout { @@ -360,7 +402,7 @@ impl FdMonitor { // raw function as a void pointer or as a typed fn that helps us keep track of what we're // doing is unsafe in all cases, so might as well make the best of it. let callback = unsafe { std::mem::transmute(callback) }; - let mut item = FdMonitorItem::new(); + let mut item = FdMonitorItem::default(); item.fd.reset(fd); item.callback = FdMonitorCallback::Ffi(callback, param.into()); if timeout_usecs != FdReadableSet::kNoTimeout {