netcdf_reader/nc4/
attributes.rs1use hdf5_reader::group::Group;
14use hdf5_reader::messages::datatype::Datatype;
15
16use crate::error::Result;
17use crate::types::{NcAttrValue, NcAttribute};
18
19const INTERNAL_ATTRIBUTES: &[&str] = &[
21 "_NCProperties",
22 "_Netcdf4Dimid",
23 "_Netcdf4Coordinates",
24 "_nc3_strict",
25 "DIMENSION_LIST",
26 "REFERENCE_LIST",
27 "CLASS",
28 "NAME",
29];
30
31pub fn is_internal_attribute(name: &str) -> bool {
34 INTERNAL_ATTRIBUTES.contains(&name)
35}
36
37pub fn extract_group_attributes(group: &Group<'_>) -> Result<Vec<NcAttribute>> {
40 let hdf5_attrs = match group.attributes() {
41 Ok(a) => a,
42 Err(_) => return Ok(Vec::new()),
43 };
44
45 let mut nc_attrs = Vec::new();
46 for attr in &hdf5_attrs {
47 if is_internal_attribute(&attr.name) {
48 continue;
49 }
50 if let Some(nc_attr) = convert_attribute(attr) {
51 nc_attrs.push(nc_attr);
52 }
53 }
54 Ok(nc_attrs)
55}
56
57pub fn extract_variable_attributes(dataset: &hdf5_reader::Dataset<'_>) -> Result<Vec<NcAttribute>> {
60 let hdf5_attrs = dataset.attributes();
61 let mut nc_attrs = Vec::new();
62 for attr in &hdf5_attrs {
63 if is_internal_attribute(&attr.name) {
64 continue;
65 }
66 if let Some(nc_attr) = convert_attribute(attr) {
67 nc_attrs.push(nc_attr);
68 }
69 }
70 Ok(nc_attrs)
71}
72
73fn convert_attribute(attr: &hdf5_reader::Attribute) -> Option<NcAttribute> {
75 let value = convert_attribute_value(attr)?;
76 Some(NcAttribute {
77 name: attr.name.clone(),
78 value,
79 })
80}
81
82fn convert_attribute_value(attr: &hdf5_reader::Attribute) -> Option<NcAttrValue> {
84 match &attr.datatype {
85 Datatype::FixedPoint { size, signed, .. } => match (size, signed) {
86 (1, true) => attr.read_1d::<i8>().ok().map(NcAttrValue::Bytes),
87 (1, false) => attr.read_1d::<u8>().ok().map(NcAttrValue::UBytes),
88 (2, true) => attr.read_1d::<i16>().ok().map(NcAttrValue::Shorts),
89 (2, false) => attr.read_1d::<u16>().ok().map(NcAttrValue::UShorts),
90 (4, true) => attr.read_1d::<i32>().ok().map(NcAttrValue::Ints),
91 (4, false) => attr.read_1d::<u32>().ok().map(NcAttrValue::UInts),
92 (8, true) => attr.read_1d::<i64>().ok().map(NcAttrValue::Int64s),
93 (8, false) => attr.read_1d::<u64>().ok().map(NcAttrValue::UInt64s),
94 _ => None,
95 },
96 Datatype::FloatingPoint { size, .. } => match size {
97 4 => attr.read_1d::<f32>().ok().map(NcAttrValue::Floats),
98 8 => attr.read_1d::<f64>().ok().map(NcAttrValue::Doubles),
99 _ => None,
100 },
101 Datatype::String { .. } => {
102 if attr.num_elements() == 1 {
104 attr.read_string().ok().map(NcAttrValue::Chars)
105 } else {
106 attr.read_strings().ok().map(NcAttrValue::Strings)
107 }
108 }
109 Datatype::VarLen { base }
110 if attr.num_elements() == 1
111 && matches!(
112 base.as_ref(),
113 Datatype::FixedPoint {
114 size: 1,
115 signed: false,
116 ..
117 }
118 ) =>
119 {
120 attr.read_string().ok().map(NcAttrValue::Chars)
121 }
122 _ => None,
123 }
124}