hidra 0.0.1

Pure Rust HID library.
Documentation

hidra

A pure-Rust HID library with a unified async API (with blocking .wait() on native targets, like nusb), a WebHID backend for WebAssembly, and standalone HID report-descriptor primitives.

No C library is linked. One Hidra / HidDevice regardless of backend:

Platform Backend Notes
Linux hidraw device nodes, sysfs enumeration no libudev dependency
Windows hid.dll + SetupAPI (via windows-sys declarations)
macOS IOHIDManager (direct framework FFI)
any platform nusb supports raw USB transfers via nusb optional nusb feature, swaps in a pure-Rust USB transport
Browsers WebHID via web-sys same Hidra/HidDevice, await-only

Quick start

Every I/O method returns a future. On native, bring MaybeFuture into scope and call .wait() to run it blocking:

use hidra::MaybeFuture;

let api = hidra::Hidra::new()?;
for dev in api.device_list() {
    println!("{:04x}:{:04x} {}", dev.vendor_id(), dev.product_id(),
             dev.product_string().unwrap_or("<unnamed>"));
}

let device = api.open(0x046d, 0xc216).wait()?;
device.write(&[0x00, 0x01, 0x02]).wait()?;        // report ID 0 + payload
let mut buf = [0u8; 64];
let len = device.read(&mut buf).wait()?;          // one input report

See examples/ for runnable versions (cargo run --example enumerate).

Async and blocking

Following nusb's design, every Hidra / HidDevice method returns an impl Future. Drive it either way:

  • .await it in any async runtime (the futures are runtime-agnostic: plain Waker wake-ups, no tokio/async-std dependency).
  • .wait() it to block the current thread (a tiny built-in executor). This is the MaybeFuture extension trait, available on native targets only; wasm32 cannot block, so there you must .await.
let len = device.read(&mut buf).await?;          // async
let len = device.read(&mut buf).wait()?;         // blocking (native)

Input reads genuinely wait on the OS (a poll(2) reactor on Linux, overlapped-event waits on Windows, the IOHIDManager callback queue on macOS, nusb's own I/O with the nusb feature, inputreport events on WebHID). read resolves with exactly one input report (never empty); for a timeout use your runtime's combinator (e.g. tokio::time::timeout). On unplug it fails with HidError::Disconnected, and the read future is cancel-safe: dropping it never loses a report. Writes and feature reports complete promptly; their futures simply run the synchronous OS call when polled.