use std::{net, str::FromStr, sync::Arc};
use crate::error::{RLanLibError, Result};
#[derive(Debug)]
pub struct IPTargets(Vec<String>, usize);
fn loop_ips<F: FnMut(net::Ipv4Addr) -> Result<()>>(
list: &[String],
mut cb: F,
) -> Result<()> {
for target in list.iter() {
if target.contains("-") {
let parts: Vec<&str> = target.split("-").collect();
let begin = net::Ipv4Addr::from_str(parts[0]).map_err(|e| {
RLanLibError::from_net_addr_parse_error(target, e)
})?;
let end = net::Ipv4Addr::from_str(parts[1]).map_err(|e| {
RLanLibError::from_net_addr_parse_error(target, e)
})?;
let subnet = ipnet::Ipv4Subnets::new(begin, end, 32);
for ip_net in subnet {
for ip in ip_net.hosts() {
cb(ip)?;
}
}
} else if target.contains("/") {
let ip_net = ipnet::Ipv4Net::from_str(target).map_err(|e| {
RLanLibError::from_ipnet_addr_parse_error(target, e)
})?;
for ip in ip_net.hosts() {
cb(ip)?;
}
} else {
let ip: net::Ipv4Addr =
net::Ipv4Addr::from_str(target).map_err(|e| {
RLanLibError::from_net_addr_parse_error(target, e)
})?;
cb(ip)?;
}
}
Ok(())
}
impl IPTargets {
pub fn new(list: Vec<String>) -> Result<Arc<Self>> {
let mut len = 0;
loop_ips(&list, |_| {
len += 1;
Ok(())
})?;
Ok(Arc::new(Self(list, len)))
}
pub fn len(&self) -> usize {
self.1
}
pub fn is_empty(&self) -> bool {
self.1 == 0
}
pub fn lazy_loop<F: FnMut(net::Ipv4Addr) -> Result<()>>(
&self,
cb: F,
) -> Result<()> {
loop_ips(&self.0, cb)
}
}
#[cfg(test)]
#[path = "./ips_tests.rs"]
mod tests;