1use std::fmt;
2
3#[derive(Debug)]
5pub enum ObnizError {
6 Connection(String),
8
9 WebSocket(String),
11
12 IoOperation(String),
14
15 InvalidPin(u8),
17
18 JsonParse(String),
20
21 Timeout,
23
24 CallbackError(String),
26
27 DeviceNotFound(String),
29
30 PermissionDenied,
32
33 Generic(String),
35}
36
37impl fmt::Display for ObnizError {
38 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
39 match self {
40 ObnizError::Connection(msg) => write!(f, "Connection error: {msg}"),
41 ObnizError::WebSocket(msg) => write!(f, "WebSocket error: {msg}"),
42 ObnizError::IoOperation(msg) => write!(f, "IO operation error: {msg}"),
43 ObnizError::InvalidPin(pin) => {
44 write!(f, "Invalid pin number: {pin}. Valid range is 0-11")
45 }
46 ObnizError::JsonParse(msg) => write!(f, "JSON parse error: {msg}"),
47 ObnizError::Timeout => write!(f, "Operation timed out"),
48 ObnizError::CallbackError(msg) => write!(f, "Callback error: {msg}"),
49 ObnizError::DeviceNotFound(id) => write!(f, "Device not found: {id}"),
50 ObnizError::PermissionDenied => write!(f, "Permission denied"),
51 ObnizError::Generic(msg) => write!(f, "Error: {msg}"),
52 }
53 }
54}
55
56impl std::error::Error for ObnizError {}
57
58impl From<anyhow::Error> for ObnizError {
59 fn from(err: anyhow::Error) -> Self {
60 ObnizError::Generic(err.to_string())
61 }
62}
63
64impl From<serde_json::Error> for ObnizError {
65 fn from(err: serde_json::Error) -> Self {
66 ObnizError::JsonParse(err.to_string())
67 }
68}
69
70impl From<tokio_tungstenite::tungstenite::Error> for ObnizError {
71 fn from(err: tokio_tungstenite::tungstenite::Error) -> Self {
72 ObnizError::WebSocket(err.to_string())
73 }
74}
75
76impl From<tokio::sync::oneshot::error::RecvError> for ObnizError {
77 fn from(_: tokio::sync::oneshot::error::RecvError) -> Self {
78 ObnizError::Timeout
79 }
80}
81
82impl From<tokio::sync::mpsc::error::SendError<crate::obniz::ObnizCommand>> for ObnizError {
83 fn from(err: tokio::sync::mpsc::error::SendError<crate::obniz::ObnizCommand>) -> Self {
84 ObnizError::Connection(format!("Failed to send command: {err}"))
85 }
86}
87
88pub type ObnizResult<T> = Result<T, ObnizError>;
90
91pub fn validate_pin(pin: u8) -> ObnizResult<()> {
93 if pin > 11 {
94 Err(ObnizError::InvalidPin(pin))
95 } else {
96 Ok(())
97 }
98}
99
100pub async fn with_timeout<F, T>(future: F, timeout_duration: std::time::Duration) -> ObnizResult<T>
102where
103 F: std::future::Future<Output = ObnizResult<T>>,
104{
105 match tokio::time::timeout(timeout_duration, future).await {
106 Ok(result) => result,
107 Err(_) => Err(ObnizError::Timeout),
108 }
109}