diff --git a/geo-types/CHANGES.md b/geo-types/CHANGES.md index 79bb76114..4b4b0cdb2 100644 --- a/geo-types/CHANGES.md +++ b/geo-types/CHANGES.md @@ -2,6 +2,8 @@ ## Unreleased * Add rstar compatibility for MultiPolygon +* Add multi-threading support to Multi* geometries. + * Feature-gated ('multithreading'), disabled by default, enabled by default when geo-types is used by geo ## 0.7.13 diff --git a/geo-types/Cargo.toml b/geo-types/Cargo.toml index 17c95d39d..6fd4eea99 100644 --- a/geo-types/Cargo.toml +++ b/geo-types/Cargo.toml @@ -13,6 +13,7 @@ edition = "2021" [features] default = ["std"] std = ["approx?/std", "num-traits/std", "serde?/std"] +multithreading = ["rayon"] # Prefer `use-rstar` feature rather than enabling rstar directly. # rstar integration relies on the optional approx crate, but implicit features cannot yet enable other features. # See: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#namespaced-features @@ -25,6 +26,7 @@ use-rstar_0_11 = ["rstar_0_11", "approx"] use-rstar_0_12 = ["rstar_0_12", "approx"] [dependencies] +rayon = { version = "1.10.0", optional = true } approx = { version = ">= 0.4.0, < 0.6.0", optional = true, default-features = false } arbitrary = { version = "1.2.0", optional = true } num-traits = { version = "0.2", default-features = false, features = ["libm"] } diff --git a/geo-types/src/geometry/multi_line_string.rs b/geo-types/src/geometry/multi_line_string.rs index 11b0c8ff8..4fcdfa466 100644 --- a/geo-types/src/geometry/multi_line_string.rs +++ b/geo-types/src/geometry/multi_line_string.rs @@ -5,6 +5,8 @@ use alloc::vec::Vec; #[cfg(any(feature = "approx", test))] use approx::{AbsDiffEq, RelativeEq}; use core::iter::FromIterator; +#[cfg(feature = "multithreading")] +use rayon::prelude::*; /// A collection of /// [`LineString`s](line_string/struct.LineString.html). Can @@ -118,6 +120,36 @@ impl MultiLineString { } } +#[cfg(feature = "multithreading")] +impl IntoParallelIterator for MultiLineString { + type Item = LineString; + type Iter = rayon::vec::IntoIter>; + + fn into_par_iter(self) -> Self::Iter { + self.0.into_par_iter() + } +} + +#[cfg(feature = "multithreading")] +impl<'a, T: CoordNum + Sync> IntoParallelIterator for &'a MultiLineString { + type Item = &'a LineString; + type Iter = rayon::slice::Iter<'a, LineString>; + + fn into_par_iter(self) -> Self::Iter { + self.0.par_iter() + } +} + +#[cfg(feature = "multithreading")] +impl<'a, T: CoordNum + Send + Sync> IntoParallelIterator for &'a mut MultiLineString { + type Item = &'a mut LineString; + type Iter = rayon::slice::IterMut<'a, LineString>; + + fn into_par_iter(self) -> Self::Iter { + self.0.par_iter_mut() + } +} + #[cfg(any(feature = "approx", test))] impl RelativeEq for MultiLineString where diff --git a/geo-types/src/geometry/multi_point.rs b/geo-types/src/geometry/multi_point.rs index ff3c16c6f..c596333da 100644 --- a/geo-types/src/geometry/multi_point.rs +++ b/geo-types/src/geometry/multi_point.rs @@ -6,6 +6,8 @@ use approx::{AbsDiffEq, RelativeEq}; use alloc::vec; use alloc::vec::Vec; use core::iter::FromIterator; +#[cfg(feature = "multithreading")] +use rayon::prelude::*; /// A collection of [`Point`s](struct.Point.html). Can /// be created from a `Vec` of `Point`s, or from an @@ -85,6 +87,36 @@ impl<'a, T: CoordNum> IntoIterator for &'a mut MultiPoint { } } +#[cfg(feature = "multithreading")] +impl IntoParallelIterator for MultiPoint { + type Item = Point; + type Iter = rayon::vec::IntoIter>; + + fn into_par_iter(self) -> Self::Iter { + self.0.into_par_iter() + } +} + +#[cfg(feature = "multithreading")] +impl<'a, T: CoordNum + Sync> IntoParallelIterator for &'a MultiPoint { + type Item = &'a Point; + type Iter = rayon::slice::Iter<'a, Point>; + + fn into_par_iter(self) -> Self::Iter { + self.0.par_iter() + } +} + +#[cfg(feature = "multithreading")] +impl<'a, T: CoordNum + Send + Sync> IntoParallelIterator for &'a mut MultiPoint { + type Item = &'a mut Point; + type Iter = rayon::slice::IterMut<'a, Point>; + + fn into_par_iter(self) -> Self::Iter { + self.0.par_iter_mut() + } +} + impl MultiPoint { pub fn new(value: Vec>) -> Self { Self(value) diff --git a/geo-types/src/geometry/multi_polygon.rs b/geo-types/src/geometry/multi_polygon.rs index fefeaf857..a40ea9965 100644 --- a/geo-types/src/geometry/multi_polygon.rs +++ b/geo-types/src/geometry/multi_polygon.rs @@ -4,7 +4,10 @@ use alloc::vec; use alloc::vec::Vec; #[cfg(any(feature = "approx", test))] use approx::{AbsDiffEq, RelativeEq}; + use core::iter::FromIterator; +#[cfg(feature = "multithreading")] +use rayon::prelude::*; /// A collection of [`Polygon`s](struct.Polygon.html). Can /// be created from a `Vec` of `Polygon`s, or from an @@ -75,6 +78,36 @@ impl<'a, T: CoordNum> IntoIterator for &'a mut MultiPolygon { } } +#[cfg(feature = "multithreading")] +impl IntoParallelIterator for MultiPolygon { + type Item = Polygon; + type Iter = rayon::vec::IntoIter>; // Parallel iterator type for Vec> + + fn into_par_iter(self) -> Self::Iter { + self.0.into_par_iter() + } +} + +#[cfg(feature = "multithreading")] +impl<'a, T: CoordNum + Sync> IntoParallelIterator for &'a MultiPolygon { + type Item = &'a Polygon; + type Iter = rayon::slice::Iter<'a, Polygon>; // Parallel iterator type for a slice of Polygon + + fn into_par_iter(self) -> Self::Iter { + self.0.par_iter() + } +} + +#[cfg(feature = "multithreading")] +impl<'a, T: CoordNum + Send + Sync> IntoParallelIterator for &'a mut MultiPolygon { + type Item = &'a mut Polygon; + type Iter = rayon::slice::IterMut<'a, Polygon>; // Parallel iterator type for a mutable slice of Polygon + + fn into_par_iter(self) -> Self::Iter { + self.0.par_iter_mut() + } +} + impl MultiPolygon { /// Instantiate Self from the raw content value pub fn new(value: Vec>) -> Self { diff --git a/geo/Cargo.toml b/geo/Cargo.toml index d48be60f2..330d1c399 100644 --- a/geo/Cargo.toml +++ b/geo/Cargo.toml @@ -17,7 +17,7 @@ default = ["earcutr", "spade", "multithreading"] use-proj = ["proj"] proj-network = ["use-proj", "proj/network"] use-serde = ["serde", "geo-types/serde"] -multithreading = ["i_overlay/allow_multithreading"] +multithreading = ["i_overlay/allow_multithreading", "geo-types/multithreading"] [dependencies] earcutr = { version = "0.4.2", optional = true }