use std::slice::SliceIndex;
use record::{Point, PointM, PointZ};
pub trait HasXY {
fn x(&self) -> f64;
fn y(&self) -> f64;
}
pub(crate) trait HasMutXY {
fn x_mut(&mut self) -> &mut f64;
fn y_mut(&mut self) -> &mut f64;
}
pub(crate) trait HasM {
fn m(&self) -> f64;
fn m_mut(&mut self) -> &mut f64;
}
pub trait MultipointShape<PointType> {
fn point<I: SliceIndex<[PointType]>>(
&self,
index: I,
) -> Option<&<I as SliceIndex<[PointType]>>::Output>;
fn points(&self) -> &[PointType];
}
pub trait MultipartShape<PointType>: MultipointShape<PointType> {
fn parts_indices(&self) -> &[i32];
fn part(&self, index: usize) -> Option<&[PointType]> {
let parts = self.parts_indices();
if parts.len() < 2 {
Some(self.points())
} else {
let first_index = *parts.get(index)? as usize;
let last_index = if index == parts.len() - 1 {
self.points().len()
} else {
*parts.get(index + 1)? as usize
};
self.points().get(first_index..last_index)
}
}
fn parts(&self) -> PartIterator<PointType, Self> {
PartIterator {
phantom: std::marker::PhantomData,
shape: &self,
current_part: 0,
}
}
}
pub struct PartIterator<'a, PointType, Shape: 'a + MultipartShape<PointType> + ?Sized> {
phantom: std::marker::PhantomData<PointType>,
shape: &'a Shape,
current_part: usize,
}
impl<'a, PointType, Shape> Iterator for PartIterator<'a, PointType, Shape>
where
PointType: 'a,
Shape: 'a + MultipartShape<PointType>,
{
type Item = &'a [PointType];
fn next(&mut self) -> Option<Self::Item> {
if self.current_part >= self.shape.parts_indices().len() {
None
} else {
self.current_part += 1;
self.shape.part(self.current_part - 1)
}
}
}
macro_rules! impl_has_xy_for {
($PointType:ty) => {
impl HasXY for $PointType {
fn x(&self) -> f64 {
self.x
}
fn y(&self) -> f64 {
self.y
}
}
};
}
macro_rules! impl_has_mut_xy_for {
($PointType:ty) => {
impl HasMutXY for $PointType {
fn x_mut(&mut self) -> &mut f64 {
&mut self.x
}
fn y_mut(&mut self) -> &mut f64 {
&mut self.y
}
}
};
}
macro_rules! impl_has_m_for {
($PointType:ty) => {
impl HasM for $PointType {
fn m(&self) -> f64 {
self.m
}
fn m_mut(&mut self) -> &mut f64 {
&mut self.m
}
}
};
}
impl_has_xy_for!(Point);
impl_has_xy_for!(PointM);
impl_has_xy_for!(PointZ);
impl_has_mut_xy_for!(Point);
impl_has_mut_xy_for!(PointM);
impl_has_mut_xy_for!(PointZ);
impl_has_m_for!(PointM);
impl_has_m_for!(PointZ);