conspire/io/netcdf/variable/
mod.rs1use crate::io::netcdf::{
2 DefineVariable, GetVariable, NcType, NetCDF, PutVariable,
3 ffi::{
4 NC_DOUBLE, NC_FLOAT, NC_INT, nc_def_var, nc_get_var_double, nc_get_var_float,
5 nc_get_var_int, nc_inq_dimid, nc_inq_varid, nc_put_var_double, nc_put_var_float,
6 nc_put_var_int,
7 },
8 nc_lock,
9};
10use std::ffi::{CString, NulError, c_int};
11
12impl DefineVariable for NetCDF {
13 fn define_variable<T: NcType>(
14 &mut self,
15 name: &str,
16 ndims: usize,
17 dim_names: &[&str],
18 ) -> Result<(), NulError> {
19 let xtype = T::XTYPE;
20 assert_eq!(ndims, dim_names.len(), "ndims must equal dim_names.len()");
21
22 let name_c_str = CString::new(name)?;
23 let dim_name_cstrings: Result<Vec<CString>, NulError> =
24 dim_names.iter().map(|name| CString::new(*name)).collect();
25 let dim_name_cstrings = dim_name_cstrings?;
26
27 let _guard = nc_lock();
28 let mut dimids = Vec::with_capacity(dim_name_cstrings.len());
29 for dim_name_cstr in dim_name_cstrings.iter() {
30 let mut dimid: c_int = 0;
31 let status = unsafe { nc_inq_dimid(self.ncid, dim_name_cstr.as_ptr(), &mut dimid) };
32 assert_eq!(
33 status, 0,
34 "nc_inq_dimid failed for dim '{:?}' with status={status}",
35 dim_name_cstr
36 );
37 dimids.push(dimid);
38 }
39
40 let status = unsafe {
41 nc_def_var(
42 self.ncid,
43 name_c_str.as_ptr(),
44 xtype,
45 ndims as c_int,
46 dimids.as_ptr(),
47 &mut self.varid,
48 )
49 };
50 assert_eq!(
51 status, 0,
52 "nc_def_var failed for {name} with status={status}"
53 );
54 Ok(())
55 }
56}
57
58impl PutVariable for NetCDF {
59 fn put_variable<T: NcType>(&mut self, name: &str, data: &[T]) -> Result<(), NulError> {
60 let name_c_str = CString::new(name)?;
61 let mut varid: c_int = 0;
62 let _guard = nc_lock();
63 let status = unsafe { nc_inq_varid(self.ncid, name_c_str.as_ptr(), &mut varid) };
64 assert_eq!(
65 status, 0,
66 "nc_inq_varid failed for {name} with status={status}"
67 );
68
69 let status = T::put_var(self.ncid, varid, data.as_ptr());
70 assert_eq!(
71 status, 0,
72 "nc_put_var failed for var '{}' (varid {}) with status={status}",
73 name, varid
74 );
75 Ok(())
76 }
77}
78
79impl GetVariable for NetCDF {
80 fn get_variable<T: NcType>(&self, name: &str, len: usize) -> Result<Vec<T>, NulError> {
81 let name_c_str = CString::new(name)?;
82 let mut varid: c_int = 0;
83 let _guard = nc_lock();
84 let status = unsafe { nc_inq_varid(self.ncid, name_c_str.as_ptr(), &mut varid) };
85 assert_eq!(
86 status, 0,
87 "nc_inq_varid failed for {name} with status={status}"
88 );
89 let mut data: Vec<T> = vec![T::default(); len];
90 let status = T::get_var(self.ncid, varid, data.as_mut_ptr());
91 assert_eq!(
92 status, 0,
93 "nc_get_var failed for var '{name}' (varid {varid}) with status={status}"
94 );
95 Ok(data)
96 }
97 fn try_get_variable<T: NcType>(
98 &self,
99 name: &str,
100 len: usize,
101 ) -> Result<Option<Vec<T>>, NulError> {
102 let name_c_str = CString::new(name)?;
103 let mut varid: c_int = 0;
104 let _guard = nc_lock();
105 let status = unsafe { nc_inq_varid(self.ncid, name_c_str.as_ptr(), &mut varid) };
106 if status != 0 {
107 return Ok(None);
108 }
109 let mut data: Vec<T> = vec![T::default(); len];
110 let status = T::get_var(self.ncid, varid, data.as_mut_ptr());
111 assert_eq!(
112 status, 0,
113 "nc_get_var failed for var '{name}' (varid {varid}) with status={status}"
114 );
115 Ok(Some(data))
116 }
117}
118
119impl NcType for i32 {
120 const XTYPE: c_int = NC_INT;
121 fn put_var(ncid: c_int, varid: c_int, data: *const Self) -> c_int {
122 unsafe { nc_put_var_int(ncid, varid, data) }
123 }
124 fn get_var(ncid: c_int, varid: c_int, data: *mut Self) -> c_int {
125 unsafe { nc_get_var_int(ncid, varid, data) }
126 }
127}
128
129impl NcType for f32 {
130 const XTYPE: c_int = NC_FLOAT;
131 fn put_var(ncid: c_int, varid: c_int, data: *const Self) -> c_int {
132 unsafe { nc_put_var_float(ncid, varid, data) }
133 }
134 fn get_var(ncid: c_int, varid: c_int, data: *mut Self) -> c_int {
135 unsafe { nc_get_var_float(ncid, varid, data) }
136 }
137}
138
139impl NcType for f64 {
140 const XTYPE: c_int = NC_DOUBLE;
141 fn put_var(ncid: c_int, varid: c_int, data: *const Self) -> c_int {
142 unsafe { nc_put_var_double(ncid, varid, data) }
143 }
144 fn get_var(ncid: c_int, varid: c_int, data: *mut Self) -> c_int {
145 unsafe { nc_get_var_double(ncid, varid, data) }
146 }
147}