krisprice / ipnet

IpNet, Ipv4Net, and Ipv6Net types and methods for Rust
Apache License 2.0
122 stars 26 forks source link

Make the trait Contains public #25

Closed Stargateur closed 3 years ago

Stargateur commented 4 years ago

The trait Contains is not pub, this is strange in my opinion, I come to the point where I would like to also have a generic function over Contains to use https://docs.rs/ipnet/2.3.0/ipnet/enum.IpNet.html#method.contains in a generic way, but I can't cause Contains is not pub, but still appear on a pub interface. In my opinion is a non sense. Specially the trait is pub https://github.com/krisprice/ipnet/blob/master/src/ipnet.rs#L1211 but not exported ???

krisprice commented 4 years ago

Hi @Stargateur -- Contains was only created so I could implement the contains methods two test the two types IpAddrs and IpNets. In release 1 is was exported and you had to include the trait just to be able to use the contains methods. In release 2 this was changed to what it is now. I don't grok what you're trying do are you able to give me a short example? Thanks

Stargateur commented 4 years ago

Simple:

#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Default)]
pub struct Hosts {
    pub ip_nets: Vec<IpNet>,
}

impl Hosts {
    pub fn contains(
        &self,
        ip_addr: &IpNet,
    ) -> Option<&Network> {
        self.ip_nets
            .iter()
            .find(|ip_net| ip_net.contains(ip_addr))
    }
}

With Contains I could make this function work for IpAddr and IpNet, I think:

use Contains;

impl Hosts {
    pub fn contains<T>(
        &self,
        ip: T,
    ) -> Option<&IpNet> {
        self.ip_nets
            .iter()
            .find(|ip_net| ip_net.contains(ip))
    }
}
krisprice commented 4 years ago

Hi @Stargateur, I don't think that would work. But you can fork the code and make Contains public and try it out if you like. You could also implement your own version that returns the found network which seems to be what you're after, something like:

use std::net::IpAddr;
use ipnet::IpNet;

pub struct Hosts {
    pub ip_nets: Vec<IpNet>,
}

pub trait Contains<T> {
    fn contains(&self, other: T) -> Option<&IpNet>;
}

impl<'a> Contains<&'a IpNet> for Hosts {
    fn contains(&self, other: &IpNet) -> Option<&IpNet> {
        self.ip_nets.iter().find(|ip_net| ip_net.contains(other))
    }
}

impl<'a> Contains<&'a IpAddr> for Hosts {
    fn contains(&self, other: &IpAddr) -> Option<&IpNet> {
        self.ip_nets.iter().find(|ip_net| ip_net.contains(other))
    }
}

fn main() {
    macro_rules! make_ipnet_vec {
        ($($x:expr),*) => ( vec![$($x.parse::<IpNet>().unwrap(),)*] );
        ($($x:expr,)*) => ( make_ipnet_vec![$($x),*] );
    }

    let n4_1: IpNet = "10.1.1.0/24".parse().unwrap();
    let ip4_1: IpAddr = "10.1.1.1".parse().unwrap();

    let hosts: Hosts = Hosts { ip_nets: make_ipnet_vec![
        "10.0.0.0/24", "10.0.1.0/24", "10.0.1.1/24", "10.0.1.2/24",
        "10.0.2.0/24",
        "10.1.0.0/24", "10.1.1.0/24",
        "192.168.0.0/24", "192.168.1.0/24", "192.168.2.0/24", "192.168.3.0/24",
        "fd00::/32", "fd00:1::/32",
        "fd00:2::/32",
    ]};

    dbg!(hosts.contains(&ip4_1));
    dbg!(hosts.contains(&n4_1));
}