use crate::LatLng;
use core::{fmt, ops::Deref};
const MAX_BNDRY_VERTS: usize = 10;
#[derive(Clone, Copy, Debug, Eq, PartialEq, Default)]
pub struct Boundary {
points: [LatLng; MAX_BNDRY_VERTS],
count: u8,
}
impl Boundary {
#[must_use]
#[doc(hidden)]
pub fn new() -> Self {
Self::default()
}
#[doc(hidden)]
pub fn push(&mut self, ll: LatLng) {
self.points[usize::from(self.count)] = ll;
self.count += 1;
}
}
impl Deref for Boundary {
type Target = [LatLng];
fn deref(&self) -> &Self::Target {
&self.points[..self.count.into()]
}
}
impl fmt::Display for Boundary {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "[")?;
for (i, ll) in self.iter().enumerate() {
if i != 0 {
write!(f, "-")?;
}
write!(f, "{ll}")?;
}
write!(f, "]")
}
}
#[cfg(feature = "geo")]
impl From<Boundary> for geo::LineString {
fn from(value: Boundary) -> Self {
Self::new(value.iter().copied().map(geo::Coord::from).collect())
}
}
#[cfg(feature = "geo")]
impl geo_traits::GeometryTrait for Boundary {
type GeometryCollectionType<'b>
= geo_traits::UnimplementedGeometryCollection<f64>
where
Self: 'b;
type LineStringType<'b>
= Self
where
Self: 'b;
type LineType<'b>
= geo_traits::UnimplementedLine<f64>
where
Self: 'b;
type MultiLineStringType<'b>
= geo_traits::UnimplementedMultiLineString<f64>
where
Self: 'b;
type MultiPointType<'b>
= geo_traits::UnimplementedMultiPoint<f64>
where
Self: 'b;
type MultiPolygonType<'b>
= geo_traits::UnimplementedMultiPolygon<f64>
where
Self: 'b;
type PointType<'b>
= geo_traits::UnimplementedPoint<f64>
where
Self: 'b;
type PolygonType<'b>
= Self
where
Self: 'b;
type RectType<'b>
= geo_traits::UnimplementedRect<f64>
where
Self: 'b;
type T = f64;
type TriangleType<'b>
= geo_traits::UnimplementedTriangle<f64>
where
Self: 'b;
fn dim(&self) -> geo_traits::Dimensions {
geo_traits::Dimensions::Xy
}
fn as_type(
&self,
) -> geo_traits::GeometryType<
'_,
Self::PointType<'_>,
Self::LineStringType<'_>,
Self::PolygonType<'_>,
Self::MultiPointType<'_>,
Self::MultiLineStringType<'_>,
Self::MultiPolygonType<'_>,
Self::GeometryCollectionType<'_>,
Self::RectType<'_>,
Self::TriangleType<'_>,
Self::LineType<'_>,
> {
if self.count >= crate::NUM_PENT_VERTS {
geo_traits::GeometryType::Polygon(self)
} else {
geo_traits::GeometryType::LineString(self)
}
}
}
#[cfg(feature = "geo")]
impl geo_traits::LineStringTrait for Boundary {
type CoordType<'a> = LatLng;
fn num_coords(&self) -> usize {
if self.count >= crate::NUM_PENT_VERTS {
self.count + 1
} else {
self.count
}
.into()
}
#[expect(unsafe_code, reason = "precondition must be held by the caller")]
unsafe fn coord_unchecked(&self, i: usize) -> Self::CoordType<'_> {
if i == usize::from(self.count) {
unsafe { *self.get_unchecked(0) }
} else {
unsafe { *self.get_unchecked(i) }
}
}
}
#[cfg(feature = "geo")]
impl geo_traits::PolygonTrait for Boundary {
type RingType<'a>
= Self
where
Self: 'a;
fn exterior(&self) -> Option<Self::RingType<'_>> {
(self.count >= crate::NUM_PENT_VERTS).then_some(*self)
}
fn num_interiors(&self) -> usize {
0
}
#[expect(unsafe_code, reason = "always panic, it's safe")]
unsafe fn interior_unchecked(&self, _i: usize) -> Self::RingType<'_> {
unreachable!("Boundary has no interior rings")
}
}