use std::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
pub trait Repeat {
unsafe fn validate(&self, repeated: usize) -> bool;
fn accept(&self, repeated: usize) -> bool;
}
impl Repeat for usize {
#[inline]
unsafe fn validate(&self, repeated: usize) -> bool {
repeated < *self
}
#[inline]
fn accept(&self, repeated: usize) -> bool {
repeated == *self
}
}
impl Repeat for Range<usize> {
#[inline]
unsafe fn validate(&self, repeated: usize) -> bool {
debug_assert!(self.end >= repeated);
self.end.unchecked_sub(repeated) > 1
}
#[inline]
fn accept(&self, repeated: usize) -> bool {
self.contains(&repeated)
}
}
impl Repeat for RangeFrom<usize> {
#[inline]
unsafe fn validate(&self, _: usize) -> bool {
true
}
#[inline]
fn accept(&self, repeated: usize) -> bool {
self.contains(&repeated)
}
}
impl Repeat for RangeFull {
#[inline]
unsafe fn validate(&self, _: usize) -> bool {
true
}
#[inline]
fn accept(&self, _: usize) -> bool {
true
}
}
impl Repeat for RangeInclusive<usize> {
#[inline]
unsafe fn validate(&self, repeated: usize) -> bool {
repeated < *self.end()
}
#[inline]
fn accept(&self, repeated: usize) -> bool {
self.contains(&repeated)
}
}
impl Repeat for RangeTo<usize> {
#[inline]
unsafe fn validate(&self, repeated: usize) -> bool {
debug_assert!(self.end >= repeated);
self.end.unchecked_sub(repeated) > 1
}
#[inline]
fn accept(&self, repeated: usize) -> bool {
self.contains(&repeated)
}
}
impl Repeat for RangeToInclusive<usize> {
#[inline]
unsafe fn validate(&self, repeated: usize) -> bool {
repeated < self.end
}
#[inline]
fn accept(&self, repeated: usize) -> bool {
self.contains(&repeated)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn repeat_usize() {
assert_eq!(unsafe { 0.validate(0) }, false);
assert_eq!(unsafe { 0.validate(1) }, false);
assert_eq!(0.accept(0), true);
assert_eq!(0.accept(1), false);
assert_eq!(unsafe { 1.validate(0) }, true);
assert_eq!(unsafe { 1.validate(1) }, false);
assert_eq!(unsafe { 1.validate(2) }, false);
assert_eq!(1.accept(0), false);
assert_eq!(1.accept(1), true);
assert_eq!(1.accept(2), false);
}
#[test]
fn repeat_range() {
assert_eq!(unsafe { (1..3).validate(0) }, true);
assert_eq!(unsafe { (1..3).validate(1) }, true);
assert_eq!(unsafe { (1..3).validate(2) }, false);
assert_eq!(unsafe { (1..3).validate(3) }, false);
assert_eq!((1..3).accept(0), false);
assert_eq!((1..3).accept(1), true);
assert_eq!((1..3).accept(2), true);
assert_eq!((1..3).accept(3), false);
assert_eq!((1..3).accept(4), false);
}
#[test]
#[should_panic]
fn repeat_range_overflow() {
unsafe { (1..3).validate(4) };
}
#[test]
fn repeat_range_from() {
assert_eq!(unsafe { (1..).validate(0) }, true);
assert_eq!(unsafe { (1..).validate(1) }, true);
assert_eq!(unsafe { (1..).validate(2) }, true);
assert_eq!(unsafe { (1..).validate(3) }, true);
assert_eq!(unsafe { (1..).validate(4) }, true);
assert_eq!((1..).accept(0), false);
assert_eq!((1..).accept(1), true);
assert_eq!((1..).accept(2), true);
assert_eq!((1..).accept(3), true);
assert_eq!((1..).accept(4), true);
}
#[test]
fn repeat_range_full() {
assert_eq!(unsafe { (..).validate(0) }, true);
assert_eq!(unsafe { (..).validate(1) }, true);
assert_eq!(unsafe { (..).validate(2) }, true);
assert_eq!(unsafe { (..).validate(3) }, true);
assert_eq!(unsafe { (..).validate(4) }, true);
assert_eq!((..).accept(0), true);
assert_eq!((..).accept(1), true);
assert_eq!((..).accept(2), true);
assert_eq!((..).accept(3), true);
assert_eq!((..).accept(4), true);
}
#[test]
fn repeat_range_inclusive() {
assert_eq!(unsafe { (1..=3).validate(0) }, true);
assert_eq!(unsafe { (1..=3).validate(1) }, true);
assert_eq!(unsafe { (1..=3).validate(2) }, true);
assert_eq!(unsafe { (1..=3).validate(3) }, false);
assert_eq!(unsafe { (1..=3).validate(4) }, false);
assert_eq!((1..=3).accept(0), false);
assert_eq!((1..=3).accept(1), true);
assert_eq!((1..=3).accept(2), true);
assert_eq!((1..=3).accept(3), true);
assert_eq!((1..=3).accept(4), false);
}
#[test]
fn repeat_range_to() {
assert_eq!(unsafe { (..3).validate(0) }, true);
assert_eq!(unsafe { (..3).validate(1) }, true);
assert_eq!(unsafe { (..3).validate(2) }, false);
assert_eq!(unsafe { (..3).validate(3) }, false);
assert_eq!((..3).accept(0), true);
assert_eq!((..3).accept(1), true);
assert_eq!((..3).accept(2), true);
assert_eq!((..3).accept(3), false);
assert_eq!((..3).accept(4), false);
}
#[test]
#[should_panic]
fn repeat_range_to_overflow() {
unsafe { (..3).validate(4) };
}
#[test]
fn repeat_range_to_inclusive() {
assert_eq!(unsafe { (..=3).validate(0) }, true);
assert_eq!(unsafe { (..=3).validate(1) }, true);
assert_eq!(unsafe { (..=3).validate(2) }, true);
assert_eq!(unsafe { (..=3).validate(3) }, false);
assert_eq!(unsafe { (..=3).validate(4) }, false);
assert_eq!((..=3).accept(0), true);
assert_eq!((..=3).accept(1), true);
assert_eq!((..=3).accept(2), true);
assert_eq!((..=3).accept(3), true);
assert_eq!((..=3).accept(4), false);
}
}