1#![forbid(future_incompatible)]
2#![deny(bad_style, missing_docs)]
3#![doc = include_str!("../README.md")]
4
5use hidg_core::{check_read, check_write, AsDevicePath};
6
7pub use hidg_core::{Class, Error, Result, StateChange, ValueChange};
8
9#[cfg(feature = "keyboard")]
10pub use hidg_core::{
11 Key, KeyStateChanges, Keyboard, KeyboardInput, KeyboardOutput, Led, LedStateChanges, Leds,
12 Modifiers,
13};
14
15#[cfg(feature = "mouse")]
16pub use hidg_core::{
17 Button, Buttons, Mouse, MouseInput, MouseInputChange, MouseInputChanges, MouseOutput,
18};
19
20use core::marker::PhantomData;
21use std::{
22 fs::{File, OpenOptions},
23 io::{Read, Write},
24};
25
26use async_io::Async;
27use blocking::unblock as asyncify;
28
29pub struct Device<C: Class> {
31 file: Async<File>,
32 _class: PhantomData<C>,
33}
34
35impl<C: Class> Device<C> {
36 pub async fn open(device: impl AsDevicePath) -> Result<Self> {
38 let path = device.as_device_path();
39 let file = Async::new(
40 asyncify(move || OpenOptions::new().read(true).write(true).open(path)).await?,
41 )?;
42 Ok(Self {
43 file,
44 _class: PhantomData,
45 })
46 }
47
48 pub async fn input(&mut self, input: &C::Input) -> Result<()>
50 where
51 C::Input: AsRef<[u8]>,
52 {
53 self.file.writable().await?;
54 let raw = input.as_ref();
55 let len = self.file.get_ref().write(raw)?;
56
57 check_write(len, raw.len())
58 }
59
60 pub async fn output(&mut self, output: &mut C::Output) -> Result<()>
62 where
63 C::Output: AsMut<[u8]>,
64 {
65 self.file.readable().await?;
66 let raw = output.as_mut();
67 let len = self.file.get_ref().read(raw)?;
68
69 check_read(len, raw.len())?;
70
71 Ok(())
72 }
73}