Skip to main content

conspire/io/netcdf/variable/
mod.rs

1use 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}