parent
107b34bcbd
commit
1c509031d6
@ -0,0 +1,287 @@
|
||||
//! 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>
|
||||
{
|
||||
|
||||
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>
|
||||
{
|
||||
Box::new(self).downcast()
|
||||
}
|
||||
}
|
||||
|
||||
#[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),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in new issue