use std::cmp::Ordering;
use std::fmt::Debug;
pub trait CheckedAddSub: Copy + Clone + Debug {
type Arithmetic: Copy + Clone + Debug;
fn checked_add(self, rhs: Self::Arithmetic) -> Option<Self>;
fn checked_sub(self, rhs: Self::Arithmetic) -> Option<Self>;
}
pub trait SequenceItem: Copy + Clone + Debug {
type Arithmetic: Copy + Clone + Debug;
type Proxy: Ord
+ Copy
+ Clone
+ From<Self>
+ TryInto<Self>
+ CheckedAddSub<Arithmetic = Self::Arithmetic>;
}
impl CheckedAddSub for isize {
type Arithmetic = usize;
fn checked_add(self, rhs: Self::Arithmetic) -> Option<Self> {
self.checked_add_unsigned(rhs)
}
fn checked_sub(self, rhs: Self::Arithmetic) -> Option<Self> {
self.checked_sub_unsigned(rhs)
}
}
impl CheckedAddSub for i64 {
type Arithmetic = u64;
fn checked_add(self, rhs: Self::Arithmetic) -> Option<Self> {
self.checked_add_unsigned(rhs)
}
fn checked_sub(self, rhs: Self::Arithmetic) -> Option<Self> {
self.checked_sub_unsigned(rhs)
}
}
impl CheckedAddSub for i32 {
type Arithmetic = u32;
fn checked_add(self, rhs: Self::Arithmetic) -> Option<Self> {
self.checked_add_unsigned(rhs)
}
fn checked_sub(self, rhs: Self::Arithmetic) -> Option<Self> {
self.checked_sub_unsigned(rhs)
}
}
impl CheckedAddSub for i16 {
type Arithmetic = u16;
fn checked_add(self, rhs: Self::Arithmetic) -> Option<Self> {
self.checked_add_unsigned(rhs)
}
fn checked_sub(self, rhs: Self::Arithmetic) -> Option<Self> {
self.checked_sub_unsigned(rhs)
}
}
impl CheckedAddSub for i8 {
type Arithmetic = u8;
fn checked_add(self, rhs: Self::Arithmetic) -> Option<Self> {
self.checked_add_unsigned(rhs)
}
fn checked_sub(self, rhs: Self::Arithmetic) -> Option<Self> {
self.checked_sub_unsigned(rhs)
}
}
impl CheckedAddSub for usize {
type Arithmetic = usize;
fn checked_add(self, rhs: Self::Arithmetic) -> Option<Self> {
self.checked_add(rhs)
}
fn checked_sub(self, rhs: Self::Arithmetic) -> Option<Self> {
self.checked_sub(rhs)
}
}
impl CheckedAddSub for u64 {
type Arithmetic = u64;
fn checked_add(self, rhs: Self::Arithmetic) -> Option<Self> {
self.checked_add(rhs)
}
fn checked_sub(self, rhs: Self::Arithmetic) -> Option<Self> {
self.checked_sub(rhs)
}
}
impl CheckedAddSub for u32 {
type Arithmetic = u32;
fn checked_add(self, rhs: Self::Arithmetic) -> Option<Self> {
self.checked_add(rhs)
}
fn checked_sub(self, rhs: Self::Arithmetic) -> Option<Self> {
self.checked_sub(rhs)
}
}
impl CheckedAddSub for u16 {
type Arithmetic = u16;
fn checked_add(self, rhs: Self::Arithmetic) -> Option<Self> {
self.checked_add(rhs)
}
fn checked_sub(self, rhs: Self::Arithmetic) -> Option<Self> {
self.checked_sub(rhs)
}
}
impl CheckedAddSub for u8 {
type Arithmetic = u8;
fn checked_add(self, rhs: Self::Arithmetic) -> Option<Self> {
self.checked_add(rhs)
}
fn checked_sub(self, rhs: Self::Arithmetic) -> Option<Self> {
self.checked_sub(rhs)
}
}
impl SequenceItem for char {
type Arithmetic = u32;
type Proxy = u32;
}
impl SequenceItem for isize {
type Arithmetic = usize;
type Proxy = isize;
}
impl SequenceItem for i64 {
type Arithmetic = u64;
type Proxy = i64;
}
impl SequenceItem for i32 {
type Arithmetic = u32;
type Proxy = i32;
}
impl SequenceItem for i16 {
type Arithmetic = u16;
type Proxy = i16;
}
impl SequenceItem for i8 {
type Arithmetic = u8;
type Proxy = i8;
}
impl SequenceItem for usize {
type Arithmetic = usize;
type Proxy = usize;
}
impl SequenceItem for u64 {
type Arithmetic = u64;
type Proxy = u64;
}
impl SequenceItem for u32 {
type Arithmetic = u32;
type Proxy = u32;
}
impl SequenceItem for u16 {
type Arithmetic = u16;
type Proxy = u16;
}
impl SequenceItem for u8 {
type Arithmetic = u8;
type Proxy = u8;
}
#[derive(Copy, Clone, Debug)]
pub struct Sequence<T>
where
T: SequenceItem,
{
pub start: T,
pub end: T,
pub incr: T::Arithmetic,
}
#[derive(Copy, Clone, Debug)]
pub struct SequenceIterator<T>
where
T: SequenceItem,
{
next: Option<T::Proxy>,
end: T::Proxy,
incr: T::Arithmetic,
}
impl<T> IntoIterator for Sequence<T>
where
T: SequenceItem,
{
type Item = Result<T, <T::Proxy as TryInto<T>>::Error>;
type IntoIter = SequenceIterator<T>;
fn into_iter(self) -> Self::IntoIter {
SequenceIterator {
next: Some(self.start.into()),
end: self.end.into(),
incr: self.incr,
}
}
}
impl<T> Iterator for SequenceIterator<T>
where
T: SequenceItem,
{
type Item = Result<T, <T::Proxy as TryInto<T>>::Error>;
fn next(&mut self) -> Option<Self::Item> {
let next = self.next;
if let Some(next) = next {
self.next = match next.cmp(&self.end) {
Ordering::Less => {
next.checked_add(self.incr).filter(|next| next <= &self.end)
}
Ordering::Equal => None,
Ordering::Greater => {
next.checked_sub(self.incr).filter(|next| next >= &self.end)
}
};
}
next.map(TryInto::try_into)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_integers() {
let sequence = Sequence {
start: 1i64,
end: 10i64,
incr: 1,
};
let values: Result<Vec<_>, _> = sequence.into_iter().collect();
assert_eq!(&values.unwrap(), &[1i64, 2, 3, 4, 5, 6, 7, 8, 9, 10]);
}
#[test]
fn test_integers_incr() {
let sequence = Sequence {
start: 1i64,
end: 10i64,
incr: 2,
};
let values: Result<Vec<_>, _> = sequence.into_iter().collect();
assert_eq!(&values.unwrap(), &[1i64, 3, 5, 7, 9]);
}
#[test]
fn test_integers_rev() {
let sequence = Sequence {
start: 10i64,
end: 1i64,
incr: 1,
};
let values: Result<Vec<_>, _> = sequence.into_iter().collect();
assert_eq!(&values.unwrap(), &[10i64, 9, 8, 7, 6, 5, 4, 3, 2, 1]);
}
#[test]
fn test_integers_rev_incr() {
let sequence = Sequence {
start: 10i64,
end: 1i64,
incr: 2,
};
let values: Result<Vec<_>, _> = sequence.into_iter().collect();
assert_eq!(&values.unwrap(), &[10i64, 8, 6, 4, 2]);
}
#[test]
fn test_characters() {
let sequence = Sequence {
start: 'a',
end: 'f',
incr: 1,
};
let values: Result<Vec<_>, _> = sequence.into_iter().collect();
assert_eq!(&values.unwrap(), &['a', 'b', 'c', 'd', 'e', 'f']);
}
#[test]
fn test_characters_illegal() {
let sequence = Sequence {
start: '\u{D7FF}',
end: '\u{E000}',
incr: 1,
};
let values: Result<Vec<_>, _> = sequence.into_iter().collect();
assert!(&values.is_err());
}
#[test]
fn test_characters_skip_surrogate() {
let sequence = Sequence {
start: '\u{D000}',
end: '\u{10001}',
incr: 0x1000,
};
let values: Result<Vec<_>, _> = sequence.into_iter().collect();
assert_eq!(
&values.unwrap(),
&['\u{D000}', '\u{E000}', '\u{F000}', '\u{10000}']
);
}
#[test]
fn test_characters_incr() {
let sequence = Sequence {
start: 'a',
end: 'f',
incr: 2,
};
let values: Result<Vec<_>, _> = sequence.into_iter().collect();
assert_eq!(&values.unwrap(), &['a', 'c', 'e']);
}
#[test]
fn test_characters_rev() {
let sequence = Sequence {
start: 'f',
end: 'a',
incr: 1,
};
let values: Result<Vec<_>, _> = sequence.into_iter().collect();
assert_eq!(&values.unwrap(), &['f', 'e', 'd', 'c', 'b', 'a']);
}
#[test]
fn test_characters_rev_incr() {
let sequence = Sequence {
start: 'f',
end: 'a',
incr: 2,
};
let values: Result<Vec<_>, _> = sequence.into_iter().collect();
assert_eq!(&values.unwrap(), &['f', 'd', 'b']);
}
}