Skip to main content

ad_core_rs/
codec.rs

1use crate::ndarray::NDDataType;
2
3/// Codec names for compressed NDArray data (matching C++ `NDCodecName`).
4#[derive(Debug, Clone, Copy, PartialEq, Eq)]
5pub enum CodecName {
6    None,
7    JPEG,
8    /// Zlib (deflate) compression (C++ `NDCODEC_ZLIB`).
9    Zlib,
10    LZ4,
11    Blosc,
12    BSLZ4,
13    /// LZ4 in the HDF5 framing variant (C++ `NDCODEC_LZ4HDF5`).
14    LZ4HDF5,
15}
16
17impl CodecName {
18    /// Codec name string as published in the EPICS `CODEC` parameter and the
19    /// `NDArray.codec.name` field (matching C++ `NDCodecName`).
20    pub fn as_str(self) -> &'static str {
21        match self {
22            Self::None => "",
23            Self::JPEG => "jpeg",
24            Self::Zlib => "zlib",
25            Self::LZ4 => "lz4",
26            Self::Blosc => "blosc",
27            Self::BSLZ4 => "bslz4",
28            Self::LZ4HDF5 => "lz4hdf5",
29        }
30    }
31}
32
33/// Blosc sub-compressor names (matching C++ `NDCodecBloscCompName`).
34///
35/// Indexed by `NDCodecBloscComp_t`: `BloscLZ`, `LZ4`, `LZ4HC`, `Snappy`,
36/// `ZLIB`, `ZSTD`.
37pub const BLOSC_COMP_NAMES: [&str; 6] = ["blosclz", "lz4", "lz4hc", "snappy", "zlib", "zstd"];
38
39/// Resolve a Blosc sub-compressor index to its name, matching C++
40/// `NDCodecBloscCompName[compressor]`. Out-of-range indices return `None`.
41pub fn blosc_comp_name(compressor: i32) -> Option<&'static str> {
42    usize::try_from(compressor)
43        .ok()
44        .and_then(|i| BLOSC_COMP_NAMES.get(i).copied())
45}
46
47/// Codec information attached to a compressed NDArray.
48///
49/// `name`/`level`/`shuffle`/`compressor` mirror C++ `Codec_t` and
50/// `compressed_size` mirrors `NDArray::compressedSize`. `original_data_type`
51/// folds in C++ `NDArray::dataType`, which "holds the data type of the
52/// *uncompressed* data ... used for decompression" (NDPluginCodec.cpp:35-36).
53/// The Rust port's typed [`NDDataBuffer`](crate::ndarray::NDDataBuffer)
54/// collapses to raw bytes (`U8`) once compressed and so can no longer carry the
55/// element type; because a `Codec` exists exactly when an array is compressed,
56/// this field is the single source of truth for the original element type on
57/// every compressed array (set by the codec plugin on compress, read on
58/// decompress).
59#[derive(Debug, Clone)]
60pub struct Codec {
61    pub name: CodecName,
62    pub compressed_size: usize,
63    pub level: i32,
64    pub shuffle: i32,
65    pub compressor: i32,
66    /// Element type of the uncompressed data (C++ `NDArray::dataType`),
67    /// retained so decompression can rebuild the correctly-typed buffer.
68    pub original_data_type: NDDataType,
69}
70
71#[cfg(test)]
72mod tests {
73    use super::*;
74
75    #[test]
76    fn test_codec_clone() {
77        let c = Codec {
78            name: CodecName::LZ4,
79            compressed_size: 1024,
80            level: 0,
81            shuffle: 0,
82            compressor: 0,
83            original_data_type: NDDataType::UInt16,
84        };
85        let c2 = c.clone();
86        assert_eq!(c2.name, CodecName::LZ4);
87        assert_eq!(c2.compressed_size, 1024);
88        assert_eq!(c2.original_data_type, NDDataType::UInt16);
89    }
90
91    #[test]
92    fn test_codec_name_none() {
93        assert_eq!(CodecName::None, CodecName::None);
94        assert_ne!(CodecName::None, CodecName::JPEG);
95    }
96
97    #[test]
98    fn test_codec_name_strings() {
99        // G12: name strings must match C++ NDCodecName.
100        assert_eq!(CodecName::None.as_str(), "");
101        assert_eq!(CodecName::JPEG.as_str(), "jpeg");
102        assert_eq!(CodecName::Zlib.as_str(), "zlib");
103        assert_eq!(CodecName::LZ4.as_str(), "lz4");
104        assert_eq!(CodecName::Blosc.as_str(), "blosc");
105        assert_eq!(CodecName::BSLZ4.as_str(), "bslz4");
106        assert_eq!(CodecName::LZ4HDF5.as_str(), "lz4hdf5");
107    }
108
109    #[test]
110    fn test_blosc_comp_names() {
111        // G12: Blosc sub-compressor table must match C++ NDCodecBloscCompName.
112        assert_eq!(blosc_comp_name(0), Some("blosclz"));
113        assert_eq!(blosc_comp_name(1), Some("lz4"));
114        assert_eq!(blosc_comp_name(2), Some("lz4hc"));
115        assert_eq!(blosc_comp_name(3), Some("snappy"));
116        assert_eq!(blosc_comp_name(4), Some("zlib"));
117        assert_eq!(blosc_comp_name(5), Some("zstd"));
118        assert_eq!(blosc_comp_name(6), None);
119        assert_eq!(blosc_comp_name(-1), None);
120    }
121}