From d9d4a906c919ed3333a128de797cedad017b442d Mon Sep 17 00:00:00 2001 From: mitchmindtree Date: Sun, 13 Oct 2019 12:07:49 +0200 Subject: [PATCH] Switch to dtolnay's `thiserror` for handling error boilerplate Currently CPAL only really uses `failure` for its `derive` capabilities and the ability to easily generate implementations for `Display`. That said there are a few issues with using the `failure` crate: - `failure` does not provie a `std::error::Error` implementation without first converting error types into `failure::Error`. - It leaks significantly into the public API and expects downstream users to also depend on `failure` and the non-std `Fail` trait for their own error handling. - Solved problems such as downcasting of causal errors which have since been addressed in `std`. - Provides application-friendly `Fail` trait and `failure::Error` type, not particularly useful to libraries like CPAL. The [`thiserror` crate](https://github.com/dtolnay/thiserror) is better targeted towards libraries, does not leak into the public API while providing easy generation of `Display`, `From` and `std::error::Error` implementations including proper handling of the newish `std::error::Error::source` method. --- Cargo.toml | 2 +- src/error.rs | 138 +++++++++++++++------------------------------------ src/lib.rs | 2 +- 3 files changed, 43 insertions(+), 99 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 31ef031..7208127 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,7 +12,7 @@ keywords = ["audio", "sound"] asio = ["asio-sys"] # Only available on Windows. See README for setup instructions. [dependencies] -failure = "0.1.5" +thiserror = "1.0.2" lazy_static = "1.3" num-traits = "0.2.6" diff --git a/src/error.rs b/src/error.rs index fe06b3f..0a87bbe 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,8 +1,8 @@ -use failure::Fail; +use thiserror::Error; /// The requested host, although supported on this platform, is unavailable. -#[derive(Clone, Debug, Fail)] -#[fail(display = "the requested host is unavailable")] +#[derive(Clone, Debug, Error)] +#[error("the requested host is unavailable")] pub struct HostUnavailable; /// Some error has occurred that is specific to the backend from which it was produced. @@ -17,101 +17,95 @@ pub struct HostUnavailable; /// **Note:** If you notice a `BackendSpecificError` that you believe could be better handled in a /// cross-platform manner, please create an issue or submit a pull request with a patch that adds /// the necessary error variant to the appropriate error enum. -#[derive(Clone, Debug, Fail)] -#[fail(display = "A backend-specific error has occurred: {}", description)] +#[derive(Clone, Debug, Error)] +#[error("A backend-specific error has occurred: {description}")] pub struct BackendSpecificError { pub description: String, } /// An error that might occur while attempting to enumerate the available devices on a system. -#[derive(Debug, Fail)] +#[derive(Debug, Error)] pub enum DevicesError { /// See the `BackendSpecificError` docs for more information about this error variant. - #[fail(display = "{}", err)] + #[error("{err}")] BackendSpecific { - #[fail(cause)] + #[from] err: BackendSpecificError, }, } /// An error that may occur while attempting to retrieve a device name. -#[derive(Debug, Fail)] +#[derive(Debug, Error)] pub enum DeviceNameError { /// See the `BackendSpecificError` docs for more information about this error variant. - #[fail(display = "{}", err)] + #[error("{err}")] BackendSpecific { - #[fail(cause)] + #[from] err: BackendSpecificError, }, } /// Error that can happen when enumerating the list of supported formats. -#[derive(Debug, Fail)] +#[derive(Debug, Error)] pub enum SupportedFormatsError { /// The device no longer exists. This can happen if the device is disconnected while the /// program is running. - #[fail( - display = "The requested device is no longer available. For example, it has been unplugged." - )] + #[error("The requested device is no longer available. For example, it has been unplugged.")] DeviceNotAvailable, /// We called something the C-Layer did not understand - #[fail( - display = "Invalid argument passed to the backend. For example, this happens when trying to read capture capabilities when the device does not support it." + #[error( + "Invalid argument passed to the backend. For example, this happens when trying to read capture capabilities when the device does not support it." )] InvalidArgument, /// See the `BackendSpecificError` docs for more information about this error variant. - #[fail(display = "{}", err)] + #[error("{err}")] BackendSpecific { - #[fail(cause)] + #[from] err: BackendSpecificError, }, } /// May occur when attempting to request the default input or output stream format from a `Device`. -#[derive(Debug, Fail)] +#[derive(Debug, Error)] pub enum DefaultFormatError { /// The device no longer exists. This can happen if the device is disconnected while the /// program is running. - #[fail( - display = "The requested device is no longer available. For example, it has been unplugged." - )] + #[error("The requested device is no longer available. For example, it has been unplugged.")] DeviceNotAvailable, /// Returned if e.g. the default input format was requested on an output-only audio device. - #[fail(display = "The requested stream type is not supported by the device.")] + #[error("The requested stream type is not supported by the device.")] StreamTypeNotSupported, /// See the `BackendSpecificError` docs for more information about this error variant. - #[fail(display = "{}", err)] + #[error("{err}")] BackendSpecific { - #[fail(cause)] + #[from] err: BackendSpecificError, }, } /// Error that can happen when creating a `Stream`. -#[derive(Debug, Fail)] +#[derive(Debug, Error)] pub enum BuildStreamError { /// The device no longer exists. This can happen if the device is disconnected while the /// program is running. - #[fail( - display = "The requested device is no longer available. For example, it has been unplugged." - )] + #[error("The requested device is no longer available. For example, it has been unplugged.")] DeviceNotAvailable, /// The required format is not supported. - #[fail(display = "The requested stream format is not supported by the device.")] + #[error("The requested stream format is not supported by the device.")] FormatNotSupported, /// We called something the C-Layer did not understand /// /// On ALSA device functions called with a feature they do not support will yield this. E.g. /// Trying to use capture capabilities on an output only format yields this. - #[fail(display = "The requested device does not support this capability (invalid argument)")] + #[error("The requested device does not support this capability (invalid argument)")] InvalidArgument, /// Occurs if adding a new Stream ID would cause an integer overflow. - #[fail(display = "Adding a new stream ID would cause an overflow")] + #[error("Adding a new stream ID would cause an overflow")] StreamIdOverflow, /// See the `BackendSpecificError` docs for more information about this error variant. - #[fail(display = "{}", err)] + #[error("{err}")] BackendSpecific { - #[fail(cause)] + #[from] err: BackendSpecificError, }, } @@ -121,15 +115,15 @@ pub enum BuildStreamError { /// As of writing this, only macOS may immediately return an error while calling this method. This /// is because both the alsa and wasapi backends only enqueue these commands and do not process /// them immediately. -#[derive(Debug, Fail)] +#[derive(Debug, Error)] pub enum PlayStreamError { /// The device associated with the stream is no longer available. - #[fail(display = "the device associated with the stream is no longer available")] + #[error("the device associated with the stream is no longer available")] DeviceNotAvailable, /// See the `BackendSpecificError` docs for more information about this error variant. - #[fail(display = "{}", err)] + #[error("{err}")] BackendSpecific { - #[fail(cause)] + #[from] err: BackendSpecificError, }, } @@ -139,80 +133,30 @@ pub enum PlayStreamError { /// As of writing this, only macOS may immediately return an error while calling this method. This /// is because both the alsa and wasapi backends only enqueue these commands and do not process /// them immediately. -#[derive(Debug, Fail)] +#[derive(Debug, Error)] pub enum PauseStreamError { /// The device associated with the stream is no longer available. - #[fail(display = "the device associated with the stream is no longer available")] + #[error("the device associated with the stream is no longer available")] DeviceNotAvailable, /// See the `BackendSpecificError` docs for more information about this error variant. - #[fail(display = "{}", err)] + #[error("{err}")] BackendSpecific { - #[fail(cause)] + #[from] err: BackendSpecificError, }, } /// Errors that might occur while a stream is running. -#[derive(Debug, Fail)] +#[derive(Debug, Error)] pub enum StreamError { /// The device no longer exists. This can happen if the device is disconnected while the /// program is running. - #[fail( - display = "The requested device is no longer available. For example, it has been unplugged." - )] + #[error("The requested device is no longer available. For example, it has been unplugged.")] DeviceNotAvailable, /// See the `BackendSpecificError` docs for more information about this error variant. - #[fail(display = "{}", err)] + #[error("{err}")] BackendSpecific { - #[fail(cause)] + #[from] err: BackendSpecificError, }, } - -impl From for DevicesError { - fn from(err: BackendSpecificError) -> Self { - DevicesError::BackendSpecific { err } - } -} - -impl From for DeviceNameError { - fn from(err: BackendSpecificError) -> Self { - DeviceNameError::BackendSpecific { err } - } -} - -impl From for SupportedFormatsError { - fn from(err: BackendSpecificError) -> Self { - SupportedFormatsError::BackendSpecific { err } - } -} - -impl From for DefaultFormatError { - fn from(err: BackendSpecificError) -> Self { - DefaultFormatError::BackendSpecific { err } - } -} - -impl From for BuildStreamError { - fn from(err: BackendSpecificError) -> Self { - BuildStreamError::BackendSpecific { err } - } -} - -impl From for PlayStreamError { - fn from(err: BackendSpecificError) -> Self { - PlayStreamError::BackendSpecific { err } - } -} - -impl From for PauseStreamError { - fn from(err: BackendSpecificError) -> Self { - PauseStreamError::BackendSpecific { err } - } -} - -impl From for StreamError { - fn from(err: BackendSpecificError) -> Self { - StreamError::BackendSpecific { err } - } -} diff --git a/src/lib.rs b/src/lib.rs index 783fd6d..a2b1ddb 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -140,7 +140,6 @@ #![recursion_limit = "512"] -extern crate failure; #[cfg(target_os = "windows")] #[macro_use] extern crate lazy_static; @@ -148,6 +147,7 @@ extern crate lazy_static; #[cfg(target_os = "emscripten")] #[macro_use] extern crate stdweb; +extern crate thiserror; pub use error::*; pub use platform::{