Add compile tests to ensure borrow semantics
+ add `trybuild`
+ add test to verify `Layer::features` mut-borrow. Refer
MODIFY
Cargo.toml
Cargo.toml
@@ -31,6 +31,7 @@ semver = "0.11"
[dev-dependencies]
tempfile = "3.1"
+trybuild = "1.0.39"
[workspace]
members = ["gdal-sys"]

MODIFY
src/vector/layer.rs
src/vector/layer.rs
@@ -69,10 +69,6 @@ impl<'a> Layer<'a> {
/// Not all drivers support this efficiently; however, the call should always work if the
/// feature exists, as a fallback implementation just scans all the features in the layer
/// looking for the desired feature.
- ///
- /// **Important**: do not call `feature` while iterating over features using the
- /// [`features`](Layer::features) function. Even if you don't mutate anything, this can cause
- /// the the iterator to get interrupted. This is a limitation of the GDAL library.
pub fn feature(&self, fid: u64) -> Option<Feature> {
let c_feature = unsafe { gdal_sys::OGR_L_GetFeature(self.c_layer, fid as i64) };
if c_feature.is_null() {
@@ -82,16 +78,24 @@ impl<'a> Layer<'a> {
}
}
- /// Iterate over all features in this layer.
+ /// Returns iterator over the features in this layer.
+ ///
+ /// **Note.** This method resets the current index to
+ /// the beginning before iteration. It also borrows the
+ /// layer mutably, preventing any overlapping borrows.
pub fn features(&mut self) -> FeatureIterator {
self.reset_feature_reading();
FeatureIterator::_with_layer(self)
}
+ /// Set a spatial filter on this layer.
+ ///
+ /// Refer [OGR_L_SetSpatialFilter](https://gdal.org/doxygen/classOGRLayer.html#a75c06b4993f8eb76b569f37365cd19ab)
pub fn set_spatial_filter(&mut self, geometry: &Geometry) {
unsafe { gdal_sys::OGR_L_SetSpatialFilter(self.c_layer, geometry.c_geometry()) };
}
+ /// Clear spatial filters set on this layer.
pub fn clear_spatial_filter(&mut self) {
unsafe { gdal_sys::OGR_L_SetSpatialFilter(self.c_layer, null_mut()) };
}
@@ -235,6 +239,9 @@ impl<'a> Layer<'a> {
}
}
+ /// Fetch the spatial reference system for this layer.
+ ///
+ /// Refer [OGR_L_GetSpatialRef](https://gdal.org/doxygen/classOGRLayer.html#a75c06b4993f8eb76b569f37365cd19ab)
pub fn spatial_ref(&self) -> Result<SpatialRef> {
let c_obj = unsafe { gdal_sys::OGR_L_GetSpatialRef(self.c_layer) };
if c_obj.is_null() {

MODIFY
src/vector/vector_tests/mod.rs
src/vector/vector_tests/mod.rs
@@ -499,8 +499,12 @@ mod tests {
});
}
- // A compilation test that should fail.
- //
+ #[test]
+ fn test_features_aliasing_compile_fail() {
+ let t = trybuild::TestCases::new(); // A compilation test that should fail.
+ t.compile_fail("tests/ui/01-features-aliasing-errors.rs");
+ }
+
// It tries to iterate over a layer's features, while
// also trying to read the layer's definition. The
// features iterator borrows layer as a mutable ref as

ADD
tests/ui/01-features-aliasing-errors.rs
+mod utils;
+
+use gdal::Dataset;
+
+fn main() {
+ let ds = Dataset::open(fixture!("roads.geojson")).unwrap();
+ let mut layer = ds.layer(0).unwrap();
+ for _ in layer.features() {
+ let _ = layer.defn();
+ }
+}

ADD
tests/ui/01-features-aliasing-errors.stderr
+error[E0502]: cannot borrow `layer` as immutable because it is also borrowed as mutable
+ --> $DIR/01-features-aliasing-errors.rs:9:17
+ |
+8 | for _ in layer.features() {
+ | ----------------
+ | |
+ | mutable borrow occurs here
+ | mutable borrow later used here
+9 | let _ = layer.defn();
+ | ^^^^^ immutable borrow occurs here

ADD
tests/ui/utils.rs
+#[macro_export]
+macro_rules! fixture {
+ ($name:expr) => {
+ std::path::Path::new(file!())
+ .parent()
+ .unwrap()
+ .parent()
+ .unwrap()
+ .join("fixtures")
+ .as_path()
+ .join($name)
+ .as_path()
+ };
+}

Add compile tests to ensure borrow semantics

+ add `trybuild`

+ add test to verify `Layer::features` mut-borrow. Refer
  https://github.com/georust/gdal/issues/159