use std::fmt::Debug;
use std::future::Future;
use std::pin::Pin;
use std::task::{ready, Context, Poll};
pub use usb::*;
mod usb;
#[derive(Clone, Copy, Debug, thiserror::Error)]
#[non_exhaustive]
pub enum Error {
#[error("usb error: {source}")]
Usb {
#[from]
source: rusb::Error,
},
}
impl Error {
#[inline]
#[must_use]
pub const fn is_timeout(&self) -> bool {
matches!(
self,
&Self::Usb {
source: rusb::Error::Timeout
}
)
}
}
pub type Result<T> = std::result::Result<T, Error>;
pub trait Transport: Debug + Send + Sync {
fn command(&self) -> Box<dyn Transfer>;
fn event(&self) -> Box<dyn Transfer>;
fn acl(&self, dir: Direction, max_data_len: u16) -> Box<dyn Transfer>;
}
#[allow(clippy::exhaustive_enums)]
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
pub enum Direction {
In,
Out,
}
pub trait Transfer:
AsRef<[u8]> + Debug + Send + Sync + structbuf::Pack + structbuf::Unpack
{
fn submit(self: Box<Self>) -> Result<TransferFuture>;
fn reset(&mut self);
}
pub trait ActiveTransfer: Debug + Future<Output = Result<()>> + Send {
fn ready(self: Box<Self>) -> Box<dyn Transfer>;
}
#[derive(Debug)]
#[repr(transparent)]
pub struct TransferFuture(Option<Box<dyn ActiveTransfer>>);
impl Future for TransferFuture {
type Output = Result<Box<dyn Transfer>>;
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
let opt = &mut self.get_mut().0;
let fut = (opt.as_mut().expect("poll of a finished transfer")).as_mut();
ready!(unsafe { Pin::new_unchecked(fut) }.poll(cx))?;
Poll::Ready(Ok(unsafe { opt.take().unwrap_unchecked() }.ready()))
}
}