use core::fmt::{self, Display, Formatter};
use core::iter::FusedIterator;
use core::marker::PhantomData;
use core::ops::Range;
use crate::location::{Column, Component, Location, LocationLike, Row};
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct ComponentRange<C: Component> {
range: Range<isize>,
phanton: PhantomData<C>,
}
impl<C: Component> ComponentRange<C> {
#[inline]
pub fn bounded(start: C, end: C) -> Self {
ComponentRange {
phanton: PhantomData,
range: start.value()..end.value(),
}
}
#[inline]
pub fn span(start: C, size: C::Distance) -> Self {
Self::bounded(start, start.add_distance(size))
}
#[inline]
pub fn start(&self) -> C {
self.range.start.into()
}
#[inline]
pub fn end(&self) -> C {
self.range.end.into()
}
#[inline]
pub fn size(&self) -> C::Distance {
self.start().distance_to(self.end())
}
pub fn check(&self, idx: impl Into<C>) -> Result<C, RangeError<C>> {
let idx = idx.into();
let min = self.start();
let max = self.end();
if idx < min {
Err(RangeError::TooLow(min))
} else if idx >= max {
Err(RangeError::TooHigh(max))
} else {
Ok(idx)
}
}
#[inline]
pub fn in_bounds(&self, loc: impl Into<C>) -> bool {
self.check(loc).is_ok()
}
pub fn cross(self, index: C::Converse) -> LocationRange<C::Converse> {
LocationRange::new(index, self)
}
}
impl<C: Component> Iterator for ComponentRange<C> {
type Item = C;
#[inline]
fn next(&mut self) -> Option<C> {
self.range.next().map(C::from)
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.range.size_hint()
}
#[inline]
fn nth(&mut self, n: usize) -> Option<C> {
self.range.nth(n).map(C::from)
}
#[inline]
fn last(mut self) -> Option<C> {
self.next_back()
}
}
impl<C: Component> DoubleEndedIterator for ComponentRange<C> {
#[inline]
fn next_back(&mut self) -> Option<C> {
self.range.next_back().map(C::from)
}
}
impl<C: Component> ExactSizeIterator for ComponentRange<C> {}
impl<C: Component> FusedIterator for ComponentRange<C> {}
pub type RowRange = ComponentRange<Row>;
pub type ColumnRange = ComponentRange<Column>;
#[derive(Debug, Copy, Clone, PartialEq, Eq)]
pub enum RangeError<T: Component> {
TooLow(T),
TooHigh(T),
}
impl<T: Component> Display for RangeError<T> {
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
match self {
RangeError::TooLow(min) => write!(f, "{} too low, must be >= {:?}", T::name(), min),
RangeError::TooHigh(max) => write!(f, "{} too high, must be < {:?}", T::name(), max),
}
}
}
pub type RowRangeError = RangeError<Row>;
pub type ColumnRangeError = RangeError<Column>;
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
pub struct LocationRange<C: Component> {
index: C,
range: ComponentRange<C::Converse>,
}
impl<C: Component> LocationRange<C> {
#[inline]
#[must_use]
pub fn new(index: C, range: ComponentRange<C::Converse>) -> Self {
LocationRange { index, range }
}
#[inline]
#[must_use]
pub fn bounded(index: C, start: C::Converse, end: C::Converse) -> Self {
Self::new(index, ComponentRange::bounded(start, end))
}
#[inline]
#[must_use]
pub fn span(index: C, start: C::Converse, size: <C::Converse as Component>::Distance) -> Self {
Self::bounded(index, start, start.add_distance(size))
}
#[inline]
#[must_use]
pub fn rooted(root: Location, size: <C::Converse as Component>::Distance) -> Self {
Self::span(root.get_component(), root.get_component(), size)
}
#[inline]
#[must_use]
pub fn component_range(&self) -> ComponentRange<C::Converse> {
self.range.clone()
}
#[inline]
#[must_use]
pub fn index(&self) -> C {
self.index
}
#[inline]
#[must_use]
pub fn start(&self) -> Location {
self.range.start().combine(self.index)
}
#[inline]
#[must_use]
pub fn end(&self) -> Location {
self.range.end().combine(self.index)
}
#[inline]
#[must_use]
pub fn size(&self) -> <C::Converse as Component>::Distance {
self.range.start().distance_to(self.range.end())
}
}
impl LocationRange<Row> {
#[inline]
#[must_use]
pub fn row(&self) -> Row {
self.index
}
#[inline]
#[must_use]
pub fn columns(&self) -> ColumnRange {
self.component_range()
}
}
impl LocationRange<Column> {
#[inline]
#[must_use]
pub fn column(&self) -> Column {
self.index
}
#[inline]
#[must_use]
pub fn rows(&self) -> RowRange {
self.component_range()
}
}
impl<C: Component> Iterator for LocationRange<C> {
type Item = Location;
#[inline]
fn next(&mut self) -> Option<Location> {
self.range
.next()
.map(move |cross| cross.combine(self.index))
}
#[inline]
fn size_hint(&self) -> (usize, Option<usize>) {
self.range.size_hint()
}
#[inline]
fn nth(&mut self, n: usize) -> Option<Location> {
self.range
.nth(n)
.map(move |cross| cross.combine(self.index))
}
#[inline]
fn last(self) -> Option<Location> {
let index = self.index;
self.range.last().map(move |cross| cross.combine(index))
}
}
impl<C: Component> DoubleEndedIterator for LocationRange<C> {
fn next_back(&mut self) -> Option<Self::Item> {
self.range
.next_back()
.map(move |cross| cross.combine(self.index))
}
}
impl<C: Component> FusedIterator for LocationRange<C> {}
impl<C: Component> ExactSizeIterator for LocationRange<C> {}