diff --git a/CHANGES.md b/CHANGES.md index 2b01b62d..d61908ef 100644 --- a/CHANGES.md +++ b/CHANGES.md @@ -1,6 +1,8 @@ # Changes ## Unreleased +- **Breaking**: `Feature::set_field_xxx` now take `&mut self` + - - **Breaking**: Moved `raster::processing::dem` to `raster::dem` - **Breaking**: Moved `raster::reproject` to `raster::warp::reproject_into` and added more options @@ -16,7 +18,7 @@ - **Breaking**: Removed `Rasterband::read_as_array`, changed signature of `Rasterband::read_block` to return a `Buffer`. - **Breaking**: `Rasterband::write` and `Rasterband::write_block` now require a `&mut Buffer` to handle possible case of drivers temporarily mutating input buffer. - - + - - Implemented `Feature::set_field_null` diff --git a/src/raster/rasterize.rs b/src/raster/rasterize.rs index a37fa6e8..f8c8d799 100644 --- a/src/raster/rasterize.rs +++ b/src/raster/rasterize.rs @@ -116,37 +116,6 @@ impl TryFrom for CslStringList { } } -#[cfg(test)] -mod tests { - use std::convert::TryFrom; - - use crate::cpl::CslStringList; - - use super::RasterizeOptions; - - #[test] - fn test_rasterizeoptions_as_ptr() { - let c_options = CslStringList::try_from(RasterizeOptions::default()).unwrap(); - assert_eq!( - c_options.fetch_name_value("ALL_TOUCHED"), - Some("FALSE".to_string()) - ); - assert_eq!(c_options.fetch_name_value("BURN_VALUE_FROM"), None); - assert_eq!( - c_options.fetch_name_value("MERGE_ALG"), - Some("REPLACE".to_string()) - ); - assert_eq!( - c_options.fetch_name_value("CHUNKYSIZE"), - Some("0".to_string()) - ); - assert_eq!( - c_options.fetch_name_value("OPTIM"), - Some("AUTO".to_string()) - ); - } -} - /// Burn geometries into raster. /// /// Rasterize a sequence of `gdal::vector::Geometry` onto some @@ -229,3 +198,34 @@ pub fn rasterize( } Ok(()) } + +#[cfg(test)] +mod tests { + use std::convert::TryFrom; + + use crate::cpl::CslStringList; + + use super::RasterizeOptions; + + #[test] + fn test_rasterizeoptions_as_ptr() { + let c_options = CslStringList::try_from(RasterizeOptions::default()).unwrap(); + assert_eq!( + c_options.fetch_name_value("ALL_TOUCHED"), + Some("FALSE".to_string()) + ); + assert_eq!(c_options.fetch_name_value("BURN_VALUE_FROM"), None); + assert_eq!( + c_options.fetch_name_value("MERGE_ALG"), + Some("REPLACE".to_string()) + ); + assert_eq!( + c_options.fetch_name_value("CHUNKYSIZE"), + Some("0".to_string()) + ); + assert_eq!( + c_options.fetch_name_value("OPTIM"), + Some("AUTO".to_string()) + ); + } +} diff --git a/src/vector/feature.rs b/src/vector/feature.rs index 917a8c18..3fba86e4 100644 --- a/src/vector/feature.rs +++ b/src/vector/feature.rs @@ -505,14 +505,14 @@ impl<'a> Feature<'a> { Ok(()) } - pub fn set_field_string(&self, field_name: &str, value: &str) -> Result<()> { + pub fn set_field_string(&mut self, field_name: &str, value: &str) -> Result<()> { let c_str_value = CString::new(value)?; let idx = self.field_idx_from_name(field_name)?; unsafe { gdal_sys::OGR_F_SetFieldString(self.c_feature, idx, c_str_value.as_ptr()) }; Ok(()) } - pub fn set_field_string_list(&self, field_name: &str, value: &[&str]) -> Result<()> { + pub fn set_field_string_list(&mut self, field_name: &str, value: &[&str]) -> Result<()> { let c_strings = value .iter() .map(|&value| CString::new(value)) @@ -530,13 +530,13 @@ impl<'a> Feature<'a> { Ok(()) } - pub fn set_field_double(&self, field_name: &str, value: f64) -> Result<()> { + pub fn set_field_double(&mut self, field_name: &str, value: f64) -> Result<()> { let idx = self.field_idx_from_name(field_name)?; unsafe { gdal_sys::OGR_F_SetFieldDouble(self.c_feature, idx, value as c_double) }; Ok(()) } - pub fn set_field_double_list(&self, field_name: &str, value: &[f64]) -> Result<()> { + pub fn set_field_double_list(&mut self, field_name: &str, value: &[f64]) -> Result<()> { let idx = self.field_idx_from_name(field_name)?; unsafe { gdal_sys::OGR_F_SetFieldDoubleList( @@ -549,13 +549,13 @@ impl<'a> Feature<'a> { Ok(()) } - pub fn set_field_integer(&self, field_name: &str, value: i32) -> Result<()> { + pub fn set_field_integer(&mut self, field_name: &str, value: i32) -> Result<()> { let idx = self.field_idx_from_name(field_name)?; unsafe { gdal_sys::OGR_F_SetFieldInteger(self.c_feature, idx, value as c_int) }; Ok(()) } - pub fn set_field_integer_list(&self, field_name: &str, value: &[i32]) -> Result<()> { + pub fn set_field_integer_list(&mut self, field_name: &str, value: &[i32]) -> Result<()> { let idx = self.field_idx_from_name(field_name)?; unsafe { gdal_sys::OGR_F_SetFieldIntegerList( @@ -568,13 +568,13 @@ impl<'a> Feature<'a> { Ok(()) } - pub fn set_field_integer64(&self, field_name: &str, value: i64) -> Result<()> { + pub fn set_field_integer64(&mut self, field_name: &str, value: i64) -> Result<()> { let idx = self.field_idx_from_name(field_name)?; unsafe { gdal_sys::OGR_F_SetFieldInteger64(self.c_feature, idx, value as c_longlong) }; Ok(()) } - pub fn set_field_integer64_list(&self, field_name: &str, value: &[i64]) -> Result<()> { + pub fn set_field_integer64_list(&mut self, field_name: &str, value: &[i64]) -> Result<()> { let idx = self.field_idx_from_name(field_name)?; unsafe { gdal_sys::OGR_F_SetFieldInteger64List( @@ -587,7 +587,11 @@ impl<'a> Feature<'a> { Ok(()) } - pub fn set_field_datetime(&self, field_name: &str, value: DateTime) -> Result<()> { + pub fn set_field_datetime( + &mut self, + field_name: &str, + value: DateTime, + ) -> Result<()> { let idx = self.field_idx_from_name(field_name)?; let year = value.year() as c_int; @@ -618,7 +622,7 @@ impl<'a> Feature<'a> { Ok(()) } - pub fn set_field(&self, field_name: &str, value: &FieldValue) -> Result<()> { + pub fn set_field(&mut self, field_name: &str, value: &FieldValue) -> Result<()> { match value { FieldValue::IntegerValue(value) => self.set_field_integer(field_name, *value), FieldValue::IntegerListValue(value) => self.set_field_integer_list(field_name, value), @@ -653,7 +657,7 @@ impl<'a> Feature<'a> { /// See: [`OGRFeature::SetFieldNull`][SetFieldNull] /// /// [SetFieldNull]: https://gdal.org/api/ogrfeature_cpp.html#_CPPv4N10OGRFeature12SetFieldNullEi - pub fn set_field_null(&self, field_name: &str) -> Result<()> { + pub fn set_field_null(&mut self, field_name: &str) -> Result<()> { let idx = self.field_idx_from_name(field_name)?; unsafe { gdal_sys::OGR_F_SetFieldNull(self.c_feature(), idx) }; Ok(()) @@ -664,7 +668,7 @@ impl<'a> Feature<'a> { /// See: [`OGRFeature::UnsetField`][UnsetField] /// /// [UnsetField]: https://gdal.org/api/ogrfeature_cpp.html#_CPPv4N10OGRFeature10UnsetFieldEi - pub fn unset_field(&self, field_name: &str) -> Result<()> { + pub fn unset_field(&mut self, field_name: &str) -> Result<()> { let idx = self.field_idx_from_name(field_name)?; unsafe { gdal_sys::OGR_F_UnsetField(self.c_feature(), idx) }; Ok(()) @@ -681,6 +685,7 @@ impl<'a> Feature<'a> { self.geometry[0] = geom; Ok(()) } + pub fn field_count(&self) -> i32 { unsafe { gdal_sys::OGR_F_GetFieldCount(self.c_feature) } } @@ -951,13 +956,9 @@ mod tests { let ds = Dataset::open(fixture("roads.geojson")).unwrap(); let mut layer = ds.layers().next().expect("layer"); - let feature = layer.features().next().expect("feature"); - for (field_name, field_value) in feature.fields() { - if let Some(_value) = field_value { - feature.set_field_null(&field_name).unwrap(); - assert!(feature.field(&field_name).unwrap().is_none()); - } - } + let mut feature = layer.features().next().expect("feature"); + feature.set_field_null("highway").unwrap(); + assert!(feature.field("highway").unwrap().is_none()); } #[test] @@ -965,9 +966,7 @@ mod tests { let ds = Dataset::open(fixture("roads.geojson")).unwrap(); let mut layer = ds.layers().next().expect("layer"); - let feature = layer.features().next().expect("feature"); - for (field_name, _) in feature.fields() { - feature.unset_field(&field_name).unwrap(); - } + let mut feature = layer.features().next().expect("feature"); + feature.unset_field("highway").unwrap(); } } diff --git a/src/vector/layer.rs b/src/vector/layer.rs index 43b68ce5..962c57c1 100644 --- a/src/vector/layer.rs +++ b/src/vector/layer.rs @@ -984,7 +984,7 @@ mod tests { #[test] fn test_set_string_list_field() { with_features("soundg.json", |mut features| { - let feature = features.next().unwrap(); + let mut feature = features.next().unwrap(); let value = FieldValue::StringListValue(vec![ String::from("the"), String::from("new"), @@ -1181,7 +1181,7 @@ mod tests { #[test] fn test_set_int_list_field() { with_features("soundg.json", |mut features| { - let feature = features.next().unwrap(); + let mut feature = features.next().unwrap(); let value = FieldValue::IntegerListValue(vec![3, 4, 5]); feature.set_field("an_int_list", &value).unwrap(); assert_eq!(feature.field("an_int_list").unwrap().unwrap(), value); @@ -1202,7 +1202,7 @@ mod tests { #[test] fn test_set_real_list_field() { with_features("soundg.json", |mut features| { - let feature = features.next().unwrap(); + let mut feature = features.next().unwrap(); let value = FieldValue::RealListValue(vec![2.5, 3.0, 4.75]); feature.set_field("a_real_list", &value).unwrap(); assert_eq!(feature.field("a_real_list").unwrap().unwrap(), value); @@ -1223,7 +1223,7 @@ mod tests { #[test] fn test_set_long_list_field() { with_features("soundg.json", |mut features| { - let feature = features.next().unwrap(); + let mut feature = features.next().unwrap(); let value = FieldValue::Integer64ListValue(vec![7000000000, 8000000000]); feature.set_field("a_long_list", &value).unwrap(); assert_eq!(feature.field("a_long_list").unwrap().unwrap(), value); @@ -1415,7 +1415,7 @@ mod tests { let ds = Dataset::open_ex(&tmp_file, ds_options).unwrap(); let mut layer = ds.layer(0).unwrap(); let fids: Vec = layer.features().map(|f| f.fid().unwrap()).collect(); - let feature = layer.feature(fids[0]).unwrap(); + let mut feature = layer.feature(fids[0]).unwrap(); // to original value of the id field in fid 0 is null; we will set it to 1. feature.set_field_integer("id", 1).ok(); layer.set_feature(feature).ok();