async-hid 0.3.0

A async library for interacting with HID devices
Documentation
use core_foundation::base::TCFType;
use core_foundation::dictionary::CFMutableDictionaryRef;
use io_kit_sys::hid::device::IOHIDDeviceGetService;
use io_kit_sys::ret::kIOReturnSuccess;
use io_kit_sys::types::io_service_t;
use io_kit_sys::{
    kIOMasterPortDefault, IOObjectRelease, IOObjectRetain, IORegistryEntryGetRegistryEntryID, IORegistryEntryIDMatching, IOServiceGetMatchingService
};
use mach2::port::MACH_PORT_NULL;

use crate::backend::iohidmanager::device::IOHIDDevice;
use crate::{ensure, HidError, HidResult};

#[derive(Debug)]
#[repr(transparent)]
pub struct IOService(io_service_t);

impl TryFrom<&IOHIDDevice> for IOService {
    type Error = HidError;

    fn try_from(value: &IOHIDDevice) -> Result<Self, Self::Error> {
        let service = unsafe { IOHIDDeviceGetService(value.as_concrete_TypeRef()) };
        ensure!(service != MACH_PORT_NULL, HidError::message("Invalid IOService"));
        Ok(IOService(service))
    }
}

impl TryFrom<RegistryEntryId> for IOService {
    type Error = HidError;

    fn try_from(value: RegistryEntryId) -> Result<Self, Self::Error> {
        let service = unsafe { IOServiceGetMatchingService(kIOMasterPortDefault, value.matching()) };
        ensure!(service != MACH_PORT_NULL, HidError::message("Invalid IOService"));
        Ok(IOService(service))
    }
}

impl IOService {
    pub fn raw(&self) -> io_service_t {
        self.0
    }

    pub fn duplicate(&self) -> HidResult<Self> {
        let result = unsafe { IOObjectRetain(self.0) };
        ensure!(result == kIOReturnSuccess, HidError::message("Failed to duplicate IOService"));
        Ok(IOService(self.0))
    }

    pub fn get_registry_entry_id(&self) -> HidResult<RegistryEntryId> {
        let copy = self.duplicate()?;
        let mut entry_id = 0;
        let result = unsafe { IORegistryEntryGetRegistryEntryID(copy.0, &mut entry_id) };
        ensure!(result == kIOReturnSuccess, HidError::message("Failed to retrieve entry id"));
        Ok(RegistryEntryId(entry_id))
    }
}

impl Drop for IOService {
    fn drop(&mut self) {
        unsafe { IOObjectRelease(self.0 as _) };
    }
}

#[derive(Debug, Copy, Clone, Eq, PartialEq, Hash)]
#[repr(transparent)]
pub struct RegistryEntryId(pub u64);

impl RegistryEntryId {
    fn matching(self) -> CFMutableDictionaryRef {
        unsafe { IORegistryEntryIDMatching(self.0) }
    }
}