cartography 0.11.0

Cartography is a map rendering library for Geographic features expressed using [georust](https://georust.org/) libraries.
Documentation
use std::sync::{
  Arc,
  atomic::{AtomicBool, Ordering},
};

use geo::Intersects as _;

use crate::{BoxedImageDataRef, BoxedLayer, ImageFeature, Layer, geometry};

/// Trait for features
pub trait Feature: Send + Sync
{
  /// Get the geometry of the feature
  fn geometry(&self) -> Option<geo::Geometry>;
  /// Get the image of the feature, if any
  fn image<'a>(&'a self) -> Option<ImageFeature<BoxedImageDataRef<'a>>>;
  /// Get the geometry type of the feature
  fn geometry_type(&self) -> geometry::GeometryType;
  /// Get the geometry type of the element of a collection
  fn element_geometry_type(&self) -> geometry::GeometryType;
  /// Return true if a coordinate is within the bounding box
  fn intersects(&self, rect: geo::Rect) -> bool;
}

/// Trait that can be implemented for a feature that can return a reference to a geometry
pub trait GeometryRef: Send + Sync
{
  /// A reference to the geometry of the feature
  fn geometry_ref(&self) -> &geo::Geometry;
}

impl<T> Feature for T
where
  T: GeometryRef,
{
  fn geometry(&self) -> Option<geo::Geometry>
  {
    Some(self.geometry_ref().to_owned())
  }
  fn image(&self) -> Option<ImageFeature<BoxedImageDataRef<'_>>>
  {
    None
  }
  fn geometry_type(&self) -> geometry::GeometryType
  {
    use crate::geometry::GeometryExt;
    self.geometry_ref().geometry_type()
  }
  fn element_geometry_type(&self) -> geometry::GeometryType
  {
    use crate::geometry::GeometryExt;
    self.geometry_ref().element_geometry_type()
  }
  fn intersects(&self, rect: geo::Rect) -> bool
  {
    self.geometry_ref().intersects(&rect)
  }
}

struct MapLayer<TFeature: Feature>
{
  name: String,
  layer: BoxedLayer<TFeature>,
  visible: AtomicBool,
}

/// Cartography map
pub struct Map<TFeature: Feature>
{
  layers: Vec<MapLayer<TFeature>>,
}

ccutils::assert_impl_all!(for(TFeature: Feature) Map<TFeature>: Sync);
ccutils::assert_impl_all!(for(TFeature: Feature) Map<TFeature>: Send);

impl<TFeature: Feature> Default for Map<TFeature>
{
  fn default() -> Self
  {
    Self::new()
  }
}

impl<TFeature: Feature> Map<TFeature>
{
  /// Create a new map
  pub fn new() -> Self
  {
    Self {
      layers: Default::default(),
    }
  }
  /// Add a new visible layer
  pub fn add_visible_layer(
    &mut self,
    name: impl Into<String>,
    layer: impl Layer<TFeature> + 'static,
  )
  {
    let name = name.into();
    let layer = Box::new(layer);
    self.layers.push(MapLayer {
      name,
      layer,
      visible: AtomicBool::new(true),
    });
  }
  /// Hide a layer
  pub fn hide_layer<'a>(&mut self, name: impl Into<&'a str>)
  {
    let name = name.into();
    self.layers.iter_mut().for_each(|l| {
      if l.name == name
      {
        l.visible.store(false, Ordering::Relaxed);
      }
    });
  }
  /// Iterator over visible layers
  pub fn visible_layers(&self) -> impl Iterator<Item = &BoxedLayer<TFeature>>
  {
    self
      .layers
      .iter()
      .filter(|l| l.visible.load(Ordering::Relaxed))
      .map(|ml| &ml.layer)
  }
  /// Is a layer visible
  pub fn is_visible<'a>(&self, name: impl Into<&'a str>) -> bool
  {
    let name = name.into();
    self
      .layers
      .iter()
      .find_map(|l| {
        if l.name == name
        {
          Some(l.visible.load(Ordering::Relaxed))
        }
        else
        {
          None
        }
      })
      .unwrap_or(false)
  }
  /// This function is used to update the visibility of a layer, return true if the visibility was changed or false otherwise
  pub fn maybe_update_visibility<'a>(&self, name: impl Into<&'a str>, visibility: bool) -> bool
  {
    let name = name.into();
    self
      .layers
      .iter()
      .find_map(|l| {
        if l.name == name
        {
          Some(l.visible.swap(visibility, Ordering::Relaxed) != visibility)
        }
        else
        {
          None
        }
      })
      .unwrap_or(false)
  }
}

/// Cartography map builder
pub struct MapBuilder<TFeature: Feature>
{
  map: Map<TFeature>,
}

impl<TFeature: Feature> Default for MapBuilder<TFeature>
{
  fn default() -> Self
  {
    Self::new()
  }
}

impl<TFeature: Feature> MapBuilder<TFeature>
{
  /// Create a new map
  pub fn new() -> Self
  {
    Self { map: Map::new() }
  }
  /// Add a new visible layer
  pub fn add_visible_layer(
    mut self,
    name: impl Into<String>,
    layer: impl Layer<TFeature> + 'static,
  ) -> Self
  {
    self.map.add_visible_layer(name, layer);
    self
  }
}

impl<TFeature: Feature> From<MapBuilder<TFeature>> for Map<TFeature>
{
  fn from(val: MapBuilder<TFeature>) -> Self
  {
    val.map
  }
}

impl<TFeature: Feature> From<MapBuilder<TFeature>> for Arc<Map<TFeature>>
{
  fn from(val: MapBuilder<TFeature>) -> Self
  {
    Arc::new(val.into())
  }
}