lasprs 0.14.3

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

#[cfg_attr(feature = "python-bindings", gen_stub_pyclass, pyclass(from_py_object))]
#[derive(Debug, Clone, Snafu)]
/// Error type for HDF5-related operations.
#[snafu(display("HDF5 error: {}", source))]
pub struct H5Error {
    source: hdf5_metno::Error,
}
impl From<hdf5_metno::Error> for H5Error {
    fn from(err: hdf5_metno::Error) -> Self {
        H5Error { source: err }
    }
}

#[cfg_attr(feature = "python-bindings", gen_stub_pyclass, pyclass(from_py_object))]
#[derive(Debug, Clone, Snafu)]
/// Error type for JSON-related operations.
pub struct JSONError {
    message: String,
}
impl From<serde_json::Error> for JSONError {
    fn from(err: serde_json::Error) -> Self {
        JSONError {
            message: err.to_string(),
        }
    }
}

#[cfg_attr(
    feature = "python-bindings",
    gen_stub_pyclass_complex_enum,
    pyclass(from_py_object)
)]
#[allow(missing_docs)]
#[derive(Debug, Clone, Snafu)]
#[snafu(visibility(pub(crate)))]
pub enum MeasurementError {
    #[snafu(display(r#"Could not open file: "{}". It might have been deleted or moved."#, filepath.as_os_str().to_string_lossy()))]
    FileNotFound { filepath: PathBuf },

    #[snafu(display(
        "Measurement '{}' is still running. Measurement is usable when recording is finished.",
        name
    ))]
    MeasurementStillRunning { name: String },

    #[snafu(display(
        "An error occurred while reading from / writing to the measurement file: {}. Error: {}",
        filepath.as_os_str().to_string_lossy(),
        error
    ))]
    FileError { filepath: PathBuf, error: String },

    #[snafu(display("Invalid measurement file name: '{}'. Reason: {}.", name, reason))]
    InvalidMeasurementName { name: String, reason: String },

    #[snafu(display(
        "An error occurred while reading from / writing to the measurement file: {}. Operation: {}",
        source.to_string(),
        operation
    ))]
    H5FileProblem { source: H5Error, operation: String },

    #[snafu(display("Failed to write attribute '{}' to the measurement file. Error: {}.", attr_name, source.to_string(),))]
    WritingAttributeFailed { attr_name: String, source: H5Error },

    #[snafu(display("Failed to read attribute '{}' from the measurement file. Error: {}.", attr_name, source.to_string(),))]
    ReadingAttributeFailed { attr_name: String, source: H5Error },

    #[snafu(display("Error importing WAV file: {}", msg))]
    WAVImportError { msg: String },

    #[snafu(display(
        "Output file '{}' already exists. Set overwrite=true to replace it.",
        path.as_os_str().to_string_lossy()
    ))]
    ExportWavFileExists { path: PathBuf },

    #[snafu(display(
        "Lossy conversion from {from} to {to} is not allowed. Set allow_lossy=true to override."
    ))]
    ExportWavLossyConversion { from: DataType, to: DataType },

    #[snafu(display("Error writing WAV file: {}", msg))]
    ExportWavWriteError { msg: String },

    #[snafu(display("Unsupported WAV export format: {}", msg))]
    ExportWavUnsupported { msg: String },

    #[snafu(display(
        "Data in the measurement file is possibly corrupted. Possible error: {}.",
        possible_error
    ))]
    DataCorrupted { possible_error: String },

    #[snafu(display("Failed to parse metadata for field '{}' from the measurement file. Error: {}.", field, source.to_string(),))]
    ParseMeta { field: String, source: JSONError },

    #[snafu(display("Channel index out of bounds. Requested index: {}, but maximum index is {}.", channel_idx, max_channels-1))]
    ChannelIdxOutOfBounds {
        channel_idx: usize,
        max_channels: usize,
    },

    #[snafu(display("Sample index out of bounds. Requested index: {}, but maximum index is {}.", sample_idx, max_samples-1))]
    SampleIdxOutOfBounds {
        sample_idx: usize,
        max_samples: usize,
    },

    #[snafu(display("Parameter '{}' out of range. Error: {}", parameter, source.to_string()))]
    ParameterOutOfRange {
        parameter: String,
        source: ValidationError,
    },

    #[snafu(display("Logic error while processing measurement '{}': {}", name, message))]
    Logic { name: String, message: String },

    #[snafu(display("Error renaming measurement '{}': {}", name, msg))]
    RenameError { name: String, msg: String },

    #[snafu(display(
        "NFFT is too large for amount of samples to compute spectra for. Please increase the number of samples, or decrease. FFT length. NFFT: {}, but number of samples is {}.",
        nfft,
        nsamples
    ))]
    NFFTTooLarge { nfft: usize, nsamples: usize },

    #[snafu(display(
        "Duplicate UUID '{}' found for measurement files '{}' and '{}'. Please
        remove one of these files as it is a copy of the other.",
        uuid,
        path1,
        path2
    ))]
    DuplicateUUID {
        path1: String,
        path2: String,
        uuid: String,
    },
}

#[cfg(feature = "python-bindings")]
#[gen_stub_pymethods]
#[pymethods]
impl MeasurementError {
    fn __str__(&self) -> String {
        self.to_string()
    }
}

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

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