From 5e866af4e462f182dc1db9b88c92c08eb9c584a9 Mon Sep 17 00:00:00 2001 From: Kevin Mehall Date: Sat, 22 Feb 2025 14:46:41 -0700 Subject: [PATCH] Add MaybeFuture::map --- src/device.rs | 14 ++-- src/maybe_future.rs | 61 ++++++++++++++++- src/platform/linux_usbfs/device.rs | 22 +++--- src/platform/macos_iokit/device.rs | 14 ++-- src/platform/windows_winusb/device.rs | 98 ++++++++++++--------------- 5 files changed, 134 insertions(+), 75 deletions(-) diff --git a/src/device.rs b/src/device.rs index 36fdcd6..9eff6ad 100644 --- a/src/device.rs +++ b/src/device.rs @@ -46,13 +46,13 @@ impl Device { pub(crate) fn open( d: &DeviceInfo, ) -> impl MaybeFuture> { - platform::Device::from_device_info(d) + platform::Device::from_device_info(d).map(|d| d.map(Device::wrap)) } /// Wraps a device that is already open. #[cfg(any(target_os = "android", target_os = "linux"))] pub fn from_fd(fd: std::os::fd::OwnedFd) -> impl MaybeFuture> { - platform::Device::from_fd(fd) + platform::Device::from_fd(fd).map(|d| d.map(Device::wrap)) } /// Open an interface of the device and claim it for exclusive use. @@ -60,7 +60,10 @@ impl Device { &self, interface: u8, ) -> impl MaybeFuture> { - self.backend.clone().claim_interface(interface) + self.backend + .clone() + .claim_interface(interface) + .map(|i| i.map(Interface::wrap)) } /// Detach kernel drivers and open an interface of the device and claim it for exclusive use. @@ -72,7 +75,10 @@ impl Device { &self, interface: u8, ) -> impl MaybeFuture> { - self.backend.clone().detach_and_claim_interface(interface) + self.backend + .clone() + .detach_and_claim_interface(interface) + .map(|i| i.map(Interface::wrap)) } /// Detach kernel drivers for the specified interface. diff --git a/src/maybe_future.rs b/src/maybe_future.rs index 75d645e..236bd7a 100644 --- a/src/maybe_future.rs +++ b/src/maybe_future.rs @@ -1,4 +1,8 @@ -use std::future::IntoFuture; +use std::{ + future::{Future, IntoFuture}, + pin::Pin, + task::{Context, Poll}, +}; /// IO that may be performed synchronously or asynchronously. /// @@ -8,6 +12,17 @@ pub trait MaybeFuture: IntoFuture { /// Block waiting for the action to complete #[cfg(not(target_arch = "wasm32"))] fn wait(self) -> Self::Output; + + /// Apply a function to the output. + fn map R + Unpin, R>(self, f: T) -> Map + where + Self: Sized, + { + Map { + wrapped: self, + func: f, + } + } } #[cfg(any( @@ -73,3 +88,47 @@ impl MaybeFuture for Ready { self.0 } } + +pub struct Map { + wrapped: F, + func: T, +} + +impl R, R> IntoFuture for Map { + type Output = R; + type IntoFuture = MapFut; + + fn into_future(self) -> Self::IntoFuture { + MapFut { + wrapped: self.wrapped.into_future(), + func: Some(self.func), + } + } +} + +impl R, R> MaybeFuture for Map { + fn wait(self) -> Self::Output { + (self.func)(self.wrapped.wait()) + } +} + +pub struct MapFut { + wrapped: F, + func: Option, +} + +impl R, R> Future for MapFut { + type Output = R; + + fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // SAFETY: structural pin projection: `self.wrapped` is always pinned. + let wrapped = unsafe { self.as_mut().map_unchecked_mut(|s| &mut s.wrapped) }; + + Future::poll(wrapped, cx).map(|output| { + // SAFETY: `self.func` is never pinned. + let func = unsafe { &mut self.as_mut().get_unchecked_mut().func }; + + (func.take().expect("polled after completion"))(output) + }) + } +} diff --git a/src/platform/linux_usbfs/device.rs b/src/platform/linux_usbfs/device.rs index 3a0585e..e55d2fc 100644 --- a/src/platform/linux_usbfs/device.rs +++ b/src/platform/linux_usbfs/device.rs @@ -54,7 +54,7 @@ pub(crate) struct LinuxDevice { impl LinuxDevice { pub(crate) fn from_device_info( d: &DeviceInfo, - ) -> impl MaybeFuture> { + ) -> impl MaybeFuture, Error>> { let busnum = d.busnum(); let devnum = d.device_address(); let sysfs_path = d.path.clone(); @@ -68,7 +68,9 @@ impl LinuxDevice { }) } - pub(crate) fn from_fd(fd: OwnedFd) -> impl MaybeFuture> { + pub(crate) fn from_fd( + fd: OwnedFd, + ) -> impl MaybeFuture, Error>> { Blocking::new(move || { debug!("Wrapping fd {} as usbfs device", fd.as_raw_fd()); Self::create_inner(fd, None, None) @@ -79,7 +81,7 @@ impl LinuxDevice { fd: OwnedFd, sysfs: Option, active_config: Option, - ) -> Result { + ) -> Result, Error> { let descriptors = { let mut file = unsafe { ManuallyDrop::new(File::from_raw_fd(fd.as_raw_fd())) }; // NOTE: Seek required on android @@ -125,7 +127,7 @@ impl LinuxDevice { epoll::EventFlags::OUT, )?; - Ok(crate::Device::wrap(arc)) + Ok(arc) } pub(crate) fn handle_usb_epoll(id: usize) { @@ -284,7 +286,7 @@ impl LinuxDevice { pub(crate) fn claim_interface( self: Arc, interface_number: u8, - ) -> impl MaybeFuture> { + ) -> impl MaybeFuture, Error>> { Blocking::new(move || { usbfs::claim_interface(&self.fd, interface_number).inspect_err(|e| { warn!( @@ -296,31 +298,31 @@ impl LinuxDevice { "Claimed interface {interface_number} on device id {dev}", dev = self.events_id ); - Ok(crate::Interface::wrap(Arc::new(LinuxInterface { + Ok(Arc::new(LinuxInterface { device: self, interface_number, reattach: false, state: Mutex::new(Default::default()), - }))) + })) }) } pub(crate) fn detach_and_claim_interface( self: Arc, interface_number: u8, - ) -> impl MaybeFuture> { + ) -> impl MaybeFuture, Error>> { Blocking::new(move || { usbfs::detach_and_claim_interface(&self.fd, interface_number)?; debug!( "Detached and claimed interface {interface_number} on device id {dev}", dev = self.events_id ); - Ok(crate::Interface::wrap(Arc::new(LinuxInterface { + Ok(Arc::new(LinuxInterface { device: self, interface_number, reattach: true, state: Mutex::new(Default::default()), - }))) + })) }) } diff --git a/src/platform/macos_iokit/device.rs b/src/platform/macos_iokit/device.rs index 67df1f4..0591bf4 100644 --- a/src/platform/macos_iokit/device.rs +++ b/src/platform/macos_iokit/device.rs @@ -53,7 +53,7 @@ fn guess_active_config(dev: &IoKitDevice) -> Option { impl MacDevice { pub(crate) fn from_device_info( d: &DeviceInfo, - ) -> impl MaybeFuture> { + ) -> impl MaybeFuture, Error>> { let registry_id = d.registry_id; let speed = d.speed; Blocking::new(move || { @@ -88,7 +88,7 @@ impl MacDevice { res.unwrap_or(0) }; - Ok(crate::Device::wrap(Arc::new(MacDevice { + Ok(Arc::new(MacDevice { _event_registration, device, device_descriptor, @@ -96,7 +96,7 @@ impl MacDevice { active_config: AtomicU8::new(active_config), is_open_exclusive: Mutex::new(opened), claimed_interfaces: AtomicUsize::new(0), - }))) + })) }) } @@ -236,7 +236,7 @@ impl MacDevice { pub(crate) fn claim_interface( self: Arc, interface_number: u8, - ) -> impl MaybeFuture> { + ) -> impl MaybeFuture, Error>> { Blocking::new(move || { let intf_service = self .device @@ -254,21 +254,21 @@ impl MacDevice { self.claimed_interfaces.fetch_add(1, Ordering::Acquire); - Ok(crate::Interface::wrap(Arc::new(MacInterface { + Ok(Arc::new(MacInterface { device: self.clone(), interface_number, interface, endpoints: Mutex::new(endpoints), state: Mutex::new(InterfaceState::default()), _event_registration, - }))) + })) }) } pub(crate) fn detach_and_claim_interface( self: Arc, interface: u8, - ) -> impl MaybeFuture> { + ) -> impl MaybeFuture, Error>> { self.claim_interface(interface) } } diff --git a/src/platform/windows_winusb/device.rs b/src/platform/windows_winusb/device.rs index a3c7c1a..15e466e 100644 --- a/src/platform/windows_winusb/device.rs +++ b/src/platform/windows_winusb/device.rs @@ -53,7 +53,7 @@ pub(crate) struct WindowsDevice { impl WindowsDevice { pub(crate) fn from_device_info( d: &DeviceInfo, - ) -> impl MaybeFuture> { + ) -> impl MaybeFuture, Error>> { let instance_id = d.instance_id.clone(); let devinst = d.devinst; Blocking::new(move || { @@ -85,14 +85,14 @@ impl WindowsDevice { }) .collect(); - Ok(crate::Device::wrap(Arc::new(WindowsDevice { + Ok(Arc::new(WindowsDevice { device_descriptor, config_descriptors, speed: connection_info.speed, active_config: connection_info.active_config, devinst: devinst, handles: Mutex::new(BTreeMap::new()), - }))) + })) }) } @@ -145,63 +145,55 @@ impl WindowsDevice { pub(crate) fn claim_interface( self: Arc, interface_number: u8, - ) -> impl MaybeFuture> { + ) -> impl MaybeFuture, Error>> { Blocking::new(move || { - self.claim_interface_blocking(interface_number) - .map(crate::Interface::wrap) + let driver = get_driver_name(self.devinst); + + let mut handles = self.handles.lock().unwrap(); + + if driver.eq_ignore_ascii_case("winusb") { + match handles.entry(0) { + Entry::Occupied(mut e) => e.get_mut().claim_interface(&self, interface_number), + Entry::Vacant(e) => { + let path = get_winusb_device_path(self.devinst)?; + let mut handle = WinusbFileHandle::new(&path, 0)?; + let intf = handle.claim_interface(&self, interface_number)?; + e.insert(handle); + Ok(intf) + } + } + } else if driver.eq_ignore_ascii_case("usbccgp") { + let (first_interface, child_dev) = + find_usbccgp_child(self.devinst, interface_number) + .ok_or_else(|| Error::new(ErrorKind::NotFound, "Interface not found"))?; + + if first_interface != interface_number { + debug!("Guessing that interface {interface_number} is an associated interface of {first_interface}"); + } + + match handles.entry(first_interface) { + Entry::Occupied(mut e) => e.get_mut().claim_interface(&self, interface_number), + Entry::Vacant(e) => { + let path = get_usbccgp_winusb_device_path(child_dev)?; + let mut handle = WinusbFileHandle::new(&path, first_interface)?; + let intf = handle.claim_interface(&self, interface_number)?; + e.insert(handle); + Ok(intf) + } + } + } else { + Err(Error::new( + ErrorKind::Unsupported, + format!("Device driver is {driver:?}, not WinUSB or USBCCGP"), + )) + } }) } - fn claim_interface_blocking( - self: &Arc, - interface_number: u8, - ) -> Result, Error> { - let driver = get_driver_name(self.devinst); - - let mut handles = self.handles.lock().unwrap(); - - if driver.eq_ignore_ascii_case("winusb") { - match handles.entry(0) { - Entry::Occupied(mut e) => e.get_mut().claim_interface(self, interface_number), - Entry::Vacant(e) => { - let path = get_winusb_device_path(self.devinst)?; - let mut handle = WinusbFileHandle::new(&path, 0)?; - let intf = handle.claim_interface(self, interface_number)?; - e.insert(handle); - Ok(intf) - } - } - } else if driver.eq_ignore_ascii_case("usbccgp") { - let (first_interface, child_dev) = - find_usbccgp_child(self.devinst, interface_number) - .ok_or_else(|| Error::new(ErrorKind::NotFound, "Interface not found"))?; - - if first_interface != interface_number { - debug!("Guessing that interface {interface_number} is an associated interface of {first_interface}"); - } - - match handles.entry(first_interface) { - Entry::Occupied(mut e) => e.get_mut().claim_interface(self, interface_number), - Entry::Vacant(e) => { - let path = get_usbccgp_winusb_device_path(child_dev)?; - let mut handle = WinusbFileHandle::new(&path, first_interface)?; - let intf = handle.claim_interface(self, interface_number)?; - e.insert(handle); - Ok(intf) - } - } - } else { - Err(Error::new( - ErrorKind::Unsupported, - format!("Device driver is {driver:?}, not WinUSB or USBCCGP"), - )) - } - } - pub(crate) fn detach_and_claim_interface( self: Arc, interface: u8, - ) -> impl MaybeFuture> { + ) -> impl MaybeFuture, Error>> { self.claim_interface(interface) } }