diff --git a/src/file.rs b/src/file.rs index b2c46f1..173eff4 100644 --- a/src/file.rs +++ b/src/file.rs @@ -136,13 +136,13 @@ impl ReadOnlyFile { } /// Get a variable from the group - pub fn variable<'g>(&'g self, name: &str) -> error::Result>> { + pub fn variable<'f>(&'f self, name: &str) -> error::Result>> { Variable::find_from_name(self.ncid(), name) } /// Iterate over all variables in a group pub fn variables<'f>( &'f self, - ) -> error::Result>>> { + ) -> error::Result>>> { super::variable::variables_at_ncid(self.ncid()) } @@ -164,18 +164,18 @@ impl ReadOnlyFile { super::dimension::dimension_from_name(self.ncid(), name) } /// Iterator over all dimensions in the root group - pub fn dimensions<'g>( - &'g self, - ) -> error::Result>>> { + pub fn dimensions<'f>( + &'f self, + ) -> error::Result>>> { super::dimension::dimensions_from_location(self.ncid()) } /// Get a group - pub fn group(&self, name: &str) -> error::Result> { + pub fn group<'f>(&'f self, name: &str) -> error::Result>> { super::group::group_from_name(self.ncid(), name) } /// Iterator over all subgroups in the root group - pub fn groups<'g>(&'g self) -> error::Result>> { + pub fn groups<'f>(&'f self) -> error::Result>> { super::group::groups_at_ncid(self.ncid()) } } @@ -198,17 +198,25 @@ impl MutableFile { } /// Get a mutable variable from the group - pub fn variable_mut<'g>( - &'g mut self, - name: &str, - ) -> error::Result>> { + pub fn variable_mut<'f>(&'f mut self, name: &str) -> error::Result>> { self.variable(name) .map(|var| var.map(|var| VariableMut(var, PhantomData))) } /// Iterate over all variables in the root group, with mutable access + /// + /// # Examples + /// Use this to get multiple writable variables + /// ```no_run + /// # fn main() -> Result<(), Box> { + /// let mut file = netcdf::append("file.nc")?; + /// let mut vars = file.variables_mut()?.collect::, _>>()?; + /// vars[0].put_value(1_u8, Some(&[2, 5]))?; + /// vars[1].put_value(1_u8, Some(&[5, 2]))?; + /// # Ok(()) } + /// ``` pub fn variables_mut<'f>( &'f mut self, - ) -> error::Result>>> { + ) -> error::Result>>> { self.variables() .map(|v| v.map(|var| var.map(|var| VariableMut(var, PhantomData)))) } @@ -233,7 +241,7 @@ impl MutableFile { } /// Adds a dimension with the given name and size. A size of zero gives an unlimited dimension - pub fn add_dimension<'g>(&'g mut self, name: &str, len: usize) -> error::Result> { + pub fn add_dimension<'f>(&'f mut self, name: &str, len: usize) -> error::Result> { let _l = LOCK.lock().unwrap(); super::dimension::add_dimension_at(self.ncid(), name, len) } @@ -256,7 +264,7 @@ impl MutableFile { &'f mut self, name: &str, dims: &[&str], - ) -> error::Result> + ) -> error::Result> where T: Numeric, { @@ -264,17 +272,21 @@ impl MutableFile { VariableMut::add_from_str(self.ncid(), T::NCTYPE, name, dims) } /// Adds a variable with a basic type of string - pub fn add_string_variable(&mut self, name: &str, dims: &[&str]) -> error::Result { + pub fn add_string_variable<'f>( + &'f mut self, + name: &str, + dims: &[&str], + ) -> error::Result> { let _l = LOCK.lock().unwrap(); VariableMut::add_from_str(self.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( - &mut self, + pub fn add_variable_from_identifiers<'f, T>( + &'f mut self, name: &str, dims: &[dimension::Identifier], - ) -> error::Result + ) -> error::Result> where T: Numeric, { diff --git a/src/group.rs b/src/group.rs index 237d732..b62e50a 100644 --- a/src/group.rs +++ b/src/group.rs @@ -54,13 +54,19 @@ impl<'f> Group<'f> { } /// Get a variable from the group - pub fn variable<'g>(&'g self, name: &str) -> error::Result>> { + pub fn variable<'g>(&'g self, name: &str) -> error::Result>> + where + 'f: 'g, + { Variable::find_from_name(self.id(), name) } /// Iterate over all variables in a group pub fn variables<'g>( &'g self, - ) -> error::Result>>> { + ) -> error::Result>>> + where + 'f: 'g, + { super::variable::variables_at_ncid(self.id()) } @@ -70,57 +76,80 @@ impl<'f> Group<'f> { Attribute::find_from_name(self.ncid, None, name) } /// Get all attributes in the group - pub fn attributes(&self) -> error::Result>> { + pub fn attributes<'a>( + &'a self, + ) -> error::Result>>> { // Need to lock when reading the first attribute (per group) let _l = super::LOCK.lock().unwrap(); crate::attribute::AttributeIterator::new(self.ncid, None) } /// Get a single dimension - pub fn dimension(&self, name: &str) -> error::Result> { + pub fn dimension<'g>(&'g self, name: &str) -> error::Result>> + where + 'f: 'g, + { super::dimension::dimension_from_name(self.id(), name) } /// Iterator over all dimensions pub fn dimensions<'g>( &'g self, - ) -> error::Result>>> { + ) -> error::Result>>> + where + 'f: 'g, + { super::dimension::dimensions_from_location(self.id()) } /// Get a group - pub fn group(&self, name: &str) -> error::Result> { + pub fn group<'g>(&'g self, name: &str) -> error::Result>> + where + 'f: 'g, + { group_from_name(self.id(), name) } /// Iterator over all subgroups in this group - pub fn groups<'g>(&'g self) -> error::Result>> { + pub fn groups<'g>(&'g self) -> error::Result>> + where + 'f: 'g, + { groups_at_ncid(self.id()) } } impl<'f> GroupMut<'f> { /// Get a mutable variable from the group - pub fn variable_mut<'g>( - &'g mut self, - name: &str, - ) -> error::Result>> { + pub fn variable_mut<'g>(&'g mut self, name: &str) -> error::Result>> + where + 'f: 'g, + { self.variable(name) .map(|v| v.map(|v| VariableMut(v, PhantomData))) } /// Iterate over all variables in a group, with mutable access pub fn variables_mut<'g>( &'g mut self, - ) -> error::Result>>> { + ) -> error::Result>>> + where + 'f: 'g, + { self.variables() .map(|var| var.map(|var| var.map(|var| VariableMut(var, PhantomData)))) } /// Mutable access to subgroup - pub fn group_mut(&'f mut self, name: &str) -> error::Result> { + pub fn group_mut<'g>(&'g mut self, name: &str) -> error::Result>> + where + 'f: 'g, + { self.group(name) .map(|g| g.map(|g| GroupMut(g, PhantomData))) } /// Iterator over all groups (mutable access) - pub fn groups_mut(&'f mut self) -> error::Result>> { + pub fn groups_mut<'g>(&'g mut self) -> error::Result>> + where + 'f: 'g, + { self.groups().map(|g| g.map(|g| GroupMut(g, PhantomData))) } @@ -140,7 +169,7 @@ impl<'f> GroupMut<'f> { } /// Adds a dimension with unbounded size - pub fn add_unlimited_dimension(&mut self, name: &str) -> error::Result { + pub fn add_unlimited_dimension<'g>(&'g mut self, name: &str) -> error::Result> { self.add_dimension(name, 0) } @@ -161,7 +190,10 @@ impl<'f> GroupMut<'f> { } /// Add an empty group to the dataset - pub fn add_group(&mut self, name: &str) -> error::Result { + pub fn add_group<'g>(&'g mut self, name: &str) -> error::Result> + where + 'f: 'g, + { let _l = LOCK.lock().unwrap(); Self::add_group_at(self.id(), name) } @@ -174,25 +206,30 @@ impl<'f> GroupMut<'f> { &'g mut self, name: &str, dims: &[&str], - ) -> error::Result> + ) -> error::Result> where T: Numeric, + 'f: 'g, { let _l = LOCK.lock().unwrap(); VariableMut::add_from_str(self.id(), T::NCTYPE, name, dims) } /// Adds a variable with a basic type of string - pub fn add_string_variable(&mut self, name: &str, dims: &[&str]) -> error::Result { + pub fn add_string_variable<'g>( + &mut self, + name: &str, + dims: &[&str], + ) -> error::Result> { let _l = LOCK.lock().unwrap(); VariableMut::add_from_str(self.id(), 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( - &mut self, + pub fn add_variable_from_identifiers<'g, T>( + &'g mut self, name: &str, dims: &[super::dimension::Identifier], - ) -> error::Result + ) -> error::Result> where T: Numeric, { diff --git a/src/variable.rs b/src/variable.rs index b8ad1cf..585ec78 100644 --- a/src/variable.rs +++ b/src/variable.rs @@ -16,9 +16,9 @@ use std::marker::Sized; #[allow(clippy::doc_markdown)] /// This struct defines a netCDF variable. #[derive(Debug, Clone)] -pub struct Variable<'f, 'g> { +pub struct Variable<'g> { /// The variable name - pub(crate) dimensions: Vec>, + pub(crate) dimensions: Vec>, /// the netcdf variable type identifier (from netcdf-sys) pub(crate) vartype: nc_type, pub(crate) ncid: nc_type, @@ -27,14 +27,14 @@ pub struct Variable<'f, 'g> { } #[derive(Debug)] -/// Mutable access to a variable -pub struct VariableMut<'f, 'g>( - pub(crate) Variable<'f, 'g>, +/// Mutable access to a variable. +pub struct VariableMut<'g>( + pub(crate) Variable<'g>, pub(crate) PhantomData<&'g mut nc_type>, ); -impl<'f, 'g> std::ops::Deref for VariableMut<'f, 'g> { - type Target = Variable<'f, 'g>; +impl<'g> std::ops::Deref for VariableMut<'g> { + type Target = Variable<'g>; fn deref(&self) -> &Self::Target { &self.0 } @@ -52,11 +52,8 @@ pub enum Endianness { } #[allow(clippy::len_without_is_empty)] -impl<'f, 'g> Variable<'f, 'g> { - pub(crate) fn find_from_name( - ncid: nc_type, - name: &str, - ) -> error::Result>> { +impl<'g> Variable<'g> { + pub(crate) fn find_from_name(ncid: nc_type, name: &str) -> error::Result>> { let cname = super::utils::short_name_to_bytes(name)?; let mut varid = 0; let e = unsafe { nc_inq_varid(ncid, cname.as_ptr() as *const _, &mut varid) }; @@ -151,7 +148,7 @@ impl<'f, 'g> Variable<'f, 'g> { } } } -impl<'f, 'g> VariableMut<'f, 'g> { +impl<'g> VariableMut<'g> { /// Sets compression on the variable. Must be set before filling in data. /// /// `deflate_level` can take a value 0..=9, with 0 being no @@ -200,7 +197,7 @@ impl<'f, 'g> VariableMut<'f, 'g> { } } -impl<'f, 'g> Variable<'f, 'g> { +impl<'g> Variable<'g> { /// Checks for array mismatch fn check_indices(&self, indices: &[usize], putting: bool) -> error::Result<()> { if indices.len() != self.dimensions.len() { @@ -684,7 +681,7 @@ impl std::ops::Deref for NcString { } } -impl<'f, 'g> VariableMut<'f, 'g> { +impl<'g> VariableMut<'g> { /// Adds an attribute to the variable pub fn add_attribute(&mut self, name: &str, val: T) -> error::Result where @@ -695,7 +692,7 @@ impl<'f, 'g> VariableMut<'f, 'g> { } } -impl<'f, 'g> Variable<'f, 'g> { +impl<'g> Variable<'g> { /// Fetches one specific value at specific indices /// indices must has the same length as self.dimensions. pub fn value(&self, indices: Option<&[usize]>) -> error::Result { @@ -900,7 +897,7 @@ impl<'f, 'g> Variable<'f, 'g> { } } -impl<'f, 'g> VariableMut<'f, 'g> { +impl<'g> VariableMut<'g> { /// Put a single value at `indices` pub fn put_value( &mut self, @@ -1098,7 +1095,7 @@ impl<'f, 'g> VariableMut<'f, 'g> { } } -impl<'f, 'g> VariableMut<'f, 'g> { +impl<'g> VariableMut<'g> { pub(crate) fn add_from_str( ncid: nc_type, xtype: nc_type, @@ -1141,12 +1138,9 @@ impl<'f, 'g> VariableMut<'f, 'g> { } } -pub(crate) fn variables_at_ncid<'f, 'g>( +pub(crate) fn variables_at_ncid<'g>( ncid: nc_type, -) -> error::Result>>> -where - 'f: 'g, -{ +) -> error::Result>>> { let mut nvars = 0; unsafe { error::checked(nc_inq_varids(ncid, &mut nvars, std::ptr::null_mut()))?; @@ -1176,12 +1170,12 @@ where })) } -pub(crate) fn add_variable_from_identifiers<'f, 'g>( +pub(crate) fn add_variable_from_identifiers<'g>( ncid: nc_type, name: &str, dims: &[super::dimension::Identifier], xtype: nc_type, -) -> error::Result> { +) -> error::Result> { let cname = super::utils::short_name_to_bytes(name)?; let dimensions = dims diff --git a/tests/lib.rs b/tests/lib.rs index 310a205..979aeff 100644 --- a/tests/lib.rs +++ b/tests/lib.rs @@ -1292,14 +1292,12 @@ fn dimension_identifiers() { let g = &mut file.add_group("g").unwrap(); let dim = &g.add_dimension("x", 5).unwrap(); let vgid = dim.identifier(); - let mut gg = file - .group_mut("g") - .unwrap() - .unwrap() - .add_group("g") - .unwrap(); - let dim = &gg.add_dimension("x", 7).unwrap(); - let vggid = dim.identifier(); + let vggid = { + let mut g = file.group_mut("g").unwrap().unwrap(); + let mut gg = g.add_group("g").unwrap(); + let dim = &gg.add_dimension("x", 7).unwrap(); + dim.identifier() + }; // Create variables file.add_variable_from_identifiers::("v_self_id", &[vrootid])