cartography 0.10.0

Cartography is a map rendering library for Geographic features expressed using [georust](https://georust.org/) libraries.
Documentation
use crate::{Feature, Projection};

/// Trait for Map Layers
pub trait Layer<TFeature: Feature>: Send + Sync
{
  /// Return the projection used by this layer.
  fn projection(&self) -> &Projection;
  /// Iterator over the map geometries, filtered by the given rect. The zoom level can be used to select detail of features.
  fn features<'a>(
    &'a self,
    rect: geo::Rect,
    zoom_level: f64,
  ) -> Box<dyn Iterator<Item = ccutils::containers::RefOrValue<'a, TFeature>> + 'a>;
}

#[allow(type_alias_bounds)]
pub(crate) type BoxedLayer<TFeature: Feature> = Box<dyn Layer<TFeature>>;

/// Standard implementation of a Layer containing a vector of features
pub struct FeaturesVecLayer<TFeature: Feature>
{
  projection: Projection,
  features: Vec<TFeature>,
}

impl<TFeature: Feature> FeaturesVecLayer<TFeature>
{
  /// Returns the bounding rectangle of all geometries in the layer.
  pub fn extent(&self) -> Option<geo::Rect>
  {
    use geo::BoundingRect as _;

    self
      .features
      .iter()
      .filter_map(|feature| {
        feature
          .geometry()
          .and_then(|geometry| geometry.bounding_rect())
      })
      .reduce(|a, b| {
        geo::Rect::new(
          geo::coord! {
            x: a.min().x.min(b.min().x),
            y: a.min().y.min(b.min().y),
          },
          geo::coord! {
            x: a.max().x.max(b.max().x),
            y: a.max().y.max(b.max().y),
          },
        )
      })
  }

  /// Parse the layer as vector of features of the given type using `geojson`.
  #[cfg(feature = "geojson")]
  #[allow(clippy::result_large_err)]
  pub fn read_from_geo_json<'de, T>(
    feature_collection_reader: impl std::io::Read,
  ) -> geojson::Result<Self>
  where
    T: serde::Deserialize<'de> + Into<TFeature>,
  {
    let projection = Projection::wgs84();
    let features =
      geojson::de::deserialize_feature_collection_to_vec::<T>(feature_collection_reader)?;
    let features = features.into_iter().map(|x| x.into()).collect();
    Ok(Self {
      projection,
      features,
    })
  }
}

impl<TFeature: Feature> From<Vec<TFeature>> for FeaturesVecLayer<TFeature>
{
  fn from(features: Vec<TFeature>) -> Self
  {
    Self {
      projection: Projection::wgs84(),
      features,
    }
  }
}

impl<TFeature, TVecElement> FromIterator<TVecElement> for FeaturesVecLayer<TFeature>
where
  TFeature: Feature,
  TVecElement: Into<TFeature>,
{
  fn from_iter<T: IntoIterator<Item = TVecElement>>(iter: T) -> Self
  {
    Self {
      projection: Projection::wgs84(),
      features: iter.into_iter().map(Into::into).collect(),
    }
  }
}

impl<TFeature: Feature> Layer<TFeature> for FeaturesVecLayer<TFeature>
{
  fn projection(&self) -> &Projection
  {
    &self.projection
  }
  fn features<'a>(
    &'a self,
    rect: geo::Rect,
    _zoom_level: f64,
  ) -> Box<dyn Iterator<Item = crate::RefOrValue<'a, TFeature>> + 'a>
  {
    Box::new(
      self
        .features
        .iter()
        .filter(move |feat| feat.intersects(rect))
        .map(Into::into),
    )
  }
}

/// Trait for converting into a layer
pub trait IntoLayer<TFeature>
where
  TFeature: Feature,
{
  /// Layer type
  type Layer: Layer<TFeature>;
  /// Convert to a layer
  /// ```ignore
  /// # This example requires the `geojson` feature to be enabled
  /// let layer = geojson::GeoJson::from_reader(reader)?.into_layer::<MyFeature>();
  /// ```
  #[must_use]
  fn into_layer(self) -> Self::Layer;
}

impl<TFeature, TOtherFeature> IntoLayer<TFeature> for Vec<TOtherFeature>
where
  TFeature: From<TOtherFeature> + Feature,
{
  type Layer = FeaturesVecLayer<TFeature>;
  fn into_layer(self) -> Self::Layer
  {
    FeaturesVecLayer::from_iter(self.into_iter().map(Into::<TFeature>::into))
  }
}