netcdf_reader/nc4/
types.rs1use hdf5_reader::messages::datatype::Datatype;
30
31use crate::error::{Error, Result};
32use crate::types::{NcCompoundField, NcType};
33
34pub fn hdf5_to_nc_type(dtype: &Datatype) -> Result<NcType> {
36 match dtype {
37 Datatype::FixedPoint { size, signed, .. } => match (size, signed) {
38 (1, true) => Ok(NcType::Byte),
39 (1, false) => Ok(NcType::UByte),
40 (2, true) => Ok(NcType::Short),
41 (2, false) => Ok(NcType::UShort),
42 (4, true) => Ok(NcType::Int),
43 (4, false) => Ok(NcType::UInt),
44 (8, true) => Ok(NcType::Int64),
45 (8, false) => Ok(NcType::UInt64),
46 _ => Err(Error::InvalidData(format!(
47 "unsupported HDF5 integer size {} for NetCDF-4",
48 size
49 ))),
50 },
51 Datatype::FloatingPoint { size, .. } => match size {
52 4 => Ok(NcType::Float),
53 8 => Ok(NcType::Double),
54 _ => Err(Error::InvalidData(format!(
55 "unsupported HDF5 float size {} for NetCDF-4",
56 size
57 ))),
58 },
59 Datatype::String { .. } => Ok(NcType::String),
60 Datatype::Enum { base, .. } => {
61 hdf5_to_nc_type(base)
63 }
64 Datatype::Compound { size, fields } => {
65 let mut nc_fields = Vec::with_capacity(fields.len());
66 for f in fields {
67 nc_fields.push(NcCompoundField {
68 name: f.name.clone(),
69 offset: f.byte_offset as u64,
70 dtype: hdf5_to_nc_type(&f.datatype)?,
71 });
72 }
73 Ok(NcType::Compound {
74 size: *size,
75 fields: nc_fields,
76 })
77 }
78 Datatype::Opaque { size, tag } => Ok(NcType::Opaque {
79 size: *size,
80 tag: tag.clone(),
81 }),
82 Datatype::Array { base, dims } => {
83 let base_nc = hdf5_to_nc_type(base)?;
84 Ok(NcType::Array {
85 base: Box::new(base_nc),
86 dims: dims.clone(),
87 })
88 }
89 Datatype::VarLen { base }
90 if matches!(
91 base.as_ref(),
92 Datatype::FixedPoint {
93 size: 1,
94 signed: false,
95 ..
96 }
97 ) =>
98 {
99 Ok(NcType::String)
100 }
101 Datatype::VarLen { base } => {
102 let base_nc = hdf5_to_nc_type(base)?;
103 Ok(NcType::VLen {
104 base: Box::new(base_nc),
105 })
106 }
107 _ => Err(Error::InvalidData(format!(
108 "HDF5 datatype {:?} has no NetCDF-4 equivalent",
109 dtype
110 ))),
111 }
112}
113
114#[cfg(test)]
115mod tests {
116 use super::*;
117 use hdf5_reader::error::ByteOrder;
118
119 #[test]
120 fn test_integer_types() {
121 let bo = ByteOrder::LittleEndian;
122 assert_eq!(
123 hdf5_to_nc_type(&Datatype::FixedPoint {
124 size: 1,
125 signed: true,
126 byte_order: bo
127 })
128 .unwrap(),
129 NcType::Byte
130 );
131 assert_eq!(
132 hdf5_to_nc_type(&Datatype::FixedPoint {
133 size: 1,
134 signed: false,
135 byte_order: bo
136 })
137 .unwrap(),
138 NcType::UByte
139 );
140 assert_eq!(
141 hdf5_to_nc_type(&Datatype::FixedPoint {
142 size: 4,
143 signed: true,
144 byte_order: bo
145 })
146 .unwrap(),
147 NcType::Int
148 );
149 assert_eq!(
150 hdf5_to_nc_type(&Datatype::FixedPoint {
151 size: 8,
152 signed: false,
153 byte_order: bo
154 })
155 .unwrap(),
156 NcType::UInt64
157 );
158 }
159
160 #[test]
161 fn test_float_types() {
162 let bo = ByteOrder::LittleEndian;
163 assert_eq!(
164 hdf5_to_nc_type(&Datatype::FloatingPoint {
165 size: 4,
166 byte_order: bo
167 })
168 .unwrap(),
169 NcType::Float
170 );
171 assert_eq!(
172 hdf5_to_nc_type(&Datatype::FloatingPoint {
173 size: 8,
174 byte_order: bo
175 })
176 .unwrap(),
177 NcType::Double
178 );
179 }
180
181 #[test]
182 fn test_varlen_u8_maps_to_string() {
183 let bo = ByteOrder::LittleEndian;
184 assert_eq!(
185 hdf5_to_nc_type(&Datatype::VarLen {
186 base: Box::new(Datatype::FixedPoint {
187 size: 1,
188 signed: false,
189 byte_order: bo,
190 }),
191 })
192 .unwrap(),
193 NcType::String
194 );
195 }
196}