tekhsi_rs 0.1.1

High-performance client for Tektronix TekHSI enabled oscilloscopes
Documentation
use crate::errors::AcquisitionError;
use crate::tekscope::WaveformHeader;
use smol_str::SmolStr;

type DataChunks = Vec<Vec<u8>>;

#[derive(Debug)]
#[allow(clippy::large_enum_variant)]
pub(crate) enum SymbolDownloadResult {
    Success {
        symbol: SmolStr,
        header: WaveformHeader,
        data_chunks: DataChunks,
    },
    Failure {
        symbol: SmolStr,
        error: AcquisitionError,
    },
}

pub(crate) struct BatchDownloadResult {
    pub results: Vec<SymbolDownloadResult>,
    pub wait_time: std::time::Duration,
    pub download_time: std::time::Duration,
}

impl Default for BatchDownloadResult {
    fn default() -> Self {
        Self {
            results: Vec::new(),
            wait_time: std::time::Duration::ZERO,
            download_time: std::time::Duration::ZERO,
        }
    }
}

impl From<AcquisitionError> for SymbolDownloadResult {
    fn from(err: AcquisitionError) -> Self {
        SymbolDownloadResult::Failure {
            symbol: SmolStr::new("unknown"),
            error: err,
        }
    }
}

impl From<tokio::task::JoinError> for SymbolDownloadResult {
    fn from(err: tokio::task::JoinError) -> Self {
        let symbol = SmolStr::new("unknown");
        SymbolDownloadResult::Failure {
            symbol,
            error: AcquisitionError::DownloadFailed {
                message: err.to_string(),
            },
        }
    }
}

#[cfg(test)]
#[cfg_attr(coverage, coverage(off))]
mod tests {
    use super::*;

    fn base_header() -> WaveformHeader {
        WaveformHeader {
            sourcename: "ch1".to_string(),
            verticalunits: "V".to_string(),
            horizontal_units: "s".to_string(),
            hasdata: true,
            ..Default::default()
        }
    }

    #[test]
    fn from_acquisition_error_creates_failure_result() {
        let error = AcquisitionError::DownloadFailed {
            message: "test error".to_string(),
        };
        let result: SymbolDownloadResult = error.into();

        match result {
            SymbolDownloadResult::Failure { symbol, error } => {
                assert_eq!(symbol, "unknown");
                assert!(matches!(error, AcquisitionError::DownloadFailed { .. }));
            }
            _ => panic!("Expected Failure outcome"),
        }
    }

    #[test]
    fn from_join_error_creates_failure_result() {
        let error = AcquisitionError::DownloadFailed {
            message: "test error".to_string(),
        };
        let result: SymbolDownloadResult = error.into();

        match result {
            SymbolDownloadResult::Failure { symbol, error } => {
                assert_eq!(symbol, "unknown");
                assert!(matches!(error, AcquisitionError::DownloadFailed { .. }));
            }
            _ => panic!("Expected Failure outcome"),
        }
    }

    #[test]
    fn batch_download_result_default() {
        let result = BatchDownloadResult::default();

        assert!(result.results.is_empty());
        assert_eq!(result.wait_time, std::time::Duration::ZERO);
        assert_eq!(result.download_time, std::time::Duration::ZERO);
    }

    #[test]
    fn create_success_symbol_download_result() {
        let result = SymbolDownloadResult::Success {
            symbol: smol_str::SmolStr::from("ch1"),
            header: base_header(),
            data_chunks: vec![vec![1, 2, 3]],
        };

        match result {
            SymbolDownloadResult::Success {
                header,
                data_chunks,
                symbol,
            } => {
                assert_eq!(symbol, "ch1");
                assert_eq!(header.sourcename, "ch1");
                assert_eq!(data_chunks.len(), 1);
                assert_eq!(data_chunks[0], vec![1, 2, 3]);
            }
            _ => panic!("Expected Success outcome"),
        }
    }
}