Skip to content

Commit

Permalink
Merge pull request #84 from rye/contains-new-impls
Browse files Browse the repository at this point in the history
New Contains ergonomics
  • Loading branch information
rye authored Feb 27, 2020
2 parents 8391f6a + 22b8299 commit cf4f83a
Show file tree
Hide file tree
Showing 5 changed files with 248 additions and 67 deletions.
5 changes: 5 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,11 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
<!-- Types of changes: Added, Changed, Deprecated, Removed, Fixed, Security -->

## Unreleased
### Changed
- **Breaking**: Adjusted the signature of the `Contains` trait to take a type parameter.

Most users should not be affected in any way by this change, as the `.contains()` method still has the same syntax.
However, the types for which containment can be checked are now explicitly enumerated.

## [0.8.0] - 2020-02-26
### Added
Expand Down
240 changes: 189 additions & 51 deletions src/netaddr/contains.rs
Original file line number Diff line number Diff line change
@@ -1,16 +1,56 @@
use super::NetAddr;
use crate::traits::Contains;

impl Contains for NetAddr {
fn contains<T: Copy>(&self, other: &T) -> bool
where
Self: From<T>,
{
let other: Self = Self::from(*other);
match (self, other) {
(Self::V4(netaddr), Self::V4(other)) => netaddr.contains(&other),
(Self::V6(netaddr), Self::V6(other)) => netaddr.contains(&other),
(_, _) => false,
impl Contains<std::net::IpAddr> for NetAddr {
fn contains(&self, other: &std::net::IpAddr) -> bool {
match self {
Self::V4(netaddr) => netaddr.contains(other),
Self::V6(netaddr) => netaddr.contains(other),
}
}
}

impl Contains<std::net::Ipv4Addr> for NetAddr {
fn contains(&self, other: &std::net::Ipv4Addr) -> bool {
match self {
Self::V4(netaddr) => netaddr.contains(other),
_ => false,
}
}
}

impl Contains<std::net::Ipv6Addr> for NetAddr {
fn contains(&self, other: &std::net::Ipv6Addr) -> bool {
match self {
Self::V6(netaddr) => netaddr.contains(other),
_ => false,
}
}
}

impl Contains<NetAddr> for NetAddr {
fn contains(&self, other: &NetAddr) -> bool {
match self {
Self::V4(netaddr) => netaddr.contains(other),
Self::V6(netaddr) => netaddr.contains(other),
}
}
}

impl Contains<crate::Netv4Addr> for NetAddr {
fn contains(&self, other: &crate::Netv4Addr) -> bool {
match self {
Self::V4(netaddr) => netaddr.contains(other),
_ => false,
}
}
}

impl Contains<crate::Netv6Addr> for NetAddr {
fn contains(&self, other: &crate::Netv6Addr) -> bool {
match self {
Self::V6(netaddr) => netaddr.contains(other),
_ => false,
}
}
}
Expand All @@ -21,77 +61,175 @@ mod tests {
use crate::NetAddr;
use std::net::IpAddr;

macro_rules! pu {
($value:literal # $t:ty) => {
$value.parse::<$t>().unwrap()
};
}

macro_rules! assert_contains {
($a:expr, $b:expr) => {
assert!($a.contains(&$b));
};
($a:expr, $b:literal # $b_ty:ty) => {
assert!($a.contains(&pu!($b # $b_ty)));
};
($a:literal # $a_ty:ty, $b:expr) => {
assert!(pu!($a # $a_ty).contains(&$b));
};
($a:literal # $a_ty:ty, $b:literal # $b_ty:ty) => {
assert!(pu!($a # $a_ty).contains(&pu!($b # $b_ty)));
};
}

macro_rules! assert_not_contains {
($a:expr, $b:expr) => {
assert!(!$a.contains(&$b));
};
($a:expr, $b:literal # $b_ty:ty) => {
assert!(!$a.contains(&pu!($b # $b_ty)));
};
($a:literal # $a_ty:ty, $b:expr) => {
assert!(!pu!($a # $a_ty).contains(&$b));
};
($a:literal # $a_ty:ty, $b:literal # $b_ty:ty) => {
assert!(!pu!($a # $a_ty).contains(&pu!($b # $b_ty)));
};
}

mod v4 {
use super::*;
use std::net::Ipv4Addr;
use crate::{Netv4Addr, Netv6Addr};
use std::net::{Ipv4Addr, Ipv6Addr};

#[test]
fn ip() {
let net: NetAddr = "127.0.0.1/8".parse().unwrap();
assert!(net.contains(&IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1))));
assert!(net.contains(&IpAddr::V4(Ipv4Addr::new(127, 127, 255, 1))));
assert!(!net.contains(&IpAddr::V4(Ipv4Addr::new(64, 0, 0, 0))));
fn ipaddr_v4() {
let net = pu!("127.0.0.1/8" # NetAddr);
assert_contains!(net, "127.0.0.1" # IpAddr);
assert_contains!(net, "127.127.255.1" # IpAddr);
assert_not_contains!(net, "64.73.69.2" # IpAddr);
}

#[test]
fn net() {
let net: NetAddr = "127.0.0.1/8".parse().unwrap();
let net_inner: NetAddr = "127.128.0.1/24".parse().unwrap();
assert!(net.contains(&net_inner));
fn ipaddr_v6() {
let net = pu!("127.0.0.1/8" # NetAddr);
assert_not_contains!(net, "ff02::1" # IpAddr);
assert_not_contains!(net, "::ffff:127.0.0.1" # IpAddr);
}

#[test]
fn ipv4addr() {
let net = pu!("127.0.0.1/8" # NetAddr);
assert_contains!(net, "127.0.0.1" # Ipv4Addr);
assert_contains!(net, "127.127.255.1" # Ipv4Addr);
assert_not_contains!(net, "64.73.69.2" # Ipv4Addr);
}

#[test]
fn ipv6addr() {
let net = pu!("127.0.0.1/8" # NetAddr);
assert_not_contains!(net, "ff02::1" # Ipv6Addr);
assert_not_contains!(net, "::ffff:127.0.0.1" # Ipv6Addr);
}

#[test]
fn netaddr_v4() {
let net = pu!("127.0.0.1/8" # NetAddr);
assert_contains!(net, "127.128.0.1/24" # NetAddr);
}

#[test]
fn netaddr_v6() {
let net = pu!("127.0.0.1/8" # NetAddr);
assert_not_contains!(net, "ff02::1/16" # NetAddr);
assert_not_contains!(net, "::ffff:127.0.0.1/96" # NetAddr);
}

#[test]
fn v6_ip() {
fn netv4addr() {
let net: NetAddr = "127.0.0.1/8".parse().unwrap();
let ip: IpAddr = "2001:db8:d00b::1".parse().unwrap();
assert!(!net.contains(&ip));
assert_contains!(net, "127.0.0.1/24" # Netv4Addr);
assert_contains!(net, "127.127.255.63/24" # Netv4Addr);
assert_not_contains!(net, "64.73.81.69/24" # Netv4Addr);
}

#[test]
fn v6_net() {
let a: NetAddr = "127.0.0.1/8".parse().unwrap();
let b: NetAddr = "2001:db8:d0::/48".parse().unwrap();
assert!(!a.contains(&b));
fn netv6addr() {
let net: NetAddr = "127.0.0.1/8".parse().unwrap();
assert_not_contains!(net, "ff02::1/16" # Netv6Addr);
assert_not_contains!(net, "::ffff:127.0.0.1/96" # Netv6Addr);
}
}

mod v6 {
use super::*;
use std::net::Ipv6Addr;
use crate::{Netv4Addr, Netv6Addr};
use std::net::{Ipv4Addr, Ipv6Addr};

#[test]
fn ipaddr_v4() {
let net = pu!("2001:db8:dead:beef::/64" # NetAddr);
assert_not_contains!(net, "127.0.0.1" # IpAddr);
assert_not_contains!(net, "127.127.255.1" # IpAddr);
assert_not_contains!(net, "64.73.69.2" # IpAddr);
}

#[test]
fn ipaddr_v6() {
let net = pu!("2001:db8:dead:beef::/64" # NetAddr);
assert_not_contains!(net, "ff02::1" # IpAddr);
assert_not_contains!(net, "::ffff:127.0.0.1" # IpAddr);
assert_contains!(net, "2001:db8:dead:beef::1" # IpAddr);
assert_contains!(net, "2001:db8:dead:beef:c0f:fee:dab:69" # IpAddr);
}

#[test]
fn ipv4addr() {
let net = pu!("2001:db8:dead:beef::/64" # NetAddr);
assert_not_contains!(net, "127.0.0.1" # Ipv4Addr);
assert_not_contains!(net, "127.127.255.1" # Ipv4Addr);
assert_not_contains!(net, "64.73.69.2" # Ipv4Addr);
}

#[test]
fn ipv6addr() {
let net = pu!("2001:db8:dead:beef::/64" # NetAddr);
assert_not_contains!(net, "ff02::1" # Ipv6Addr);
assert_not_contains!(net, "::ffff:127.0.0.1" # Ipv6Addr);
assert_contains!(net, "2001:db8:dead:beef::1" # Ipv6Addr);
assert_contains!(net, "2001:db8:dead:beef:c0f:fee:dab:69" # Ipv6Addr);
}

#[test]
fn ip() {
let net: NetAddr = "2001:db8:d00b::/48".parse().unwrap();
assert!(net.contains(&IpAddr::V6(Ipv6Addr::new(
0x2001, 0x0db8, 0xd00b, 0, 0, 0, 0, 0x0001
))));
assert!(net.contains(&IpAddr::V6(Ipv6Addr::new(
0x2001, 0x0db8, 0xd00b, 0xffff, 0xffff, 0xffff, 0xffff, 0xffff
))));
assert!(!net.contains(&IpAddr::V6(Ipv6Addr::new(
0x2001, 0x0db8, 0xd00c, 0, 0, 0, 0, 1
))));
fn netaddr_v4() {
let net = pu!("2001:db8:dead:beef::/64" # NetAddr);
assert_not_contains!(net, "127.128.0.1/24" # NetAddr);
assert_contains!(net, "2001:db8:dead:beef::1/64" # NetAddr);
assert_contains!(net, "2001:db8:dead:beef:c0f:fee::/96" # NetAddr);
}

#[test]
fn net() {
let net: NetAddr = "2001:db8:d000::/40".parse().unwrap();
let net_inner: NetAddr = "2001:db8:d00b::/48".parse().unwrap();
assert!(net.contains(&net_inner));
fn netaddr_v6() {
let net = pu!("2001:db8:dead:beef::/64" # NetAddr);
assert_not_contains!(net, "ff02::1/16" # NetAddr);
assert_not_contains!(net, "::ffff:127.0.0.1/96" # NetAddr);
}

#[test]
fn v4_ip() {
let net: NetAddr = "2001:db8:d000::/40".parse().unwrap();
let ip: IpAddr = "127.0.0.1".parse().unwrap();
assert!(!net.contains(&ip));
fn netv4addr() {
let net: NetAddr = "2001:db8:dead:beef::/64".parse().unwrap();
assert_not_contains!(net, "127.0.0.1/24" # Netv4Addr);
assert_not_contains!(net, "127.127.255.63/24" # Netv4Addr);
assert_not_contains!(net, "64.73.81.69/24" # Netv4Addr);
}

#[test]
fn v4_net() {
let a: NetAddr = "2001:db8:d0::/48".parse().unwrap();
let b: NetAddr = "127.0.0.1/8".parse().unwrap();
assert!(!a.contains(&b));
fn netv6addr() {
let net: NetAddr = "2001:db8:dead:beef::/64".parse().unwrap();
assert_not_contains!(net, "ff02::1/16" # Netv6Addr);
assert_not_contains!(net, "::ffff:127.0.0.1/96" # Netv6Addr);
assert_contains!(net, "2001:db8:dead:beef::1/64" # Netv6Addr);
assert_contains!(net, "2001:db8:dead:beef:c0f:fee::/96" # Netv6Addr);
}
}
}
32 changes: 26 additions & 6 deletions src/netv4addr/contains.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,32 @@ use super::Netv4Addr;
use crate::traits::Contains;
use crate::traits::Mask;

impl Contains for Netv4Addr {
fn contains<T: Copy>(&self, other: &T) -> bool
where
Self: From<T>,
{
let other: Self = Self::from(*other);
impl Contains<std::net::IpAddr> for Netv4Addr {
fn contains(&self, other: &std::net::IpAddr) -> bool {
match other {
std::net::IpAddr::V4(other) => self.contains(other),
_ => false,
}
}
}

impl Contains<std::net::Ipv4Addr> for Netv4Addr {
fn contains(&self, other: &std::net::Ipv4Addr) -> bool {
other.mask(self.mask()) == *self.addr()
}
}

impl Contains<crate::NetAddr> for Netv4Addr {
fn contains(&self, other: &crate::NetAddr) -> bool {
match other {
crate::NetAddr::V4(other) => self.contains(other),
_ => false,
}
}
}

impl Contains<Netv4Addr> for Netv4Addr {
fn contains(&self, other: &Netv4Addr) -> bool {
other.addr().mask(self.mask()) == *self.addr()
}
}
Expand Down
32 changes: 26 additions & 6 deletions src/netv6addr/contains.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,32 @@ use super::Netv6Addr;
use crate::traits::Contains;
use crate::traits::Mask;

impl Contains for Netv6Addr {
fn contains<T: Copy>(&self, other: &T) -> bool
where
Self: From<T>,
{
let other: Self = Self::from(*other);
impl Contains<std::net::IpAddr> for Netv6Addr {
fn contains(&self, other: &std::net::IpAddr) -> bool {
match other {
std::net::IpAddr::V6(other) => self.contains(other),
_ => false,
}
}
}

impl Contains<std::net::Ipv6Addr> for Netv6Addr {
fn contains(&self, other: &std::net::Ipv6Addr) -> bool {
other.mask(self.mask()) == *self.addr()
}
}

impl Contains<crate::NetAddr> for Netv6Addr {
fn contains(&self, other: &crate::NetAddr) -> bool {
match other {
crate::NetAddr::V6(other) => self.contains(other),
_ => false,
}
}
}

impl Contains<Netv6Addr> for Netv6Addr {
fn contains(&self, other: &Netv6Addr) -> bool {
other.addr().mask(self.mask()) == *self.addr()
}
}
Expand Down
6 changes: 2 additions & 4 deletions src/traits/contains.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,4 @@
/// Check containment of one object within another
pub trait Contains {
fn contains<T: Copy>(&self, other: &T) -> bool
where
Self: From<T>;
pub trait Contains<T> {
fn contains(&self, other: &T) -> bool;
}

0 comments on commit cf4f83a

Please sign in to comment.