conspire/io/netcdf/
mod.rs1#[cfg(test)]
2mod test;
3
4pub(super) mod base;
5pub(super) mod format;
6pub(super) mod from;
7pub(super) mod variable;
8
9pub use from::NetCdfError;
10
11use format::{Attribute, DimSpec, Parsed, VarSpec};
12use std::{
13 ffi::{CString, NulError},
14 fs::File,
15 sync::{Mutex, MutexGuard},
16};
17
18static NC_LOCK: Mutex<()> = Mutex::new(());
19
20pub(crate) fn nc_lock() -> MutexGuard<'static, ()> {
21 NC_LOCK.lock().unwrap_or_else(|error| error.into_inner())
22}
23
24pub(crate) fn reject_nul(name: &str) -> Result<(), NulError> {
25 CString::new(name).map(|_| ())
26}
27
28pub struct NetCDF {
35 state: State,
36}
37
38enum State {
39 Write(Writer),
40 Read(Reader),
41}
42
43struct Writer {
44 path: String,
45 dims: Vec<DimSpec>,
46 global_attributes: Vec<Attribute>,
47 variables: Vec<VarBuild>,
48 netcdf4: Option<usize>,
50 output: Option<Output>,
51}
52
53struct VarBuild {
54 name: String,
55 xtype: i32,
56 dim_names: Vec<String>,
57 attributes: Vec<Attribute>,
58}
59
60struct Output {
61 file: File,
62 variables: Vec<VarSpec>,
63 data: Vec<Vec<u8>>,
64}
65
66struct Reader {
67 bytes: Vec<u8>,
68 parsed: Parsed,
69}
70
71impl Drop for NetCDF {
72 fn drop(&mut self) {
73 self.close();
74 }
75}
76
77pub trait DefineVariable {
78 fn define_variable<T: NcType>(
79 &mut self,
80 name: &str,
81 ndims: usize,
82 dim_names: &[&str],
83 ) -> Result<(), NulError>;
84}
85
86pub trait PutVariable {
87 fn put_variable<T: NcType>(&mut self, name: &str, data: &[T]) -> Result<(), NulError>;
88}
89
90pub trait GetVariable {
91 fn get_variable<T: NcType>(&self, name: &str, len: usize) -> Result<Vec<T>, NulError>;
92 fn try_get_variable<T: NcType>(
93 &self,
94 name: &str,
95 len: usize,
96 ) -> Result<Option<Vec<T>>, NulError>;
97 fn get_variable_slice<T: NcType>(
101 &self,
102 name: &str,
103 start: &[usize],
104 count: &[usize],
105 ) -> Result<Vec<T>, NulError>;
106}
107
108pub unsafe trait NcType: Default + Copy {
113 const XTYPE: i32;
114 const SIZE: usize;
115 fn xdr_swap(src: &[u8], dst: &mut [u8]);
116}
117
118#[inline]
119fn swap_words<const N: usize>(src: &[u8], dst: &mut [u8], swap: impl Fn([u8; N]) -> [u8; N]) {
120 let (src, _) = src.as_chunks::<N>();
121 let (dst, _) = dst.as_chunks_mut::<N>();
122 for (s, d) in src.iter().zip(dst) {
123 *d = swap(*s);
124 }
125}
126
127unsafe impl NcType for i32 {
128 const XTYPE: i32 = format::NC_INT;
129 const SIZE: usize = 4;
130 #[inline]
131 fn xdr_swap(src: &[u8], dst: &mut [u8]) {
132 swap_words::<4>(src, dst, |w| u32::from_ne_bytes(w).to_be_bytes());
133 }
134}
135
136unsafe impl NcType for f32 {
137 const XTYPE: i32 = format::NC_FLOAT;
138 const SIZE: usize = 4;
139 #[inline]
140 fn xdr_swap(src: &[u8], dst: &mut [u8]) {
141 swap_words::<4>(src, dst, |w| u32::from_ne_bytes(w).to_be_bytes());
142 }
143}
144
145unsafe impl NcType for f64 {
146 const XTYPE: i32 = format::NC_DOUBLE;
147 const SIZE: usize = 8;
148 #[inline]
149 fn xdr_swap(src: &[u8], dst: &mut [u8]) {
150 swap_words::<8>(src, dst, |w| u64::from_ne_bytes(w).to_be_bytes());
151 }
152}