streamdeck-commands/src/lib.rs
2022-02-06 15:17:38 -06:00

105 lines
2.4 KiB
Rust

use tokio::io::{AsyncRead, AsyncReadExt, AsyncWrite, AsyncWriteExt};
use tokio_serial::SerialStream;
use tracing_error::SpanTrace;
#[derive(Debug)]
pub struct Error {
kind: ErrorKind,
context: SpanTrace,
}
#[derive(Debug, thiserror::Error)]
pub enum ErrorKind {
#[error(transparent)]
Serial(#[from] tokio_serial::Error),
#[error(transparent)]
Io(#[from] std::io::Error),
#[error(transparent)]
Utf8(#[from] std::string::FromUtf8Error),
}
pub async fn identity(port: &mut SerialStream) -> Result<Vec<u8>, Error> {
get_prop(port, b"ident").await
}
pub async fn name(port: &mut SerialStream) -> Result<String, Error> {
get_string_prop(port, b"name").await
}
pub async fn author(port: &mut SerialStream) -> Result<String, Error> {
get_string_prop(port, b"author").await
}
pub async fn repo(port: &mut SerialStream) -> Result<String, Error> {
get_string_prop(port, b"repo").await
}
pub async fn version(port: &mut SerialStream) -> Result<String, Error> {
get_string_prop(port, b"version").await
}
pub async fn reset(port: &mut SerialStream) -> Result<(), Error> {
send_command(port, b"reset").await
}
async fn send_command<Port>(port: &mut Port, command: &[u8]) -> Result<(), Error>
where
Port: AsyncWrite + Unpin,
{
port.write_all(command).await?;
port.flush().await?;
Ok(())
}
async fn get_string_prop<Port>(port: &mut Port, prop: &[u8]) -> Result<String, Error>
where
Port: AsyncRead + AsyncWrite + Unpin,
{
Ok(String::from_utf8(get_prop(port, prop).await?)?)
}
async fn get_prop<Port>(port: &mut Port, prop: &[u8]) -> Result<Vec<u8>, Error>
where
Port: AsyncRead + AsyncWrite + Unpin,
{
send_command::<Port>(port, prop).await?;
let mut len_buf = [0u8; 1];
port.read_exact(&mut len_buf).await?;
let input_len = len_buf[0];
let mut input = vec![0u8; input_len as usize];
port.read_exact(&mut input).await?;
Ok(input)
}
impl std::fmt::Display for Error {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
writeln!(f, "{}", self.kind)?;
std::fmt::Display::fmt(&self.context, f)
}
}
impl std::error::Error for Error {
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
self.kind.source()
}
}
impl<T> From<T> for Error
where
ErrorKind: From<T>,
{
fn from(error: T) -> Self {
Error {
kind: error.into(),
context: SpanTrace::capture(),
}
}
}