// License: see LICENSE file at root directory of `master` branch

//! # IPv4 range iter

#![cfg(feature="iter")]

use {
    alloc::vec::Vec,
    core::cell::RefCell,
    std::net::IpAddr,

    perm::PermIter,

    super::{Component, IPv4Range},
};

#[cfg(test)]
use {
    alloc::string::ToString,
};

/// # IPv4 range iter
///
/// ## Examples
///
/// ```
/// use {
///     core::{
///         cell::RefCell,
///         str::FromStr,
///     },
///     std::net::IpAddr,
///     dia_ip_range::{IPv4Range, IPv4RangeIter},
/// };
///
/// let output_buffer = RefCell::new(Vec::with_capacity(4));
/// let mut iter = IPv4RangeIter::new(
///     IPv4Range::from_str("10.0.0.[2,9]")?,
///     &output_buffer,
/// );
/// for sample in vec![
///     [10, 0, 0, 2], [10, 0, 0, 3], [10, 0, 0, 4], [10, 0, 0, 5],
///     [10, 0, 0, 6], [10, 0, 0, 7], [10, 0, 0, 8], [10, 0, 0, 9],
/// ] {
///     assert_eq!(iter.next().unwrap(), IpAddr::from(sample));
/// }
/// assert!(iter.next().is_none());
///
/// # Ok::<_, dia_ip_range::Error>(())
/// ```
#[derive(Debug, Eq, PartialEq, Hash)]
pub struct IPv4RangeIter<'a> {
    iter: PermIter<'a, Component>,
}

impl<'a> IPv4RangeIter<'a> {

    /// # Makes new instance
    ///
    /// Output buffer is used for better performance.
    ///
    /// ## Panics
    ///
    /// If you mutably borrow the output buffer while this instance already did that, it panics.
    pub fn new(ip_v4_range: IPv4Range, output_buffer: &'a RefCell<Vec<u8>>) -> Self {
        Self {
            iter: PermIter::new(
                alloc::vec![
                    ip_v4_range.a,
                    ip_v4_range.b,
                    ip_v4_range.c,
                    ip_v4_range.d,
                ],
                output_buffer,
            ),
        }
    }

}

impl Iterator for IPv4RangeIter<'_> {

    type Item = IpAddr;

    fn next(&mut self) -> Option<Self::Item> {
        self.iter.next().map(|d| IpAddr::from([d[0], d[1], d[2], d[3]]))
    }

}

#[test]
fn test_ip_range_iters() -> crate::Result<()> {
    let output_buffer = RefCell::new(Vec::with_capacity(4));
    let mut iter = IPv4RangeIter::new(
        IPv4Range {
            a: Component::new(192, 192),
            b: Component::new(168, 168),
            c: Component::new(0, 2),
            d: Component::new(0, 2),
        },
        &output_buffer,
    );
    for s in &[
        "192.168.0.0", "192.168.1.0", "192.168.2.0",
        "192.168.0.1", "192.168.1.1", "192.168.2.1",
        "192.168.0.2", "192.168.1.2", "192.168.2.2",
    ] {
        assert_eq!(iter.next().unwrap().to_string(), *s);
    }
    assert!(iter.next().is_none());

    let output_buffer = RefCell::new(Vec::with_capacity(4));
    let mut iter = IPv4RangeIter::new(
        IPv4Range {
            a: Component::new(0, 0),
            b: Component::new(0, 0),
            c: Component::new(0, 0),
            d: Component::new(0, 0),
        },
        &output_buffer,
    );
    for s in &["0.0.0.0"] {
        assert_eq!(iter.next().unwrap().to_string(), *s);
    }
    assert!(iter.next().is_none());

    Ok(())
}
