You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
297 lines
7.1 KiB
297 lines
7.1 KiB
//! Workarounds for ridiculously janky `std::ops::Range*` polymorphism
|
|
use super::*;
|
|
use std::{
|
|
ops::{
|
|
Range,
|
|
RangeFrom,
|
|
RangeInclusive,
|
|
RangeTo,
|
|
RangeToInclusive,
|
|
RangeFull,
|
|
|
|
Bound,
|
|
RangeBounds,
|
|
},
|
|
str::{
|
|
FromStr,
|
|
},
|
|
fmt,
|
|
error,
|
|
};
|
|
|
|
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
|
pub enum DynRange<T>
|
|
{
|
|
Range(Range<T>),
|
|
From(RangeFrom<T>),
|
|
Inclusive(RangeInclusive<T>),
|
|
To(RangeTo<T>),
|
|
ToInclusive(RangeToInclusive<T>),
|
|
Full(RangeFull),
|
|
}
|
|
|
|
#[macro_export] macro_rules! impl_from {
|
|
(Full, RangeFull) => {
|
|
impl<T> From<RangeFull> for DynRange<T>
|
|
{
|
|
#[inline] fn from(from: RangeFull) -> Self
|
|
{
|
|
Self::Full(from)
|
|
}
|
|
}
|
|
};
|
|
($name:ident, $range:tt) => {
|
|
|
|
impl<T> From<$range <T>> for DynRange<T>
|
|
{
|
|
#[inline] fn from(from: $range<T>) -> Self
|
|
{
|
|
Self::$name(from)
|
|
}
|
|
}
|
|
};
|
|
}
|
|
|
|
impl_from!(Range, Range);
|
|
impl_from!(From, RangeFrom);
|
|
impl_from!(Inclusive, RangeInclusive);
|
|
impl_from!(To, RangeTo);
|
|
impl_from!(ToInclusive, RangeToInclusive);
|
|
impl_from!(Full, RangeFull);
|
|
|
|
macro_rules! bounds {
|
|
($self:ident, $bound:ident) => {
|
|
match $self {
|
|
DynRange::Range(from) => from.$bound(),
|
|
DynRange::From(from) => from.$bound(),
|
|
DynRange::Inclusive(i) => i.$bound(),
|
|
DynRange::To(i) => i.$bound(),
|
|
DynRange::ToInclusive(i) => i.$bound(),
|
|
DynRange::Full(_) => (..).$bound(),
|
|
}
|
|
};
|
|
}
|
|
|
|
impl<T> RangeBounds<T> for DynRange<T>
|
|
{
|
|
fn start_bound(&self) -> Bound<&T> {
|
|
bounds!(self, start_bound)
|
|
}
|
|
fn end_bound(&self) -> Bound<&T> {
|
|
bounds!(self, end_bound)
|
|
}
|
|
}
|
|
|
|
impl<'a, T> RangeBounds<T> for &'a DynRange<T>
|
|
{
|
|
fn start_bound(&self) -> Bound<&T> {
|
|
bounds!(self, start_bound)
|
|
}
|
|
fn end_bound(&self) -> Bound<&T> {
|
|
bounds!(self, end_bound)
|
|
}
|
|
}
|
|
|
|
impl<T: fmt::Display> fmt::Display for DynRange<T>
|
|
{
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
|
{
|
|
match self {
|
|
Self::Range(from) => write!(f, "{}..{}", from.start, from.end),
|
|
Self::From(from) => write!(f, "{}..", from.start),
|
|
Self::Inclusive(from) => write!(f, "{}..={}", from.start(), from.end()),
|
|
Self::To(from) => write!(f, "..{}", from.end),
|
|
Self::ToInclusive(from) => write!(f, "..={}", from.end),
|
|
Self::Full(_) => write!(f, ".."),
|
|
}
|
|
}
|
|
}
|
|
|
|
use std::any::{
|
|
Any,
|
|
};
|
|
|
|
impl<T: 'static> DynRange<T>
|
|
{
|
|
#[inline]
|
|
pub fn into_boxed(self) -> Box<dyn Any /*TODO: + Send + Sync */+ 'static>
|
|
{
|
|
self.into_inner()
|
|
}
|
|
fn into_inner(self) -> Box<dyn Any + 'static>
|
|
{
|
|
match self {
|
|
Self::Range(from) => Box::new(from),
|
|
Self::From(from) => Box::new(from),
|
|
Self::Inclusive(from) => Box::new(from),
|
|
Self::To(from) => Box::new(from),
|
|
Self::ToInclusive(from) => Box::new(from),
|
|
Self::Full(_) => Box::new(..),
|
|
}
|
|
}
|
|
fn inner_mut(&mut self) -> &mut dyn Any
|
|
{
|
|
match self {
|
|
Self::Range(from) => from,
|
|
Self::From(from) => from,
|
|
Self::Inclusive(from) => from,
|
|
Self::To(from) => from,
|
|
Self::ToInclusive(from) => from,
|
|
Self::Full(f) => f,
|
|
}
|
|
}
|
|
fn inner_ref(&self) -> &dyn Any
|
|
{
|
|
match self {
|
|
Self::Range(from) => from,
|
|
Self::From(from) => from,
|
|
Self::Inclusive(from) => from,
|
|
Self::To(from) => from,
|
|
Self::ToInclusive(from) => from,
|
|
Self::Full(_) => &(..),
|
|
}
|
|
}
|
|
pub fn downcast_ref<R: RangeBounds<T> + 'static>(&self) -> Option<&R>
|
|
{
|
|
self.inner_ref().downcast_ref()
|
|
}
|
|
pub fn downcast_mut<R: RangeBounds<T> + 'static>(&mut self) -> Option<&mut R>
|
|
{
|
|
self.inner_mut().downcast_mut()
|
|
}
|
|
pub fn downcast<R: RangeBounds<T> + 'static>(self) -> Result<R, Self>
|
|
{
|
|
self.into_inner().downcast::<R>()
|
|
.map(|x| *x)
|
|
.map_err(|b| {
|
|
todo!("make this bullshit properly unboxable ehh...")
|
|
})
|
|
//Box::<(dyn std::any::Any + 'static)>::downcast(Box::new(self)).map_ok(|ok| *ok)
|
|
}
|
|
}
|
|
|
|
#[derive(Debug)]
|
|
pub struct ParseError(DynRange<()>, Option<Box<dyn error::Error+'static>>);
|
|
|
|
impl ParseError
|
|
{
|
|
fn new<R: Into<DynRange<()>>>(which: R, err: impl error::Error + 'static) -> Self
|
|
{
|
|
Self(which.into(), Some(Box::new(err)))
|
|
}
|
|
fn none(which: impl Into<DynRange<()>>) -> Self
|
|
{
|
|
Self(which.into(), None)
|
|
}
|
|
fn map<T: Into<DynRange<()>>>(self, to: T) -> Self
|
|
{
|
|
Self (to.into(), self.1)
|
|
}
|
|
}
|
|
|
|
impl error::Error for ParseError
|
|
{
|
|
fn source(&self) -> Option<&(dyn error::Error + 'static)> {
|
|
if let Some(this) = self.1.as_ref() {
|
|
Some(this.as_ref())
|
|
} else {
|
|
None
|
|
}
|
|
}
|
|
}
|
|
|
|
impl fmt::Display for ParseError
|
|
{
|
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
|
{
|
|
write!(f, "failed to parse range in format `{:?}`", self.0)?;
|
|
if let Some(this) = self.1.as_ref() {
|
|
write!(f, ": {}", this)?;
|
|
}
|
|
Ok(())
|
|
}
|
|
}
|
|
|
|
|
|
impl<T: FromStr> FromStr for DynRange<T>
|
|
where T::Err: error::Error + 'static
|
|
{
|
|
type Err = ParseError;
|
|
fn from_str(s: &str) -> Result<Self, Self::Err> {
|
|
if s== ".." {
|
|
Ok(Self::Full(..))
|
|
} else if s.starts_with("..=") {
|
|
Ok(Self::ToInclusive(..=T::from_str(&s[3..]).map_err(|x| ParseError::new(..=(), x))?))
|
|
} else if s.starts_with("..") {
|
|
Ok(Self::To(..(T::from_str(&s[2..])).map_err(|x| ParseError::new(..(), x))?))
|
|
} else if s.ends_with("..") {
|
|
Ok(Self::From(T::from_str(&s[..s.len()-2]).map_err(|x| ParseError::new(().., x))?..))
|
|
} else {
|
|
fn try_next_incl<'a, T: FromStr>(m: &mut impl Iterator<Item=&'a str>) -> Result<RangeInclusive<T>, ParseError>
|
|
where T::Err: error::Error + 'static
|
|
{
|
|
let (first, second) = if let Some(first) = m.next() {
|
|
if let Some(seocond) = m.next() {
|
|
(first,seocond)
|
|
} else {
|
|
return Err(ParseError::none(()..=()));
|
|
}
|
|
} else {
|
|
return Err(ParseError::none(()..=()));
|
|
};
|
|
|
|
let first: T = first.parse().map_err(|x| ParseError::new(()..=(), x))?;
|
|
let second: T = second.parse().map_err(|x| ParseError::new(()..=(), x))?;
|
|
|
|
Ok(first..=second)
|
|
}
|
|
|
|
fn try_next<'a, T: FromStr>(m: &mut impl Iterator<Item=&'a str>) -> Result<Range<T>, ParseError>
|
|
where T::Err: error::Error + 'static
|
|
{
|
|
let (first, second) = if let Some(first) = m.next() {
|
|
if let Some(seocond) = m.next() {
|
|
(first,seocond)
|
|
} else {
|
|
return Err(ParseError::none(()..()));
|
|
}
|
|
} else {
|
|
return Err(ParseError::none(()..()));
|
|
};
|
|
|
|
let first: T = first.parse().map_err(|x| ParseError::new(()..(), x))?;
|
|
let second: T = second.parse().map_err(|x| ParseError::new(()..(), x))?;
|
|
|
|
Ok(first..second)
|
|
}
|
|
|
|
|
|
let mut split = s.split("..=").fuse();
|
|
|
|
let mut last_err = ParseError::none(()..());
|
|
match loop {
|
|
match try_next_incl(&mut split) {
|
|
Err(ParseError(_, None)) => break Err(last_err), // iter empty
|
|
Err(other) => last_err = other,
|
|
Ok(value) => break Ok(Self::Inclusive(value)),
|
|
}
|
|
} {
|
|
Ok(v) => return Ok(v),
|
|
Err(e) => last_err = e,
|
|
};
|
|
|
|
let mut split = s.split("..").fuse();
|
|
match loop {
|
|
match try_next(&mut split) {
|
|
Err(ParseError(_, None)) => break Err(last_err), // iter empty
|
|
Err(other) => last_err = other,
|
|
Ok(value) => break Ok(Self::Range(value)),
|
|
}
|
|
} {
|
|
Ok(v) => Ok(v),
|
|
Err(e) => Err(e),
|
|
}
|
|
}
|
|
}
|
|
}
|