geo_traits/
line_string.rs

1use std::marker::PhantomData;
2
3use crate::iterator::LineStringIterator;
4use crate::{CoordTrait, GeometryTrait, UnimplementedCoord};
5#[cfg(feature = "geo-types")]
6use geo_types::{Coord, CoordNum, LineString};
7
8/// A trait for accessing data from a generic LineString.
9///
10/// A LineString is an ordered collection of two or more [points][CoordTrait], representing a path
11/// between locations.
12///
13/// Refer to [geo_types::LineString] for information about semantics and validity.
14pub trait LineStringTrait: Sized + GeometryTrait {
15    /// The type of each underlying coordinate, which implements [CoordTrait]
16    type CoordType<'a>: 'a + CoordTrait<T = Self::T>
17    where
18        Self: 'a;
19
20    /// An iterator over the coordinates in this LineString
21    fn coords(&self) -> impl DoubleEndedIterator + ExactSizeIterator<Item = Self::CoordType<'_>> {
22        LineStringIterator::new(self, 0, self.num_coords())
23    }
24
25    /// The number of coordinates in this LineString
26    fn num_coords(&self) -> usize;
27
28    /// Access to a specified coordinate in this LineString
29    /// Will return None if the provided index is out of bounds
30    #[inline]
31    fn coord(&self, i: usize) -> Option<Self::CoordType<'_>> {
32        if i >= self.num_coords() {
33            None
34        } else {
35            unsafe { Some(self.coord_unchecked(i)) }
36        }
37    }
38
39    /// Access to a specified coordinate in this LineString
40    ///
41    /// # Safety
42    ///
43    /// Accessing an index out of bounds is UB.
44    unsafe fn coord_unchecked(&self, i: usize) -> Self::CoordType<'_>;
45}
46
47#[cfg(feature = "geo-types")]
48impl<T: CoordNum> LineStringTrait for LineString<T> {
49    type CoordType<'a>
50        = Coord<Self::T>
51    where
52        Self: 'a;
53
54    fn num_coords(&self) -> usize {
55        self.0.len()
56    }
57
58    unsafe fn coord_unchecked(&self, i: usize) -> Self::CoordType<'_> {
59        *self.0.get_unchecked(i)
60    }
61}
62
63#[cfg(feature = "geo-types")]
64impl<T: CoordNum> LineStringTrait for &'_ LineString<T> {
65    type CoordType<'b>
66        = Coord<Self::T>
67    where
68        Self: 'b;
69
70    fn num_coords(&self) -> usize {
71        self.0.len()
72    }
73
74    unsafe fn coord_unchecked(&self, i: usize) -> Self::CoordType<'_> {
75        *self.0.get_unchecked(i)
76    }
77}
78
79/// An empty struct that implements [LineStringTrait].
80///
81/// This can be used as the `LineStringType` of the `GeometryTrait` by implementations that don't
82/// have a LineString concept
83pub struct UnimplementedLineString<T>(PhantomData<T>);
84
85impl<T> LineStringTrait for UnimplementedLineString<T> {
86    type CoordType<'a>
87        = UnimplementedCoord<Self::T>
88    where
89        Self: 'a;
90
91    fn num_coords(&self) -> usize {
92        unimplemented!()
93    }
94
95    unsafe fn coord_unchecked(&self, _i: usize) -> Self::CoordType<'_> {
96        unimplemented!()
97    }
98}