lasprs 0.14.3

Library for Acoustic Signal Processing (Rust edition, with optional Python bindings via pyo3)
Documentation
use super::*;
use crate::*;
use snafu::prelude::*;
use std::fmt::{Display, Formatter};

/// Stream manager errors
#[allow(missing_docs)]
#[derive(Debug, Snafu, Clone)]
#[snafu(visibility(pub(crate)))]
#[cfg_attr(
    feature = "python-bindings",
    gen_stub_pyclass_complex_enum,
    pyclass(from_py_object)
)]
pub enum StreamMgrError {
    #[snafu(display("API '{}' is not available.", apiname))]
    ApiNotAvailable { apiname: String },

    #[snafu(display("API specific error: {}", msg))]
    APISpecificError { msg: String },

    #[snafu(display("Backend specific error: {}", msg))]
    BackendSpecificError { msg: String },

    #[snafu(display("Unable to start a default stream: CPAL API is not available"))]
    CPALNotAvailable {},

    #[snafu(display("Data type not supported: {dtype}"))]
    DataTypeNotSupported { dtype: String },

    #[snafu(display("DAQ Configuration error: {}", msg))]
    DAQConfigError { msg: String },

    #[snafu(display("DAQ Configuration validation error: {}", source))]
    DAQConfigValidationError { source: ValidationError },

    #[snafu(display("Device {} not available", device_name))]
    DeviceNotAvailableError { device_name: String },

    /// Cannot complete operation: a device scan is currently in progress.
    DeviceScanAlreadyInProgress {},

    #[snafu(display("Cannot perform operation: an input stream is (already) running"))]
    InputStreamAlreadyRunning {},

    #[snafu(display("Cannot perform operation: an input stream is not running"))]
    InputStreamNotRunning {},

    #[snafu(display("Cannot perform operation: an output stream is (already) running"))]
    OutputStreamAlreadyRunning {},

    #[snafu(display("Cannot perform operation: an output stream is not running"))]
    OutputStreamNotRunning {},

    #[snafu(display("Signal generator error: {}", source))]
    SiggenError { source: crate::siggen::SiggenError },

    #[snafu(display("Stream error: {}", source))]
    StreamError { source: StreamError },

    #[snafu(display(
        "Buffer size not supported by the device: min={}, max={}, requested={}",
        min,
        max,
        requested
    ))]
    BufferSizeNotSupported { min: u32, max: u32, requested: u32 },

    /// No default device found
    NoDefaultDeviceFound {},
}

cfg_select! {
    any(feature="python-bindings") => {
        use pyo3::exceptions::PyException;
        #[gen_stub_pyclass]
        #[pyclass(extends = PyException, str, from_py_object)] // or PyBaseException
        /// Wrapper for StreamMgrError, to make it a struct, not enum, as enums cannot
        /// be extended from PyBaseException.
        #[derive(Debug, Clone)]
        pub struct PyStreamMgrError {
            /// The inner error
            #[pyo3(get)]
            pub inner: StreamMgrError,
        }
        impl Display for PyStreamMgrError {
            fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
                write!(f, "{}", self.inner)
            }
        }
        #[gen_stub_pymethods]
        #[pymethods]
        impl PyStreamMgrError {
            /// Create a new PyStreamMgrError from a StreamMgrError
            #[new]
            fn new(inner: StreamMgrError) -> Self {
                PyStreamMgrError { inner }
            }
        }

        impl From<StreamMgrError> for PyErr {
            fn from(value: StreamMgrError) -> Self {
                // let err = PyStreamMgrError {inner: value};
                // PyErr::from_value(err.into())
                PyErr::new::<PyStreamMgrError, _>(value)
            }
        }
    }
    _ => {}
}

#[cfg(test)]
mod test {
    use super::*;
    #[test]
    fn test_stream_mgr_error() {
        let err = StreamMgrError::ApiNotAvailable {
            apiname: "testapi".to_string(),
        };
        assert_eq!(err.to_string(), "API 'testapi' is not available.");
        assert_eq!(format!("{}", err), "API 'testapi' is not available.");
    }
}