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