Skip to main content

netcdf_reader/classic/
types.rs

1//! NC type mapping and helper functions for the classic (CDF-1/2/5) format.
2
3use crate::error::{Error, Result};
4use crate::types::NcType;
5
6// NetCDF classic type codes (from the binary header).
7pub const NC_BYTE: u32 = 1;
8pub const NC_CHAR: u32 = 2;
9pub const NC_SHORT: u32 = 3;
10pub const NC_INT: u32 = 4;
11pub const NC_FLOAT: u32 = 5;
12pub const NC_DOUBLE: u32 = 6;
13// CDF-5 extended types.
14pub const NC_UBYTE: u32 = 7;
15pub const NC_USHORT: u32 = 8;
16pub const NC_UINT: u32 = 9;
17pub const NC_INT64: u32 = 10;
18pub const NC_UINT64: u32 = 11;
19
20/// Convert a classic NC type code to an `NcType`.
21pub fn nc_type_from_code(code: u32) -> Result<NcType> {
22    match code {
23        NC_BYTE => Ok(NcType::Byte),
24        NC_CHAR => Ok(NcType::Char),
25        NC_SHORT => Ok(NcType::Short),
26        NC_INT => Ok(NcType::Int),
27        NC_FLOAT => Ok(NcType::Float),
28        NC_DOUBLE => Ok(NcType::Double),
29        NC_UBYTE => Ok(NcType::UByte),
30        NC_USHORT => Ok(NcType::UShort),
31        NC_UINT => Ok(NcType::UInt),
32        NC_INT64 => Ok(NcType::Int64),
33        NC_UINT64 => Ok(NcType::UInt64),
34        _ => Err(Error::InvalidData(format!("unknown NC type code {}", code))),
35    }
36}
37
38/// Size of one element for a classic NC type code.
39pub fn nc_type_size(code: u32) -> Result<usize> {
40    Ok(nc_type_from_code(code)?.size())
41}
42
43/// Compute the amount of padding needed to reach a 4-byte boundary.
44pub fn padding_to_4(len: usize) -> usize {
45    let rem = len % 4;
46    if rem == 0 {
47        0
48    } else {
49        4 - rem
50    }
51}
52
53/// Round up to the next 4-byte boundary.
54pub fn pad_to_4(len: usize) -> usize {
55    len + padding_to_4(len)
56}
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61
62    #[test]
63    fn test_nc_type_from_code() {
64        assert_eq!(nc_type_from_code(1).unwrap(), NcType::Byte);
65        assert_eq!(nc_type_from_code(2).unwrap(), NcType::Char);
66        assert_eq!(nc_type_from_code(3).unwrap(), NcType::Short);
67        assert_eq!(nc_type_from_code(4).unwrap(), NcType::Int);
68        assert_eq!(nc_type_from_code(5).unwrap(), NcType::Float);
69        assert_eq!(nc_type_from_code(6).unwrap(), NcType::Double);
70        assert_eq!(nc_type_from_code(7).unwrap(), NcType::UByte);
71        assert_eq!(nc_type_from_code(8).unwrap(), NcType::UShort);
72        assert_eq!(nc_type_from_code(9).unwrap(), NcType::UInt);
73        assert_eq!(nc_type_from_code(10).unwrap(), NcType::Int64);
74        assert_eq!(nc_type_from_code(11).unwrap(), NcType::UInt64);
75        assert!(nc_type_from_code(0).is_err());
76        assert!(nc_type_from_code(12).is_err());
77    }
78
79    #[test]
80    fn test_padding() {
81        assert_eq!(padding_to_4(0), 0);
82        assert_eq!(padding_to_4(1), 3);
83        assert_eq!(padding_to_4(2), 2);
84        assert_eq!(padding_to_4(3), 1);
85        assert_eq!(padding_to_4(4), 0);
86        assert_eq!(padding_to_4(5), 3);
87        assert_eq!(pad_to_4(0), 0);
88        assert_eq!(pad_to_4(1), 4);
89        assert_eq!(pad_to_4(3), 4);
90        assert_eq!(pad_to_4(4), 4);
91        assert_eq!(pad_to_4(5), 8);
92    }
93}