use core::ops::{Range, RangeFrom, RangeFull, RangeInclusive, RangeTo, RangeToInclusive};
mod impls;
const ONE: u8 = 1;
#[derive(Debug, Eq, PartialEq, Hash, Clone)]
pub struct IPv4ComponentRange {
start: Option<u8>,
end: Option<u8>,
}
impl From<u8> for IPv4ComponentRange {
fn from(n: u8) -> Self {
Self {
start: Some(n),
end: Some(n),
}
}
}
impl From<Range<u8>> for IPv4ComponentRange {
fn from(range: Range<u8>) -> Self {
Self {
start: Some(range.start),
end: range.end.checked_sub(ONE),
}
}
}
impl From<RangeFrom<u8>> for IPv4ComponentRange {
fn from(range: RangeFrom<u8>) -> Self {
Self {
start: Some(range.start),
end: Some(u8::max_value()),
}
}
}
impl From<RangeFull> for IPv4ComponentRange {
fn from(_: RangeFull) -> Self {
Self {
start: Some(u8::min_value()),
end: Some(u8::max_value()),
}
}
}
impl From<RangeInclusive<u8>> for IPv4ComponentRange {
fn from(range: RangeInclusive<u8>) -> Self {
Self {
start: Some(*range.start()),
end: Some(*range.end()),
}
}
}
impl From<RangeTo<u8>> for IPv4ComponentRange {
fn from(range: RangeTo<u8>) -> Self {
Self {
start: Some(u8::min_value()),
end: range.end.checked_sub(ONE),
}
}
}
impl From<RangeToInclusive<u8>> for IPv4ComponentRange {
fn from(range: RangeToInclusive<u8>) -> Self {
Self {
start: Some(u8::min_value()),
end: Some(range.end),
}
}
}
impl Iterator for IPv4ComponentRange {
type Item = u8;
fn next(&mut self) -> Option<Self::Item> {
match (self.start, self.end) {
(Some(start), Some(end)) if start <= end => {
self.start = start.checked_add(ONE);
Some(start)
},
_ => None,
}
}
fn nth(&mut self, mut n: usize) -> Option<Self::Item> {
while n > 0 {
match (self.start, self.end) {
(Some(start), Some(end)) => match end.checked_sub(start).map(|skip| usize::from(skip).min(n)) {
Some(skip) if skip > 0 => {
self.start = Some(start + skip as u8);
n -= skip;
},
_ => self.start = None,
},
_ => return None,
};
}
self.next()
}
#[cfg(not(target_pointer_width = "8"))]
fn size_hint(&self) -> (usize, Option<usize>) {
match (self.start, self.end) {
(Some(start), Some(end)) if end >= start => {
let result = usize::from(end - start);
match result.checked_add(ONE.into()) {
None => (result, None),
Some(result) => (result, Some(result)),
}
},
_ => (0, Some(0)),
}
}
}
#[cfg(not(target_pointer_width = "8"))]
impl ExactSizeIterator for IPv4ComponentRange {}
#[test]
fn test_iterator_nth() -> crate::Result<()> {
use alloc::vec::Vec;
for (range, size_hint, values) in [
(0..5, (5, Some(5)), (0_usize..=9).collect::<Vec<_>>()), (0..255, (255, Some(255)), (0..512).collect()),
] {
for n in values {
let mut ipv4_component_range = IPv4ComponentRange::from(range.clone());
assert_eq!(ipv4_component_range.size_hint(), size_hint);
assert_eq!(size_hint.0, ipv4_component_range.clone().count());
if n < range.end.into() {
assert_eq!(n, ipv4_component_range.nth(n).unwrap().into());
} else {
assert!(ipv4_component_range.nth(n).is_none());
assert!(ipv4_component_range.next().is_none());
}
}
}
for (range, size_hint, values) in [
(0..=5, (6, Some(6)), (0_usize..=9).collect::<Vec<_>>()), (0..=255, (256, Some(256)), (0..512).collect()),
] {
for n in values {
let mut ipv4_component_range = IPv4ComponentRange::from(range.clone());
assert_eq!(ipv4_component_range.size_hint(), size_hint);
assert_eq!(size_hint.0, ipv4_component_range.clone().count());
if n <= (*range.end()).into() {
assert_eq!(n, ipv4_component_range.nth(n).unwrap().into());
} else {
assert!(ipv4_component_range.nth(n).is_none());
assert!(ipv4_component_range.next().is_none());
}
}
}
Ok(())
}
#[test]
fn test_iterator() -> crate::Result<()> {
use core::str::FromStr;
for range in ["[1,0]", "(0,0)", "(0,1)"] {
assert_eq!(IPv4ComponentRange::from_str(range)?.count(), 0);
}
for (range, expected) in [("0", 0), ("1", 1), ("[0,0]", 0), ("(0,1]", 1), ("(1,3)", 2)] {
let mut range = IPv4ComponentRange::from_str(range)?;
assert_eq!(range.size_hint(), (1, Some(1)));
assert_eq!(range.nth(0), Some(expected));
assert_eq!(range.next(), None);
}
for (range, expected) in [
("(0,2)", None), ("(0,3)", Some(2)), ("(1,4)", Some(3)),
("[0,2]", Some(1)), ("[0,3]", Some(1)), ("[1,4]", Some(2)),
("[0,2)", Some(1)), ("[0,1)", None),
("(1,3]", Some(3)), ("(1,2]", None),
] {
let mut range = IPv4ComponentRange::from_str(range)?;
assert_eq!(range.nth(1), expected);
}
Ok(())
}