Add MaybeFuture::map

This commit is contained in:
Kevin Mehall 2025-02-22 14:46:41 -07:00
parent 8dfb3e5f1d
commit 5e866af4e4
5 changed files with 134 additions and 75 deletions

View file

@ -46,13 +46,13 @@ impl Device {
pub(crate) fn open(
d: &DeviceInfo,
) -> impl MaybeFuture<Output = Result<Device, std::io::Error>> {
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<Output = Result<Device, Error>> {
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<Output = Result<Interface, Error>> {
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<Output = Result<Interface, Error>> {
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.

View file

@ -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<T: FnOnce(Self::Output) -> R + Unpin, R>(self, f: T) -> Map<Self, T>
where
Self: Sized,
{
Map {
wrapped: self,
func: f,
}
}
}
#[cfg(any(
@ -73,3 +88,47 @@ impl<T> MaybeFuture for Ready<T> {
self.0
}
}
pub struct Map<F, T> {
wrapped: F,
func: T,
}
impl<F: MaybeFuture, T: FnOnce(F::Output) -> R, R> IntoFuture for Map<F, T> {
type Output = R;
type IntoFuture = MapFut<F::IntoFuture, T>;
fn into_future(self) -> Self::IntoFuture {
MapFut {
wrapped: self.wrapped.into_future(),
func: Some(self.func),
}
}
}
impl<F: MaybeFuture, T: FnOnce(F::Output) -> R, R> MaybeFuture for Map<F, T> {
fn wait(self) -> Self::Output {
(self.func)(self.wrapped.wait())
}
}
pub struct MapFut<F, T> {
wrapped: F,
func: Option<T>,
}
impl<F: Future, T: FnOnce(F::Output) -> R, R> Future for MapFut<F, T> {
type Output = R;
fn poll(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
// 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)
})
}
}

View file

@ -54,7 +54,7 @@ pub(crate) struct LinuxDevice {
impl LinuxDevice {
pub(crate) fn from_device_info(
d: &DeviceInfo,
) -> impl MaybeFuture<Output = Result<crate::Device, Error>> {
) -> impl MaybeFuture<Output = Result<Arc<LinuxDevice>, 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<Output = Result<crate::Device, Error>> {
pub(crate) fn from_fd(
fd: OwnedFd,
) -> impl MaybeFuture<Output = Result<Arc<LinuxDevice>, 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<SysfsPath>,
active_config: Option<u8>,
) -> Result<crate::Device, Error> {
) -> Result<Arc<LinuxDevice>, 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<Self>,
interface_number: u8,
) -> impl MaybeFuture<Output = Result<crate::Interface, Error>> {
) -> impl MaybeFuture<Output = Result<Arc<LinuxInterface>, 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<Self>,
interface_number: u8,
) -> impl MaybeFuture<Output = Result<crate::Interface, Error>> {
) -> impl MaybeFuture<Output = Result<Arc<LinuxInterface>, 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()),
})))
}))
})
}

View file

@ -53,7 +53,7 @@ fn guess_active_config(dev: &IoKitDevice) -> Option<u8> {
impl MacDevice {
pub(crate) fn from_device_info(
d: &DeviceInfo,
) -> impl MaybeFuture<Output = Result<crate::Device, Error>> {
) -> impl MaybeFuture<Output = Result<Arc<MacDevice>, 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<Self>,
interface_number: u8,
) -> impl MaybeFuture<Output = Result<crate::Interface, Error>> {
) -> impl MaybeFuture<Output = Result<Arc<MacInterface>, 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<Self>,
interface: u8,
) -> impl MaybeFuture<Output = Result<crate::Interface, Error>> {
) -> impl MaybeFuture<Output = Result<Arc<MacInterface>, Error>> {
self.claim_interface(interface)
}
}

View file

@ -53,7 +53,7 @@ pub(crate) struct WindowsDevice {
impl WindowsDevice {
pub(crate) fn from_device_info(
d: &DeviceInfo,
) -> impl MaybeFuture<Output = Result<crate::Device, Error>> {
) -> impl MaybeFuture<Output = Result<Arc<WindowsDevice>, 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<Self>,
interface_number: u8,
) -> impl MaybeFuture<Output = Result<crate::Interface, Error>> {
) -> impl MaybeFuture<Output = Result<Arc<WindowsInterface>, 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<Self>,
interface_number: u8,
) -> Result<Arc<WindowsInterface>, 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<Self>,
interface: u8,
) -> impl MaybeFuture<Output = Result<crate::Interface, Error>> {
) -> impl MaybeFuture<Output = Result<Arc<WindowsInterface>, Error>> {
self.claim_interface(interface)
}
}