From 3577bfadd6e748c8ca30e90e4c3d52cb60a2b14c Mon Sep 17 00:00:00 2001 From: Magnus Ulimoen Date: Fri, 1 Mar 2024 11:21:43 +0100 Subject: [PATCH] Make common API for &str/DimensionIdentifier --- netcdf/src/dimension.rs | 172 ++++++++++++++++++++++++++++++++++++- netcdf/src/file.rs | 57 +++++++----- netcdf/src/group.rs | 28 +++--- netcdf/src/lib.rs | 4 +- netcdf/src/variable.rs | 95 ++++++++------------ netcdf/tests/attributes.rs | 2 +- netcdf/tests/file.rs | 2 +- netcdf/tests/group.rs | 10 +-- netcdf/tests/lib.rs | 163 ++++++++++++++++++----------------- netcdf/tests/types.rs | 20 ++--- 10 files changed, 358 insertions(+), 195 deletions(-) diff --git a/netcdf/src/dimension.rs b/netcdf/src/dimension.rs index a259661..637309a 100644 --- a/netcdf/src/dimension.rs +++ b/netcdf/src/dimension.rs @@ -7,6 +7,118 @@ use netcdf_sys::*; use super::error; +mod sealed { + pub trait Sealed {} +} + +/// Types which can be used to distinguish dimensions +/// in a netCDF file. This can be `&str` (the normal use case) +/// or a special identifier when using nested groups. +/// +/// This trait is not expected to be implemented elsewhere and is therefore sealed. +/// +/// # Examples +/// (helper function to show consumption of type) +/// ```rust +/// # use netcdf::AsNcDimensions; +/// fn take(d: impl AsNcDimensions) {} +/// ``` +/// Normally one uses the name of the dimension to specify the dimension +/// ```rust +/// # use netcdf::AsNcDimensions; +/// # fn take(d: impl AsNcDimensions) {} +/// take(()); // scalar +/// take("x"); // single dimension +/// take(["x", "y"]); // multiple dimensions +/// ``` +/// When working with dimensions across groups, it might be necessary +/// to use dimension identifiers to get the correct group dimension +/// ```rust,no_run +/// # fn main() -> Result<(), Box> { +/// # use netcdf::AsNcDimensions; +/// # fn take(d: impl AsNcDimensions) {} +/// let file = netcdf::open("test.nc")?; +/// let dim = file.dimension("x").expect("File does not contain dimension"); +/// let dimid = dim.identifier(); +/// +/// take(dimid); // from a dimension identifier +/// take([dimid, dimid]); // from multiple identifiers +/// # Ok(()) } +/// ``` +pub trait AsNcDimensions: sealed::Sealed { + /// Convert from a slice of [`&str`]/[`DimensionIdentifier`] to concrete dimensions + /// which are guaranteed to exist in this file + fn get_dimensions<'g>(&self, ncid: nc_type) -> error::Result>>; +} + +impl sealed::Sealed for &[&str] {} +impl AsNcDimensions for &[&str] { + fn get_dimensions<'g>(&self, ncid: nc_type) -> error::Result>> { + self.iter() + .map(|&name| match dimension_from_name(ncid, name) { + Ok(Some(x)) => Ok(x), + Ok(None) => Err(format!("Dimension {name} not found").into()), + Err(e) => Err(e), + }) + .collect() + } +} +impl sealed::Sealed for [&str; N] {} +impl AsNcDimensions for [&str; N] { + fn get_dimensions<'g>(&self, ncid: nc_type) -> error::Result>> { + self.as_slice().get_dimensions(ncid) + } +} +impl sealed::Sealed for &[&str; N] {} +impl AsNcDimensions for &[&str; N] { + fn get_dimensions<'g>(&self, ncid: nc_type) -> error::Result>> { + self.as_slice().get_dimensions(ncid) + } +} + +impl sealed::Sealed for &[DimensionIdentifier] {} +impl AsNcDimensions for &[DimensionIdentifier] { + fn get_dimensions<'g>(&self, ncid: nc_type) -> error::Result>> { + self.iter() + .map(|dimid| match dimension_from_identifier(ncid, *dimid) { + Ok(Some(x)) => Ok(x), + Ok(None) => Err("Dimension id does not exist".into()), + Err(e) => Err(e), + }) + .collect() + } +} +impl sealed::Sealed for [DimensionIdentifier; N] {} +impl AsNcDimensions for [DimensionIdentifier; N] { + fn get_dimensions<'g>(&self, ncid: nc_type) -> error::Result>> { + self.as_slice().get_dimensions(ncid) + } +} +impl sealed::Sealed for &[DimensionIdentifier; N] {} +impl AsNcDimensions for &[DimensionIdentifier; N] { + fn get_dimensions<'g>(&self, ncid: nc_type) -> error::Result>> { + self.as_slice().get_dimensions(ncid) + } +} +impl sealed::Sealed for () {} +impl AsNcDimensions for () { + fn get_dimensions<'g>(&self, _ncid: nc_type) -> error::Result>> { + Ok(Vec::new()) + } +} +impl sealed::Sealed for &str {} +impl AsNcDimensions for &str { + fn get_dimensions<'g>(&self, ncid: nc_type) -> error::Result>> { + ([*self]).get_dimensions(ncid) + } +} +impl sealed::Sealed for DimensionIdentifier {} +impl AsNcDimensions for DimensionIdentifier { + fn get_dimensions<'g>(&self, ncid: nc_type) -> error::Result>> { + ([*self]).get_dimensions(ncid) + } +} + /// Represents a netcdf dimension #[derive(Debug, Clone)] pub struct Dimension<'g> { @@ -25,9 +137,23 @@ pub struct DimensionIdentifier { pub(crate) dimid: nc_type, } +impl DimensionIdentifier { + // Internal netcdf detail, the top 16 bits gives the corresponding + // file handle. This to ensure dimensions are not added from another + // file which is unrelated to self + pub(crate) fn belongs_to(&self, ncid: nc_type) -> bool { + self.ncid >> 16 == ncid >> 16 + } +} + #[allow(clippy::len_without_is_empty)] impl<'g> Dimension<'g> { /// Get current length of this dimension + /// + /// ## Note + /// A dimension can be unlimited (growable) and changes size + /// if putting values to a variable which uses this + /// dimension pub fn len(&self) -> usize { if let Some(x) = self.len { x.get() @@ -66,7 +192,10 @@ impl<'g> Dimension<'g> { } /// Grabs the unique identifier for this dimension, which - /// can be used in `add_variable_from_identifiers` + /// can be used in [`add_variable`](crate::FileMut::add_variable). + /// + /// This is useful when working with nested groups and need + /// to distinguish between names at different levels. pub fn identifier(&self) -> DimensionIdentifier { self.id } @@ -272,6 +401,47 @@ pub(crate) fn dimension_from_name<'f>( })) } +pub(crate) fn dimension_from_identifier<'f>( + ncid: nc_type, + dimid: DimensionIdentifier, +) -> error::Result>> { + if !dimid.belongs_to(ncid) { + return Err(error::Error::WrongDataset); + } + let dimid = dimid.dimid; + + let mut dimlen = 0; + unsafe { + error::checked(super::with_lock(|| nc_inq_dimlen(ncid, dimid, &mut dimlen))).unwrap(); + } + if dimlen != 0 { + // Have to check if this dimension is unlimited + let mut nunlim = 0; + unsafe { + error::checked(super::with_lock(|| { + nc_inq_unlimdims(ncid, &mut nunlim, std::ptr::null_mut()) + }))?; + } + if nunlim != 0 { + let mut unlimdims = Vec::with_capacity(nunlim.try_into()?); + unsafe { + error::checked(super::with_lock(|| { + nc_inq_unlimdims(ncid, std::ptr::null_mut(), unlimdims.as_mut_ptr()) + }))?; + } + unsafe { unlimdims.set_len(nunlim.try_into()?) } + if unlimdims.contains(&dimid) { + dimlen = 0; + } + } + } + Ok(Some(Dimension { + len: core::num::NonZeroUsize::new(dimlen), + id: super::dimension::DimensionIdentifier { ncid, dimid }, + _group: PhantomData, + })) +} + pub(crate) fn add_dimension_at<'f>( ncid: nc_type, name: &str, diff --git a/netcdf/src/file.rs b/netcdf/src/file.rs index 17a8029..4e9b3f3 100644 --- a/netcdf/src/file.rs +++ b/netcdf/src/file.rs @@ -7,7 +7,7 @@ use std::path; use netcdf_sys::*; use super::attribute::{Attribute, AttributeValue}; -use super::dimension::{self, Dimension}; +use super::dimension::{AsNcDimensions, Dimension}; use super::error; use super::group::{Group, GroupMut}; use super::variable::{NcPutGet, Variable, VariableMut}; @@ -338,20 +338,50 @@ impl FileMut { )) } - /// Create a Variable into the dataset, with no data written into it + /// Create a variable in the dataset, with no data written into it /// - /// Dimensions are identified using the name of the dimension, and will recurse upwards - /// if not found in the current group. - pub fn add_variable<'f, T>( + /// # Examples + /// ## Adding variables with different types + /// ```rust,no_run + /// # fn main() -> Result<(), Box> { + /// let mut file = netcdf::create("file.nc")?; + /// file.add_dimension("x", 10)?; + /// file.add_dimension("y", 11)?; + /// file.add_variable::("var_u8", &["y", "x"])?; + /// file.add_variable::("var_i8", &["y", "x"])?; + /// file.add_variable::("var_u64", &["y", "x"])?; + /// file.add_variable::("var_f64", &["y", "x"])?; + /// # Ok(())} + /// ``` + /// ## Adding a scalar variable + /// ```rust,no_run + /// # fn main() -> Result<(), Box> { + /// let mut file = netcdf::create("scalar.nc")?; + /// file.add_variable::("var2", ())?; + /// # Ok(())} + /// ``` + /// ## Using dimension identifiers in place of names + /// ```rust,no_run + /// # fn main() -> Result<(), Box> { + /// let mut file = netcdf::create("dimids.nc")?; + /// let dimx = file.dimension("x").unwrap().identifier(); + /// let dimy = file.dimension("y").unwrap().identifier(); + /// file.add_variable::("var2", &[dimy, dimx])?; + /// # Ok(())} + ///``` + /// + /// See [`AsNcDimensions`] for how to specify dimensions. + pub fn add_variable<'f, T, D>( &'f mut self, name: &str, - dims: &[&str], + dims: D, ) -> error::Result> where T: NcPutGet, + D: AsNcDimensions, { let (ncid, name) = super::group::get_parent_ncid_and_stem(self.ncid(), name)?; - VariableMut::add_from_str(ncid, T::NCTYPE, name, dims) + VariableMut::add_from_dimids(ncid, T::NCTYPE, name, dims.get_dimensions(ncid)?) } /// Create a variable with the specified type @@ -410,19 +440,6 @@ impl FileMut { let (ncid, name) = super::group::get_parent_ncid_and_stem(self.ncid(), name)?; VariableMut::add_from_str(ncid, NC_STRING, name, dims) } - /// Adds a variable from a set of unique identifiers, recursing upwards - /// from the current group if necessary. - pub fn add_variable_from_identifiers<'f, T>( - &'f mut self, - name: &str, - dims: &[dimension::DimensionIdentifier], - ) -> error::Result> - where - T: NcPutGet, - { - let (ncid, name) = super::group::get_parent_ncid_and_stem(self.ncid(), name)?; - super::variable::add_variable_from_identifiers(ncid, name, dims, T::NCTYPE) - } } #[cfg(feature = "has-mmap")] diff --git a/netcdf/src/group.rs b/netcdf/src/group.rs index a821cb6..324b203 100644 --- a/netcdf/src/group.rs +++ b/netcdf/src/group.rs @@ -6,7 +6,7 @@ use std::marker::PhantomData; use netcdf_sys::*; use super::attribute::{Attribute, AttributeValue}; -use super::dimension::Dimension; +use super::dimension::{AsNcDimensions, Dimension}; use super::error; use super::variable::{NcPutGet, Variable, VariableMut}; @@ -244,18 +244,23 @@ impl<'f> GroupMut<'f> { /// Create a Variable into the dataset, with no data written into it /// /// Dimensions are identified using the name of the dimension, and will recurse upwards - /// if not found in the current group. - pub fn add_variable<'g, T>( + /// if not found in the current group. If the name is shadowed one can get an + /// [`DimensionIdentifier`](crate::DimensionIdentifier) to ensure the right dimension + /// is used + /// + /// See [`AsNcDimensions`] for how to specify dimensions. + pub fn add_variable<'g, T, D>( &'g mut self, name: &str, - dims: &[&str], + dims: D, ) -> error::Result> where T: NcPutGet, 'f: 'g, + D: AsNcDimensions, { let (ncid, name) = super::group::get_parent_ncid_and_stem(self.id(), name)?; - VariableMut::add_from_str(ncid, T::NCTYPE, name, dims) + VariableMut::add_from_dimids(ncid, T::NCTYPE, name, dims.get_dimensions(ncid)?) } /// Adds a variable with a basic type of string pub fn add_string_variable<'g>( @@ -266,19 +271,6 @@ impl<'f> GroupMut<'f> { let (ncid, name) = super::group::get_parent_ncid_and_stem(self.id(), name)?; VariableMut::add_from_str(ncid, NC_STRING, name, dims) } - /// Adds a variable from a set of unique identifiers, recursing upwards - /// from the current group if necessary. - pub fn add_variable_from_identifiers<'g, T>( - &'g mut self, - name: &str, - dims: &[super::dimension::DimensionIdentifier], - ) -> error::Result> - where - T: NcPutGet, - { - let (ncid, name) = super::group::get_parent_ncid_and_stem(self.id(), name)?; - super::variable::add_variable_from_identifiers(ncid, name, dims, T::NCTYPE) - } /// Create a variable with the specified type pub fn add_variable_with_type( diff --git a/netcdf/src/lib.rs b/netcdf/src/lib.rs index ae9df16..134bf1a 100644 --- a/netcdf/src/lib.rs +++ b/netcdf/src/lib.rs @@ -71,7 +71,7 @@ //! file.add_unlimited_dimension("time")?; //! //! // A variable can now be declared, and must be created from the dimension names. -//! let mut var = file.add_variable::( +//! let mut var = file.add_variable::( //! "crab_coolness_level", //! &["time", "ncrabs"], //! )?; @@ -114,7 +114,7 @@ pub mod types; pub(crate) mod variable; pub use attribute::{Attribute, AttributeValue}; -pub use dimension::{Dimension, DimensionIdentifier}; +pub use dimension::{AsNcDimensions, Dimension, DimensionIdentifier}; pub use error::{Error, Result}; pub use extent::{Extent, Extents}; #[cfg(feature = "has-mmap")] diff --git a/netcdf/src/variable.rs b/netcdf/src/variable.rs index fc8af9d..a8da66e 100644 --- a/netcdf/src/variable.rs +++ b/netcdf/src/variable.rs @@ -1434,6 +1434,42 @@ impl<'g> VariableMut<'g> { } impl<'g> VariableMut<'g> { + pub(crate) fn add_from_dimids<'d>( + ncid: nc_type, + xtype: nc_type, + name: &str, + dimensions: Vec>, + ) -> error::Result + where + 'd: 'g, + { + let cname = super::utils::short_name_to_bytes(name)?; + let mut varid = 0; + unsafe { + let dims = dimensions.iter().map(|x| x.id.dimid).collect::>(); + let dimlen = dims.len().try_into()?; + error::checked(super::with_lock(|| { + nc_def_var( + ncid, + cname.as_ptr().cast(), + xtype, + dimlen, + dims.as_ptr(), + &mut varid, + ) + }))?; + } + Ok(VariableMut( + Variable { + ncid, + varid, + vartype: xtype, + dimensions, + _group: PhantomData, + }, + PhantomData, + )) + } pub(crate) fn add_from_str( ncid: nc_type, xtype: nc_type, @@ -1520,62 +1556,3 @@ pub(crate) fn variables_at_ncid<'g>( }) })) } - -pub(crate) fn add_variable_from_identifiers<'g>( - ncid: nc_type, - name: &str, - dims: &[super::dimension::DimensionIdentifier], - xtype: nc_type, -) -> error::Result> { - let cname = super::utils::short_name_to_bytes(name)?; - - let dimensions = dims - .iter() - .map(move |&id| { - // Internal netcdf detail, the top 16 bits gives the corresponding - // file handle. This to ensure dimensions are not added from another - // file which is unrelated to self - if id.ncid >> 16 != ncid >> 16 { - return Err(error::Error::WrongDataset); - } - let mut dimlen = 0; - unsafe { - error::checked(super::with_lock(|| { - nc_inq_dimlen(id.ncid, id.dimid, &mut dimlen) - }))?; - } - Ok(Dimension { - len: core::num::NonZeroUsize::new(dimlen), - id, - _group: PhantomData, - }) - }) - .collect::>>()?; - let dims = dims.iter().map(|x| x.dimid).collect::>(); - - let mut varid = 0; - unsafe { - let dimlen = dims.len().try_into()?; - error::checked(super::with_lock(|| { - nc_def_var( - ncid, - cname.as_ptr().cast(), - xtype, - dimlen, - dims.as_ptr(), - &mut varid, - ) - }))?; - } - - Ok(VariableMut( - Variable { - ncid, - dimensions, - varid, - vartype: xtype, - _group: PhantomData, - }, - PhantomData, - )) -} diff --git a/netcdf/tests/attributes.rs b/netcdf/tests/attributes.rs index d7f9b0e..199b40a 100644 --- a/netcdf/tests/attributes.rs +++ b/netcdf/tests/attributes.rs @@ -23,7 +23,7 @@ fn attributes_read() { let mut file = netcdf::create(path).expect("Could not create file"); let var = &mut file - .add_variable::("var", &[]) + .add_variable::("var", ()) .expect("Could not add variable"); var.put_attribute("att", "some attribute") .expect("Could not add attribute"); diff --git a/netcdf/tests/file.rs b/netcdf/tests/file.rs index 78fa4cb..73f34b8 100644 --- a/netcdf/tests/file.rs +++ b/netcdf/tests/file.rs @@ -52,7 +52,7 @@ fn fetch_from_path() { let mut group = file.add_group("grp").unwrap(); let mut subgroup = group.add_group("subgrp").unwrap(); subgroup.add_dimension("dim", 1).unwrap(); - subgroup.add_variable::("var", &["dim"]).unwrap(); + subgroup.add_variable::("var", &["dim"]).unwrap(); subgroup.add_attribute("attr", "test").unwrap(); } let file = netcdf::open(path).unwrap(); diff --git a/netcdf/tests/group.rs b/netcdf/tests/group.rs index ef45637..b90fa51 100644 --- a/netcdf/tests/group.rs +++ b/netcdf/tests/group.rs @@ -44,10 +44,10 @@ fn find_variable() { let mut file = netcdf::create(path).unwrap(); let mut group = file.add_group("group").unwrap(); - group.add_variable::("v", &[]).unwrap(); - group.add_variable::("w", &[]).unwrap(); + group.add_variable::("v", ()).unwrap(); + group.add_variable::("w", ()).unwrap(); group.add_dimension("d", 3).unwrap(); - group.add_variable::("z", &["d"]).unwrap(); + group.add_variable::("z", &["d"]).unwrap(); assert_eq!(group.variables_mut().count(), 3); assert_eq!(group.variables().count(), 3); @@ -83,8 +83,8 @@ fn add_and_get_from_path() { file.add_group("a/b").unwrap(); file.add_dimension("a/b/dim", 1).unwrap(); assert!(file.add_dimension("a/c/dim", 1).is_err()); - file.add_variable::("a/b/var", &["dim"]).unwrap(); - assert!(file.add_variable::("a/c/var", &["dim"]).is_err()); + file.add_variable::("a/b/var", &["dim"]).unwrap(); + assert!(file.add_variable::("a/c/var", &["dim"]).is_err()); file.add_attribute("a/b/attr", "test").unwrap(); assert!(file.add_attribute("a/c/test", "test").is_err()); } diff --git a/netcdf/tests/lib.rs b/netcdf/tests/lib.rs index 8913db7..ba8d547 100644 --- a/netcdf/tests/lib.rs +++ b/netcdf/tests/lib.rs @@ -134,10 +134,10 @@ fn variable_not_replacing() { let p = d.path().join("variable_not_replacing.nc"); let mut f = netcdf::create(p).unwrap(); - f.add_variable::("a", &[]).unwrap(); - f.add_variable::("b", &[]).unwrap(); - f.add_variable::("a", &[]).unwrap_err(); - f.add_variable_from_identifiers::("b", &[]).unwrap_err(); + f.add_variable::("a", ()).unwrap(); + f.add_variable::("b", ()).unwrap(); + f.add_variable::("a", ()).unwrap_err(); + f.add_variable::("b", ()).unwrap_err(); } #[test] @@ -179,10 +179,10 @@ fn netcdf_error() { let path = d.path().join("netcdf_error.nc"); let mut file = netcdf::create(path).expect("Could not create file"); - file.add_variable::("var", &["v"]).unwrap_err(); + file.add_variable::("var", &["v"]).unwrap_err(); file.add_dimension("v", 3).expect("Could not add dimension"); - file.add_variable::("var", &["v"]).unwrap(); - file.add_variable::("var", &["v"]).unwrap_err(); + file.add_variable::("var", &["v"]).unwrap(); + file.add_variable::("var", &["v"]).unwrap_err(); file.add_dimension("v", 2).unwrap_err(); file.add_unlimited_dimension("v").unwrap_err(); @@ -258,13 +258,13 @@ fn create_group_dimensions() { let g = &mut f.add_group("gp1").unwrap(); g.add_dimension("x", 100).unwrap(); - g.add_variable::("y", &["x"]).unwrap(); + g.add_variable::("y", &["x"]).unwrap(); let gg = &mut g.add_group("gp2").unwrap(); - gg.add_variable::("y", &["x"]).unwrap(); + gg.add_variable::("y", &["x"]).unwrap(); gg.add_dimension("x", 30).unwrap(); - gg.add_variable::("z", &["x"]).unwrap(); + gg.add_variable::("z", &["x"]).unwrap(); assert_eq!( f.group("gp1") @@ -342,7 +342,7 @@ fn def_dims_vars_attrs() { let var_name = "varstuff_int"; let data: Vec = vec![42; 10 * 20]; let var = &mut file - .add_variable::(var_name, &[dim1_name, dim2_name]) + .add_variable::(var_name, &[dim1_name, dim2_name]) .unwrap(); var.put_values(data.as_slice(), ..).unwrap(); assert_eq!(var.dimensions()[0].len(), 10); @@ -350,7 +350,7 @@ fn def_dims_vars_attrs() { let var_name = "varstuff_float"; let data: Vec = vec![42.2; 10]; - let mut var = file.add_variable::(var_name, &[dim1_name]).unwrap(); + let mut var = file.add_variable::(var_name, &[dim1_name]).unwrap(); var.put_values(data.as_slice(), ..).unwrap(); assert_eq!(var.dimensions()[0].len(), 10); @@ -456,60 +456,60 @@ fn all_var_types() { // byte let data = vec![42i8; 10]; let var_name = "var_byte"; - let mut var = root.add_variable::(var_name, &[dim_name]).unwrap(); + let mut var = root.add_variable::(var_name, &[dim_name]).unwrap(); var.put_values(&data, ..).unwrap(); let data = vec![42u8; 10]; let var_name = "var_char"; - let mut var = root.add_variable::(var_name, &[dim_name]).unwrap(); + let mut var = root.add_variable::(var_name, &[dim_name]).unwrap(); var.put_values(&data, ..).unwrap(); // short let data = vec![42i16; 10]; let var_name = "var_short"; - let mut var = root.add_variable::(var_name, &[dim_name]).unwrap(); + let mut var = root.add_variable::(var_name, &[dim_name]).unwrap(); var.put_values(&data, ..).unwrap(); // ushort let data = vec![42u16; 10]; let var_name = "var_ushort"; - let mut var = root.add_variable::(var_name, &[dim_name]).unwrap(); + let mut var = root.add_variable::(var_name, &[dim_name]).unwrap(); var.put_values(&data, ..).unwrap(); // int let data = vec![42i32; 10]; let var_name = "var_int"; - let mut var = root.add_variable::(var_name, &[dim_name]).unwrap(); + let mut var = root.add_variable::(var_name, &[dim_name]).unwrap(); var.put_values(&data, ..).unwrap(); // uint let data = vec![42u32; 10]; let var_name = "var_uint"; - let mut var = root.add_variable::(var_name, &[dim_name]).unwrap(); + let mut var = root.add_variable::(var_name, &[dim_name]).unwrap(); var.put_values(&data, ..).unwrap(); // int64 let data = vec![42i64; 10]; let var_name = "var_int64"; - let mut var = root.add_variable::(var_name, &[dim_name]).unwrap(); + let mut var = root.add_variable::(var_name, &[dim_name]).unwrap(); var.put_values(&data, ..).unwrap(); // uint64 let data = vec![42u64; 10]; let var_name = "var_uint64"; - let mut var = root.add_variable::(var_name, &[dim_name]).unwrap(); + let mut var = root.add_variable::(var_name, &[dim_name]).unwrap(); var.put_values(&data, ..).unwrap(); // float let data = vec![42.2f32; 10]; let var_name = "var_float"; - let mut var = root.add_variable::(var_name, &[dim_name]).unwrap(); + let mut var = root.add_variable::(var_name, &[dim_name]).unwrap(); var.put_values(&data, ..).unwrap(); // double let data = vec![42.2f64; 10]; let var_name = "var_double"; - let mut var = root.add_variable::(var_name, &[dim_name]).unwrap(); + let mut var = root.add_variable::(var_name, &[dim_name]).unwrap(); var.put_values(&data, ..).unwrap(); } @@ -625,7 +625,7 @@ fn append() { let mut file_w = netcdf::create(&f).unwrap(); file_w.add_dimension(dim_name, 3).unwrap(); let var = &mut file_w - .add_variable::("some_variable", &[dim_name]) + .add_variable::("some_variable", &[dim_name]) .unwrap(); var.put_values::(&[1, 2, 3], ..).unwrap(); // close it (done when `file_w` goes out of scope) @@ -635,7 +635,7 @@ fn append() { // and create a variable called "some_other_variable" let mut file_a = netcdf::append(&f).unwrap(); let var = &mut file_a - .add_variable::("some_other_variable", &[dim_name]) + .add_variable::("some_other_variable", &[dim_name]) .unwrap(); var.put_values::(&[4, 5, 6], ..).unwrap(); // close it (done when `file_a` goes out of scope) @@ -659,7 +659,9 @@ fn put_single_value() { // and create a variable called "some_variable" in it let mut file_w = netcdf::create(&f).unwrap(); file_w.add_dimension(dim_name, 3).unwrap(); - let var = &mut file_w.add_variable::(var_name, &[dim_name]).unwrap(); + let var = &mut file_w + .add_variable::(var_name, &[dim_name]) + .unwrap(); var.put_values(&[1., 2., 3.], ..).unwrap(); } let indices: [usize; 1] = [0]; @@ -689,7 +691,9 @@ fn put_values() { // and create a variable called "some_variable" in it let mut file_w = netcdf::create(&f).unwrap(); file_w.add_dimension(dim_name, 3).unwrap(); - let var = &mut file_w.add_variable::(var_name, &[dim_name]).unwrap(); + let var = &mut file_w + .add_variable::(var_name, &[dim_name]) + .unwrap(); var.put_values(&[1i32, 2, 3], ..).unwrap(); // close it (done when `file_w` goes out of scope) } @@ -724,7 +728,9 @@ fn set_fill_value() { let mut file_w = netcdf::create(f).unwrap(); file_w.add_dimension(dim_name, 3).unwrap(); - let var = &mut file_w.add_variable::(var_name, &[dim_name]).unwrap(); + let var = &mut file_w + .add_variable::(var_name, &[dim_name]) + .unwrap(); var.set_fill_value(fill_value).unwrap(); var.put_values(&[2, 3], &[1..]).unwrap(); @@ -758,7 +764,7 @@ fn more_fill_values() { let mut file = netcdf::create(path).expect("Could not open file"); file.add_dimension("x", 2).unwrap(); - let var = &mut file.add_variable::("v0", &["x"]).unwrap(); + let var = &mut file.add_variable::("v0", &["x"]).unwrap(); var.set_fill_value(1_i32).unwrap(); var.put_value(6, [1]).unwrap(); @@ -767,7 +773,7 @@ fn more_fill_values() { assert_eq!(var.get_value::([0]).unwrap(), 1_i32); assert_eq!(var.get_value::([1]).unwrap(), 6_i32); - let var = &mut file.add_variable::("v1", &["x"]).unwrap(); + let var = &mut file.add_variable::("v1", &["x"]).unwrap(); unsafe { var.set_nofill().unwrap(); } @@ -778,7 +784,7 @@ fn more_fill_values() { assert_eq!(var.get_value::([1]).unwrap(), 6_i32); assert!(var.attribute("_FillValue").is_none()); - let var = &mut file.add_variable::("v2", &["x"]).unwrap(); + let var = &mut file.add_variable::("v2", &["x"]).unwrap(); var.set_fill_value(2_i32).unwrap(); assert_eq!( var.attribute("_FillValue").unwrap().value().unwrap(), @@ -842,7 +848,7 @@ fn use_compression_chunking() { file.add_dimension("x", 10).unwrap(); - let var = &mut file.add_variable::("compressed", &["x"]).unwrap(); + let var = &mut file.add_variable::("compressed", &["x"]).unwrap(); var.set_compression(5, false).unwrap(); var.set_chunking(&[5]).unwrap(); @@ -850,21 +856,21 @@ fn use_compression_chunking() { var.put_values(&v, ..).unwrap(); let var = &mut file - .add_variable::("compressed2", &["x", "x"]) + .add_variable::("compressed2", &["x", "x"]) .unwrap(); var.set_compression(9, true).unwrap(); var.set_chunking(&[5, 5]).unwrap(); var.put_values(&[1i32, 2, 3, 4, 5, 6, 7, 8, 9, 10], (..10, ..1)) .unwrap(); - let var = &mut file.add_variable::("chunked3", &["x"]).unwrap(); + let var = &mut file.add_variable::("chunked3", &["x"]).unwrap(); assert!(matches!( var.set_chunking(&[2, 2]).unwrap_err(), netcdf::Error::SliceLen )); file.add_dimension("y", 0).unwrap(); - let var = &mut file.add_variable::("chunked4", &["y", "x"]).unwrap(); + let var = &mut file.add_variable::("chunked4", &["y", "x"]).unwrap(); var.set_chunking(&[100, 2]).unwrap(); } @@ -879,13 +885,13 @@ fn set_compression_all_variables_in_a_group() { .expect("Could not create dimension"); file.add_dimension("y", 15) .expect("Could not create dimension"); - file.add_variable::("var0", &["x", "y"]) + file.add_variable::("var0", &["x", "y"]) .expect("Could not create variable"); - file.add_variable::("var1", &["x", "y"]) + file.add_variable::("var1", &["x", "y"]) .expect("Could not create variable"); - file.add_variable::("var2", &["x", "y"]) + file.add_variable::("var2", &["x", "y"]) .expect("Could not create variable"); - file.add_variable::("var3", &["x", "y"]) + file.add_variable::("var3", &["x", "y"]) .expect("Could not create variable"); for mut var in file.variables_mut() { @@ -939,9 +945,9 @@ fn add_conflicting_variables() { file.add_dimension("x", 10).unwrap(); file.add_dimension("y", 20).unwrap(); - file.add_variable::("x", &["x"]).unwrap(); + file.add_variable::("x", &["x"]).unwrap(); - let e = file.add_variable::("x", &["y"]).unwrap_err(); + let e = file.add_variable::("x", &["y"]).unwrap_err(); assert!(match e { netcdf::Error::AlreadyExists => { true @@ -961,7 +967,7 @@ fn unlimited_dimension_single_putting() { file.add_unlimited_dimension("x").unwrap(); file.add_unlimited_dimension("y").unwrap(); - let var = &mut file.add_variable::("var", &["x", "y"]).unwrap(); + let var = &mut file.add_variable::("var", &["x", "y"]).unwrap(); var.set_fill_value(0u8).unwrap(); var.put_value(1, (0, 0)).unwrap(); @@ -1005,7 +1011,9 @@ fn unlimited_dimension_multi_putting() { file.add_unlimited_dimension("x3").unwrap(); file.add_unlimited_dimension("x4").unwrap(); - let var = &mut file.add_variable::("one_unlim", &["x", "z"]).unwrap(); + let var = &mut file + .add_variable::("one_unlim", &["x", "z"]) + .unwrap(); var.put_values(&[0u8, 1, 2, 3], ..).unwrap_err(); var.put_values(&[0u8, 1, 2, 3], (..2, ..2)).unwrap(); check_equal(var, &[0u8, 1, 2, 3]); @@ -1014,7 +1022,7 @@ fn unlimited_dimension_multi_putting() { check_equal(var, &[0u8, 1, 2, 3, 4, 5, 6, 7]); let var = &mut file - .add_variable::("unlim_first", &["z", "x2"]) + .add_variable::("unlim_first", &["z", "x2"]) .unwrap(); var.put_values(&[0u8, 1, 2, 3], (.., ..2)).unwrap(); check_equal(var, &[0u8, 1, 2, 3]); @@ -1022,7 +1030,9 @@ fn unlimited_dimension_multi_putting() { .unwrap(); check_equal(var, &[0u8, 1, 2, 3, 4, 5, 6, 7]); - let var = &mut file.add_variable::("two_unlim", &["x3", "x4"]).unwrap(); + let var = &mut file + .add_variable::("two_unlim", &["x3", "x4"]) + .unwrap(); var.set_fill_value(0u8).unwrap(); var.put_values(&[0u8, 1, 2, 3], (.., ..)).unwrap_err(); var.put_values(&[0u8, 1, 2, 3], [..1, ..4]).unwrap(); @@ -1046,10 +1056,10 @@ fn length_of_variable() { file.add_dimension("y", 6).unwrap(); file.add_unlimited_dimension("z").unwrap(); - let var = &mut file.add_variable::("x", &["x", "y"]).unwrap(); + let var = &mut file.add_variable::("x", &["x", "y"]).unwrap(); assert_eq!(var.len(), 4 * 6); - let var = &mut file.add_variable::("z", &["x", "z"]).unwrap(); + let var = &mut file.add_variable::("z", &["x", "z"]).unwrap(); var.put_value(1u8, [2, 8]).unwrap(); assert_eq!(var.len(), 4 * 9); } @@ -1060,7 +1070,7 @@ fn single_length_variable() { let path = d.path().join("single_length_variable.nc"); let mut file = netcdf::create(&path).unwrap(); - let var = &mut file.add_variable::("x", &[]).unwrap(); + let var = &mut file.add_variable::("x", ()).unwrap(); var.put_value(3u8, ..).unwrap(); assert_eq!(var.get_value::(..).unwrap(), 3_u8); @@ -1098,10 +1108,10 @@ fn put_then_def() { let path = d.path().join("put_then_def.nc"); let mut file = netcdf::create(path).unwrap(); - let var = &mut file.add_variable::("x", &[]).unwrap(); + let var = &mut file.add_variable::("x", ()).unwrap(); var.put_value(3i8, ..).unwrap(); - let var2 = &mut file.add_variable::("y", &[]).unwrap(); + let var2 = &mut file.add_variable::("y", ()).unwrap(); var2.put_value(4i8, ..).unwrap(); } @@ -1126,7 +1136,7 @@ fn string_variables() { // Some weird interaction between unlimited dimensions, put_str, // and the name of this variable leads to crash. This // can be observed by changing this \ / to "x" - let var = &mut file.add_variable::("y", &[]).unwrap(); + let var = &mut file.add_variable::("y", &[]).unwrap(); var.put_value(42i32, ()).unwrap(); } let file = netcdf::open(path).unwrap(); @@ -1164,8 +1174,8 @@ fn unlimited_in_parents() { let mut file = netcdf::append(&path).unwrap(); let g = &mut file.group_mut("g").unwrap().unwrap(); - g.add_variable::("w", &["z1"]).unwrap(); - g.add_variable::("v", &["x"]).unwrap(); + g.add_variable::("w", &["z1"]).unwrap(); + g.add_variable::("v", &["x"]).unwrap(); } #[test] @@ -1189,21 +1199,15 @@ fn dimension_identifiers() { }; // Create variables - file.add_variable_from_identifiers::("v_self_id", &[vrootid]) - .unwrap(); + file.add_variable::("v_self_id", &[vrootid]).unwrap(); let mut g = file.group_mut("g").unwrap().unwrap(); - g.add_variable_from_identifiers::("v_root_id", &[vrootid]) - .unwrap(); - g.add_variable_from_identifiers::("v_self_id", &[vgid]) - .unwrap(); + g.add_variable::("v_root_id", &[vrootid]).unwrap(); + g.add_variable::("v_self_id", &[vgid]).unwrap(); let gg = &mut g.group_mut("g").unwrap(); - gg.add_variable_from_identifiers::("v_root_id", &[vrootid]) - .unwrap(); - gg.add_variable_from_identifiers::("v_up_id", &[vgid]) - .unwrap(); - gg.add_variable_from_identifiers::("v_self_id", &[vggid]) - .unwrap(); + gg.add_variable::("v_root_id", &[vrootid]).unwrap(); + gg.add_variable::("v_up_id", &[vgid]).unwrap(); + gg.add_variable::("v_self_id", &[vggid]).unwrap(); } let file = &netcdf::open(path).unwrap(); @@ -1276,7 +1280,7 @@ fn set_get_endian() { let mut file_w = netcdf::create(&f).unwrap(); file_w.add_dimension(dim_name, 3).unwrap(); let var = &mut file_w - .add_variable::("some_variable", &[dim_name]) + .add_variable::("some_variable", &[dim_name]) .unwrap(); var.set_endianness(*i).unwrap(); assert_eq!(var.endianness().unwrap(), *i); @@ -1304,7 +1308,9 @@ mod strided { file.add_dimension("z", 3).unwrap(); file.add_dimension("y", 5).unwrap(); file.add_dimension("x", 9).unwrap(); - let mut var = file.add_variable::("data", &["z", "y", "x"]).unwrap(); + let mut var = file + .add_variable::("data", &["z", "y", "x"]) + .unwrap(); let buffer = (0..3 * 5 * 9).collect::>(); var.put_values(&buffer, ..).unwrap(); } @@ -1427,7 +1433,7 @@ mod strided { file.add_dimension("d0", 7).unwrap(); file.add_dimension("d1", 9).unwrap(); - let mut var = file.add_variable::("var", &["d0", "d1"]).unwrap(); + let mut var = file.add_variable::("var", &["d0", "d1"]).unwrap(); let values = (0..7 * 9).collect::>(); let zeros = [0; 7 * 9]; @@ -1506,7 +1512,7 @@ fn dimension_identifiers_from_different_ncids() { let d1 = g1.add_dimension("d", 11).unwrap(); match file0 - .add_variable_from_identifiers::("var", &[d1.identifier()]) + .add_variable::("var", &[d1.identifier()]) .unwrap_err() { netcdf::Error::WrongDataset => (), @@ -1515,16 +1521,13 @@ fn dimension_identifiers_from_different_ncids() { let d0 = file0.add_dimension("f", 20).unwrap(); let id = d0.identifier(); - file0 - .add_variable_from_identifiers::("var2", &[id]) - .unwrap(); + file0.add_variable::("var2", &[id]).unwrap(); let mut g0 = file0.add_group("g").unwrap(); let dg = g0.add_dimension("h", 17).unwrap(); let idg = dg.identifier(); - g0.add_variable_from_identifiers::("var3", &[id, idg]) - .unwrap(); + g0.add_variable::("var3", &[id, idg]).unwrap(); } #[test] @@ -1550,7 +1553,7 @@ fn open_to_find_unlim_dim() { let mut file = netcdf::create(&path).unwrap(); file.add_unlimited_dimension("a").unwrap(); - let mut var = file.add_variable::("b", &["a"]).unwrap(); + let mut var = file.add_variable::("b", &["a"]).unwrap(); var.put_values(&[0, 1, 2, 3, 4, 5], ..).unwrap(); } @@ -1600,7 +1603,7 @@ fn drop_dim_on_simple_indices() { f.add_dimension("d4", 13).unwrap(); let var = f - .add_variable::("v", &["d1", "d2", "d3", "d4"]) + .add_variable::("v", &["d1", "d2", "d3", "d4"]) .unwrap(); let values = var.get::(..).unwrap(); @@ -1639,7 +1642,7 @@ fn ndarray_put() { let values = ndarray::Array::::zeros((10, 11, 12, 13)); let mut var = f - .add_variable::("var", &["d1", "d2", "d3", "d4"]) + .add_variable::("var", &["d1", "d2", "d3", "d4"]) .unwrap(); macro_rules! put_values { @@ -1672,7 +1675,9 @@ fn ndarray_put() { put_values!(var, (.., .., .., 1), values, s![.., .., .., ..], Failure); std::mem::drop(var); - let mut var = f.add_variable::("grow", &["grow", "d2", "d3"]).unwrap(); + let mut var = f + .add_variable::("grow", &["grow", "d2", "d3"]) + .unwrap(); // let values = ndarray::Array::::zeros((10, 11, 12, 13)); put_values!(var, .., values, s![.., .., .., ..], Failure); @@ -1715,7 +1720,9 @@ fn ndarray_get_into() { (100 * k + 10 * j + i).try_into().unwrap() }); - let mut var = f.add_variable::("var", &["d1", "d2", "d3"]).unwrap(); + let mut var = f + .add_variable::("var", &["d1", "d2", "d3"]) + .unwrap(); var.put(.., values.view()).unwrap(); diff --git a/netcdf/tests/types.rs b/netcdf/tests/types.rs index efe13a1..2212358 100644 --- a/netcdf/tests/types.rs +++ b/netcdf/tests/types.rs @@ -6,16 +6,16 @@ fn test_roundtrip_types() { let path = d.path().join("test_roundtrip_types.nc"); { let mut file = netcdf::create(&path).unwrap(); - file.add_variable::("i8", &[]).unwrap(); - file.add_variable::("u8", &[]).unwrap(); - file.add_variable::("i16", &[]).unwrap(); - file.add_variable::("u16", &[]).unwrap(); - file.add_variable::("i32", &[]).unwrap(); - file.add_variable::("u32", &[]).unwrap(); - file.add_variable::("i64", &[]).unwrap(); - file.add_variable::("u64", &[]).unwrap(); - file.add_variable::("f32", &[]).unwrap(); - file.add_variable::("f64", &[]).unwrap(); + file.add_variable::("i8", ()).unwrap(); + file.add_variable::("u8", ()).unwrap(); + file.add_variable::("i16", ()).unwrap(); + file.add_variable::("u16", ()).unwrap(); + file.add_variable::("i32", ()).unwrap(); + file.add_variable::("u32", ()).unwrap(); + file.add_variable::("i64", ()).unwrap(); + file.add_variable::("u64", ()).unwrap(); + file.add_variable::("f32", ()).unwrap(); + file.add_variable::("f64", ()).unwrap(); file.add_string_variable("string", &[]).unwrap(); }