dcuddeback / libusb-rs

A safe Rust wrapper for libusb.
MIT License
199 stars 64 forks source link

async API? #4

Open goertzenator opened 8 years ago

goertzenator commented 8 years ago

It appears libusb-rs does not support the libusb async API. Any plans or thoughts on this?

I've used the async API from C++ before and am considering doing it from Rust.

kevinmehall commented 8 years ago

I started implementing safe Rust bindings to the libusb async transfer functions a while ago, but haven't gotten around to finishing it yet. I'll try to clean it up later this week.

goertzenator commented 8 years ago

Thanks, I'll give that a look when you push it.

dcuddeback commented 8 years ago

@goertzenator Yeah, definitely. Sounds like @kevinmehall might be ahead of me on that. I'd love to see what he comes up with.

kevinmehall commented 8 years ago

Work in progress here: https://github.com/kevinmehall/libusb-rs/blob/async/src/async.rs

Example streaming from a device

The new concept (vs libusb) is the AsyncGroup (could use a better name), which takes ownership of transfers when they are submitted, manages completions, and returns the completed transfers back to you to be handled and/or resubmitted. Libusb does that with callbacks, but this wraps that error-prone API in a safe Rust interface. It's not quite zero-cost, because it keeps track of pending transfers in a HashSet and completed transfers in a VecDeque, but should have minimal overhead.

I still need to rework the buffer management. Right now a transfer takes &'d mut [u8]. That lifetime must outlive the AsyncGroup to guarantee that it stays valid while the transfer is pending, In reality, it only needs to live until the transfer completes, but references can't express that. It requires a mutable buffer because the same type is shared for both IN and OUT directions. I'm thinking the Transfer should own the buffer -- that solves the mutability question, and if it let you give ownership to the AsyncGroup on submit, and take it back on completion, you can stream owned buffers into or out of a USB endpoint.

Other TODOs (some could happen later);

goertzenator commented 8 years ago

Thanks Kevin. I'm actually interested in using my own event loop (mio), and this wrapper doesn't seem to support that... and I'm not certain it should since libusb doesn't provide it in a portable manner (no Windows support).

My inclination for my project at hand is to just code straight to Linux usbfs. Using the libusb usbfs layer as a guide, this seems very doable.

kevinmehall commented 8 years ago

I think it would be possible to make the AsyncGroup a mio Evented under the proposed new mio API such that you could add the AsyncGroup to your event loop and get notified when a completion is ready. Windows could use an event listener thread, or maybe someday libusb will expose the underlying IOCP handles on Windows.

oberien commented 8 years ago

@kevinmehall What's the status here? I would really love to see this, especially because currently I need to read_interrupt on 2 interfaces while i read_control from a 3rd one. With threads this is pretty messy. But with your given "Example streaming from a device" it seems easily possible :)

Looking forward to seeing this!

marjakm commented 6 years ago

I have an async implementation for linux (and possibly mac, haven't tested it) that can be used with mio, but it made the api somewhat more complicated - most structs are generic to enable choosing whether you want to use the libusb sync or async api's (and to enable different async solutions for linux and windows) and if you want to store references, Rc's or Arc's to the Context. Sync and Async api's are also defined in traits. There is practically no documentation, errors are not thought through and it may be very broken (but it seems to work in one app). There is some design motivation written in the readme. Some code was copied from @kevinmehall code, I hope thats fine.

https://github.com/marjakm/libusb-rs/tree/no-lifetimes

whitequark commented 5 years ago

@kevinmehall Thanks for your code! I've found one serious issue with it though, fixed in commit whitequark/libusb-rs@9cc650c04fdc65125725b43ca513a16f220a522e.

brandonros commented 3 years ago

where did this end up? is there a way to do async USB I/O in rust with any library in 2020 or not?

jesultra commented 2 years ago

I am interested in this as well. My application does TCP communication via mio, and also uses rusb (currently only synchronously). Ideally, I would like to be able to wait for both sockets and asynchronous rusb requests using the same Poll.