Skip to main content

bhwi_async_transport/
error.rs

1//! Native discovery and transport errors.
2
3use bhwi_async::{ErrorKind, ErrorKindOf, transport::io_error_kind};
4
5use crate::DeviceType;
6
7/// A result from native device discovery or opening.
8pub type NativeResult<T> = Result<T, NativeError>;
9
10/// A failure while discovering, opening, or probing a native device.
11#[derive(Debug, thiserror::Error)]
12pub enum NativeError {
13    /// Support for the requested device type is disabled in this build.
14    #[error("{0} support is not compiled into this build")]
15    NotCompiled(
16        /// The requested device type.
17        DeviceType,
18    ),
19
20    /// A device-identifier constant required by discovery is unset.
21    #[error("{0}")]
22    MissingDeviceId(
23        /// A description of the missing identifier.
24        &'static str,
25    ),
26
27    /// Listed on the bus, but no longer there when it was opened.
28    #[error("{0} is no longer connected")]
29    Gone(
30        /// The discovery path that could not be found.
31        String,
32    ),
33
34    /// Native HID enumeration or opening failed.
35    #[cfg(any(
36        feature = "bitbox",
37        feature = "coldcard",
38        feature = "keepkey",
39        feature = "ledger",
40        feature = "trezor"
41    ))]
42    #[error("hid enumeration failed: {0}")]
43    Hid(
44        /// The underlying HID error.
45        #[from]
46        async_hid::HidError,
47    ),
48
49    /// A native channel or filesystem operation failed.
50    #[error("{0}")]
51    Io(
52        /// The underlying I/O error.
53        #[from]
54        std::io::Error,
55    ),
56
57    /// Native USB enumeration failed.
58    #[cfg(any(feature = "keepkey", feature = "trezor"))]
59    #[error("usb enumeration failed: {0}")]
60    Usb(
61        /// The underlying `nusb` error.
62        #[from]
63        nusb::Error,
64    ),
65
66    /// Serial-port enumeration or opening failed.
67    #[cfg(any(feature = "jade", feature = "specter"))]
68    #[error("serial port enumeration failed: {0}")]
69    Serial(
70        /// The underlying serial-port error.
71        #[from]
72        tokio_serial::Error,
73    ),
74
75    /// Linux serial enumeration cannot access `/sys/class/tty`.
76    #[cfg(any(feature = "jade", feature = "specter"))]
77    #[error("serial port enumeration unavailable: /sys/class/tty is missing")]
78    SerialSysfsMissing,
79
80    /// The port opened, but the device did not answer as the expected type.
81    #[cfg(feature = "specter")]
82    #[error("probing {device_type}: {source}")]
83    Probe {
84        /// The device type expected on the opened channel.
85        device_type: DeviceType,
86        /// The failed protocol probe.
87        source: bhwi_async::HWIDeviceError,
88    },
89}
90
91impl NativeError {
92    /// Returns the failure kind of a discovery or opening error.
93    pub fn kind(&self) -> ErrorKind {
94        match self {
95            Self::NotCompiled(_) => ErrorKind::Unsupported,
96            Self::MissingDeviceId(_) => ErrorKind::InvalidInput,
97            Self::Gone(_) => ErrorKind::Disconnected,
98            Self::Io(error) => io_error_kind(error),
99            #[cfg(any(
100                feature = "bitbox",
101                feature = "coldcard",
102                feature = "keepkey",
103                feature = "ledger",
104                feature = "trezor"
105            ))]
106            Self::Hid(async_hid::HidError::Disconnected | async_hid::HidError::NotConnected) => {
107                ErrorKind::Disconnected
108            }
109            #[cfg(any(
110                feature = "bitbox",
111                feature = "coldcard",
112                feature = "keepkey",
113                feature = "ledger",
114                feature = "trezor"
115            ))]
116            Self::Hid(_) => ErrorKind::Transport,
117            #[cfg(any(feature = "keepkey", feature = "trezor"))]
118            Self::Usb(_) => ErrorKind::Transport,
119            #[cfg(any(feature = "jade", feature = "specter"))]
120            Self::Serial(_) | Self::SerialSysfsMissing => ErrorKind::Transport,
121            #[cfg(feature = "specter")]
122            Self::Probe { source, .. } => source.kind().unwrap_or(ErrorKind::Other),
123        }
124    }
125}
126
127impl ErrorKindOf for NativeError {
128    fn error_kind(&self) -> ErrorKind {
129        self.kind()
130    }
131}