diff --git a/src/lib.rs b/src/lib.rs index b042968..f4356d0 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,13 +1,12 @@ #![feature(ip)] #![feature(addr_parse_ascii)] -use pyo3::prelude::*; use core::net::Ipv4Addr; -use std::net::Ipv6Addr; -use std::str::{self, FromStr}; use ipnet::Ipv4Net; use numpy::pyo3::Python; use numpy::{IntoPyArray, PyArray1, PyReadonlyArray1, PyUntypedArrayMethods}; - +use pyo3::prelude::*; +use std::net::Ipv6Addr; +use std::str::{self, FromStr}; pub fn netmask_to_prefix4(mask: u32) -> u8 { mask.leading_ones() as u8 @@ -17,74 +16,89 @@ pub fn netmask_to_prefix6(mask: u128) -> u8 { mask.leading_ones() as u8 } - #[pyfunction] -fn to_text4<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u32>) --> PyResult<(Bound<'py, PyArray1>, Bound<'py, PyArray1>)> { - let mut offsets: Vec = vec!(0, ); +fn to_text4<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u32>, +) -> PyResult<(Bound<'py, PyArray1>, Bound<'py, PyArray1>)> { + let mut offsets: Vec = vec![0]; let mut data: Vec = Vec::new(); - for out in x.as_array().iter() - { - let (a, b, c, d) = out.to_be_bytes().into(); - data.extend(Ipv4Addr::new(a, b, c, d).to_string().as_bytes()); - offsets.push(data.len() as u32); - }; + for out in x.as_array().iter() { + let (a, b, c, d) = out.to_be_bytes().into(); + data.extend(Ipv4Addr::new(a, b, c, d).to_string().as_bytes()); + offsets.push(data.len() as u32); + } Ok((data.into_pyarray_bound(py), offsets.into_pyarray_bound(py))) } /// Parse strings into IP4 addresses (length 4 bytestrings) #[pyfunction] -fn parse4<'py>(py: Python<'py>, offsets: PyReadonlyArray1<'py, u32>, - data : PyReadonlyArray1<'py, u8> +fn parse4<'py>( + py: Python<'py>, + offsets: PyReadonlyArray1<'py, u32>, + data: PyReadonlyArray1<'py, u8>, ) -> PyResult<(Bound<'py, PyArray1>, Bound<'py, PyArray1>)> { let ar = offsets.as_array(); let sl = ar.as_slice().unwrap(); let ar2 = data.as_array(); let by = ar2.as_slice().unwrap(); - let (out, valid): (Vec, Vec) = sl.windows(2).map( - |w| { - match Ipv4Addr::parse_ascii(&by[w[0] as usize..w[1] as usize]) { + let (out, valid): (Vec, Vec) = sl + .windows(2) + .map( + |w| match Ipv4Addr::parse_ascii(&by[w[0] as usize..w[1] as usize]) { Ok(x) => (u32::from_ne_bytes(x.octets()), 1u8), - Err(_) => (0u32, 0u8) - } - } - ).unzip(); + Err(_) => (0u32, 0u8), + }, + ) + .unzip(); Ok((out.into_pyarray_bound(py), valid.into_pyarray_bound(py))) } #[pyfunction] -fn to_text6<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u8>) --> PyResult<(Bound<'py, PyArray1>, Bound<'py, PyArray1>)> { - let mut offsets: Vec = vec!(0, ); +fn to_text6<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u8>, +) -> PyResult<(Bound<'py, PyArray1>, Bound<'py, PyArray1>)> { + let mut offsets: Vec = vec![0]; let mut data: Vec = Vec::new(); - for sl in x.as_slice().unwrap().chunks_exact(16) - { - data.extend(Ipv6Addr::from_bits(u128::from_be_bytes(sl.try_into().unwrap())).to_string().as_bytes()); - offsets.push(data.len() as u32); - }; + for sl in x.as_slice().unwrap().chunks_exact(16) { + data.extend( + Ipv6Addr::from_bits(u128::from_be_bytes(sl.try_into().unwrap())) + .to_string() + .as_bytes(), + ); + offsets.push(data.len() as u32); + } Ok((data.into_pyarray_bound(py), offsets.into_pyarray_bound(py))) } #[pyfunction] -fn parse6<'py>(py: Python<'py>, offsets: PyReadonlyArray1<'py, u32>, - data : PyReadonlyArray1<'py, u8> +fn parse6<'py>( + py: Python<'py>, + offsets: PyReadonlyArray1<'py, u32>, + data: PyReadonlyArray1<'py, u8>, ) -> PyResult>> { let ar = offsets.as_array(); let sl = ar.as_slice().unwrap(); let ar2 = data.as_array(); let by = ar2.as_slice().unwrap(); let mut out: Vec = Vec::with_capacity((sl.len() - 1) * 16); - for w in sl.windows(2) { - out.extend(Ipv6Addr::parse_ascii(&by[w[0] as usize..w[1] as usize]).unwrap().octets()) - }; + for w in sl.windows(2) { + out.extend( + Ipv6Addr::parse_ascii(&by[w[0] as usize..w[1] as usize]) + .unwrap() + .octets(), + ) + } Ok(out.into_pyarray_bound(py)) } /// Parse strings into IP4 networks (length 4 bytestring and 1-byte prefix value) #[pyfunction] -fn parsenet4<'py>(py: Python<'py>, +fn parsenet4<'py>( + py: Python<'py>, offsets: PyReadonlyArray1<'py, u32>, - data : PyReadonlyArray1<'py, u8> + data: PyReadonlyArray1<'py, u8>, ) -> PyResult<(Bound<'py, PyArray1>, Bound<'py, PyArray1>)> { let ar = offsets.as_array(); let sl = ar.as_slice().unwrap(); @@ -93,164 +107,267 @@ fn parsenet4<'py>(py: Python<'py>, let mut outaddr: Vec = Vec::with_capacity(ar.len() - 1); let mut outpref: Vec = Vec::with_capacity(ar.len() - 1); for w in sl.windows(2) { - let net = Ipv4Net::from_str( - &str::from_utf8(&by[w[0] as usize..w[1] as usize]).unwrap()).unwrap(); + let net = + Ipv4Net::from_str(&str::from_utf8(&by[w[0] as usize..w[1] as usize]).unwrap()).unwrap(); outaddr.push(u32::from_ne_bytes(net.addr().octets())); outpref.push(net.prefix_len()); - }; - Ok((outaddr.into_pyarray_bound(py), outpref.into_pyarray_bound(py))) + } + Ok(( + outaddr.into_pyarray_bound(py), + outpref.into_pyarray_bound(py), + )) } - /// Is `other` contained in the address/prefix pairs of the input array? #[pyfunction] -fn contains_one4<'py>(py: Python<'py>, +fn contains_one4<'py>( + py: Python<'py>, addr: PyReadonlyArray1<'py, u32>, pref: PyReadonlyArray1<'py, u8>, - other: u32 + other: u32, ) -> PyResult>> { - let out: Vec = addr.as_array().iter().zip(pref.as_array()).map(|(add, pre)| - Ipv4Net::new(Ipv4Addr::from_bits(*add), *pre).unwrap().contains(&Ipv4Addr::from_bits(other)) - ).collect(); + let out: Vec = addr + .as_array() + .iter() + .zip(pref.as_array()) + .map(|(add, pre)| { + Ipv4Net::new(Ipv4Addr::from_bits(*add), *pre) + .unwrap() + .contains(&Ipv4Addr::from_bits(other)) + }) + .collect(); Ok(out.into_pyarray_bound(py)) } - // list of IP4 addresses indicated by each network #[pyfunction] -fn hosts4<'py>(py: Python<'py>, +fn hosts4<'py>( + py: Python<'py>, addr: PyReadonlyArray1<'py, u32>, pref: PyReadonlyArray1<'py, u8>, ) -> PyResult<(Bound<'py, PyArray1>, Bound<'py, PyArray1>)> { let mut out: Vec = Vec::new(); let mut offsets: Vec = Vec::from([0]); for (&add, &pre) in addr.as_array().iter().zip(pref.as_array()) { - let hosts = Ipv4Net::new({ - let (a, b, c, d) = add.to_ne_bytes().into(); - Ipv4Addr::new(a, b, c, d) - }, pre).unwrap().hosts(); - out.extend(hosts.map(|ip|u32::from_ne_bytes(ip.octets()))); + let hosts = Ipv4Net::new( + { + let (a, b, c, d) = add.to_ne_bytes().into(); + Ipv4Addr::new(a, b, c, d) + }, + pre, + ) + .unwrap() + .hosts(); + out.extend(hosts.map(|ip| u32::from_ne_bytes(ip.octets()))); offsets.push(out.len() as u64); - }; + } Ok((out.into_pyarray_bound(py), offsets.into_pyarray_bound(py))) } /// the hostmask implied by the given network prefix #[pyfunction] -fn hostmask4<'py>(py: Python<'py>, +fn hostmask4<'py>( + py: Python<'py>, pref: PyReadonlyArray1<'py, u8>, ) -> PyResult>> { - let out: Vec = pref.as_array().iter().map( - |x| u32::from_ne_bytes(Ipv4Net::new(Ipv4Addr::new(0, 0, 0, 0), *x).unwrap().hostmask().octets()) - ).collect(); + let out: Vec = pref + .as_array() + .iter() + .map(|x| { + u32::from_ne_bytes( + Ipv4Net::new(Ipv4Addr::new(0, 0, 0, 0), *x) + .unwrap() + .hostmask() + .octets(), + ) + }) + .collect(); Ok(out.into_pyarray_bound(py)) } - /// the netmask implied by the given network prefix #[pyfunction] -fn netmask4<'py>(py: Python<'py>, +fn netmask4<'py>( + py: Python<'py>, pref: PyReadonlyArray1<'py, u8>, ) -> PyResult>> { - let out: Vec = pref.as_array().iter().map( - |x| u32::from_ne_bytes(Ipv4Net::new(Ipv4Addr::new(0, 0, 0, 0), *x).unwrap().netmask().octets()) - ).collect(); + let out: Vec = pref + .as_array() + .iter() + .map(|x| { + u32::from_ne_bytes( + Ipv4Net::new(Ipv4Addr::new(0, 0, 0, 0), *x) + .unwrap() + .netmask() + .octets(), + ) + }) + .collect(); Ok(out.into_pyarray_bound(py)) } /// the base network address of the given network values #[pyfunction] -fn network4<'py>(py: Python<'py>, +fn network4<'py>( + py: Python<'py>, addr: PyReadonlyArray1<'py, u32>, pref: PyReadonlyArray1<'py, u8>, ) -> PyResult>> { - let out: Vec = addr.as_array().iter().zip(pref.as_array().iter()).map( - | (&add, &pre) | u32::from_ne_bytes(Ipv4Net::new({ - let (a, b, c, d) = add.to_ne_bytes().into(); - Ipv4Addr::new(a, b, c, d) - }, pre).unwrap().network().octets()) - ).collect(); + let out: Vec = addr + .as_array() + .iter() + .zip(pref.as_array().iter()) + .map(|(&add, &pre)| { + u32::from_ne_bytes( + Ipv4Net::new( + { + let (a, b, c, d) = add.to_ne_bytes().into(); + Ipv4Addr::new(a, b, c, d) + }, + pre, + ) + .unwrap() + .network() + .octets(), + ) + }) + .collect(); Ok(out.into_pyarray_bound(py)) } - /// the highest address of the given network values #[pyfunction] -fn broadcast4<'py>(py: Python<'py>, +fn broadcast4<'py>( + py: Python<'py>, addr: PyReadonlyArray1<'py, u32>, pref: PyReadonlyArray1<'py, u8>, ) -> PyResult>> { - let out: Vec = addr.as_array().iter().zip(pref.as_array().iter()).map( - | (&add, &pre) | u32::from_ne_bytes(Ipv4Net::new({ - let (a, b, c, d) = add.to_ne_bytes().into(); - Ipv4Addr::new(a, b, c, d) - }, pre).unwrap().broadcast().octets()) - ).collect(); + let out: Vec = addr + .as_array() + .iter() + .zip(pref.as_array().iter()) + .map(|(&add, &pre)| { + u32::from_ne_bytes( + Ipv4Net::new( + { + let (a, b, c, d) = add.to_ne_bytes().into(); + Ipv4Addr::new(a, b, c, d) + }, + pre, + ) + .unwrap() + .broadcast() + .octets(), + ) + }) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn trunc4<'py>(py: Python<'py>, +fn trunc4<'py>( + py: Python<'py>, addr: PyReadonlyArray1<'py, u32>, pref: PyReadonlyArray1<'py, u8>, ) -> PyResult>> { - let out: Vec = addr.as_array().iter().zip(pref.as_array().iter()).map( - | (&add, &pre) | u32::from_ne_bytes(Ipv4Net::new({ - let (a, b, c, d) = add.to_ne_bytes().into(); - Ipv4Addr::new(a, b, c, d) - }, pre).unwrap().trunc().addr().octets()) - ).collect(); + let out: Vec = addr + .as_array() + .iter() + .zip(pref.as_array().iter()) + .map(|(&add, &pre)| { + u32::from_ne_bytes( + Ipv4Net::new( + { + let (a, b, c, d) = add.to_ne_bytes().into(); + Ipv4Addr::new(a, b, c, d) + }, + pre, + ) + .unwrap() + .trunc() + .addr() + .octets(), + ) + }) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn supernet4<'py>(py: Python<'py>, +fn supernet4<'py>( + py: Python<'py>, addr: PyReadonlyArray1<'py, u32>, pref: PyReadonlyArray1<'py, u8>, ) -> PyResult>> { - let out: Vec = addr.as_array().iter().zip(pref.as_array().iter()).map( - | (&add, &pre) | u32::from_ne_bytes(Ipv4Net::new({ - let (a, b, c, d) = add.to_ne_bytes().into(); - Ipv4Addr::new(a, b, c, d) - }, pre).unwrap().supernet().unwrap().addr().octets()) - ).collect(); + let out: Vec = addr + .as_array() + .iter() + .zip(pref.as_array().iter()) + .map(|(&add, &pre)| { + u32::from_ne_bytes( + Ipv4Net::new( + { + let (a, b, c, d) = add.to_ne_bytes().into(); + Ipv4Addr::new(a, b, c, d) + }, + pre, + ) + .unwrap() + .supernet() + .unwrap() + .addr() + .octets(), + ) + }) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn subnets4<'py>(py: Python<'py>, +fn subnets4<'py>( + py: Python<'py>, addr: PyReadonlyArray1<'py, u32>, pref: PyReadonlyArray1<'py, u8>, - new_pref: u8 + new_pref: u8, ) -> PyResult<(Bound<'py, PyArray1>, Bound<'py, PyArray1>)> { let mut out: Vec = Vec::new(); let mut counts: Vec = Vec::with_capacity(pref.len()); let mut count: u64 = 0; counts.push(0); - addr.as_array().iter().zip(pref.as_array().iter()).for_each( - | (&add, &pre) | { - Ipv4Net::new({ - let (a, b, c, d) = add.to_ne_bytes().into(); - Ipv4Addr::new(a, b, c, d) - }, pre).unwrap().subnets(new_pref).unwrap().for_each( - |x|{ - count += 1; - out.push(u32::from_ne_bytes(x.addr().octets())) - } - ); + addr.as_array() + .iter() + .zip(pref.as_array().iter()) + .for_each(|(&add, &pre)| { + Ipv4Net::new( + { + let (a, b, c, d) = add.to_ne_bytes().into(); + Ipv4Addr::new(a, b, c, d) + }, + pre, + ) + .unwrap() + .subnets(new_pref) + .unwrap() + .for_each(|x| { + count += 1; + out.push(u32::from_ne_bytes(x.addr().octets())) + }); counts.push(count); - } - - ); + }); Ok((out.into_pyarray_bound(py), counts.into_pyarray_bound(py))) } #[pyfunction] -fn aggregate4<'py>(py: Python<'py>, +fn aggregate4<'py>( + py: Python<'py>, addr: PyReadonlyArray1<'py, u32>, offsets: PyReadonlyArray1<'py, u64>, pref: PyReadonlyArray1<'py, u8>, -) -> PyResult<(Bound<'py, PyArray1>, Bound<'py, PyArray1>, Bound<'py, PyArray1>)> { +) -> PyResult<( + Bound<'py, PyArray1>, + Bound<'py, PyArray1>, + Bound<'py, PyArray1>, +)> { let mut out_addr: Vec = Vec::new(); let mut out_pref: Vec = Vec::new(); let mut counts: Vec = Vec::with_capacity(pref.len()); @@ -269,207 +386,358 @@ fn aggregate4<'py>(py: Python<'py>, networks.clear(); while count_in < *w { let (a, b, c, d): (u8, u8, u8, u8) = ad_slice.next().unwrap().to_ne_bytes().into(); - networks.push(Ipv4Net::new(Ipv4Addr::new(a, b, c, d), *pr_slice.next().unwrap()).unwrap()); + networks + .push(Ipv4Net::new(Ipv4Addr::new(a, b, c, d), *pr_slice.next().unwrap()).unwrap()); count_in += 1; - }; - Ipv4Net::aggregate(&networks).iter().for_each( - |x| { - out_addr.push(u32::from_ne_bytes(x.addr().octets())); - out_pref.push(x.prefix_len()); - count += 1; - }); + } + Ipv4Net::aggregate(&networks).iter().for_each(|x| { + out_addr.push(u32::from_ne_bytes(x.addr().octets())); + out_pref.push(x.prefix_len()); + count += 1; + }); counts.push(count); } - Ok((out_addr.into_pyarray_bound(py), out_pref.into_pyarray_bound(py), counts.into_pyarray_bound(py))) + Ok(( + out_addr.into_pyarray_bound(py), + out_pref.into_pyarray_bound(py), + counts.into_pyarray_bound(py), + )) } - #[pyfunction] -fn is_broadcast4<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u32>) -> PyResult>> { - let out: Vec = x.as_array().iter().map(|&x|{ - let (a, b, c, d) = x.to_ne_bytes().into(); - Ipv4Addr::new(a, b, c, d).is_broadcast() - }).collect(); +fn is_broadcast4<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u32>, +) -> PyResult>> { + let out: Vec = x + .as_array() + .iter() + .map(|&x| { + let (a, b, c, d) = x.to_ne_bytes().into(); + Ipv4Addr::new(a, b, c, d).is_broadcast() + }) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn is_global4<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u32>) -> PyResult>> { - let out: Vec = x.as_array().iter().map(|&x|{ - let (a, b, c, d) = x.to_ne_bytes().into(); - Ipv4Addr::new(a, b, c, d).is_global() - }).collect(); +fn is_global4<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u32>, +) -> PyResult>> { + let out: Vec = x + .as_array() + .iter() + .map(|&x| { + let (a, b, c, d) = x.to_ne_bytes().into(); + Ipv4Addr::new(a, b, c, d).is_global() + }) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn is_unspecified4<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u32>) -> PyResult>> { - let out: Vec = x.as_array().iter().map(|&x|{ - let (a, b, c, d) = x.to_ne_bytes().into(); - Ipv4Addr::new(a, b, c, d).is_unspecified() - }).collect(); +fn is_unspecified4<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u32>, +) -> PyResult>> { + let out: Vec = x + .as_array() + .iter() + .map(|&x| { + let (a, b, c, d) = x.to_ne_bytes().into(); + Ipv4Addr::new(a, b, c, d).is_unspecified() + }) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn is_loopback4<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u32>) -> PyResult>> { - let out: Vec = x.as_array().iter().map(|&x|{ - let (a, b, c, d) = x.to_ne_bytes().into(); - Ipv4Addr::new(a, b, c, d).is_loopback() - }).collect(); +fn is_loopback4<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u32>, +) -> PyResult>> { + let out: Vec = x + .as_array() + .iter() + .map(|&x| { + let (a, b, c, d) = x.to_ne_bytes().into(); + Ipv4Addr::new(a, b, c, d).is_loopback() + }) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn is_private4<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u32>) -> PyResult>> { - let out: Vec = x.as_array().iter().map(|&x|{ - let (a, b, c, d) = x.to_ne_bytes().into(); - Ipv4Addr::new(a, b, c, d).is_private() - }).collect(); +fn is_private4<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u32>, +) -> PyResult>> { + let out: Vec = x + .as_array() + .iter() + .map(|&x| { + let (a, b, c, d) = x.to_ne_bytes().into(); + Ipv4Addr::new(a, b, c, d).is_private() + }) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn is_link_local4<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u32>) -> PyResult>> { - let out: Vec = x.as_array().iter().map(|&x|{ - let (a, b, c, d) = x.to_ne_bytes().into(); - Ipv4Addr::new(a, b, c, d).is_link_local() - }).collect(); +fn is_link_local4<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u32>, +) -> PyResult>> { + let out: Vec = x + .as_array() + .iter() + .map(|&x| { + let (a, b, c, d) = x.to_ne_bytes().into(); + Ipv4Addr::new(a, b, c, d).is_link_local() + }) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn is_shared4<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u32>) -> PyResult>> { - let out: Vec = x.as_array().iter().map(|&x|{ - let (a, b, c, d) = x.to_ne_bytes().into(); - Ipv4Addr::new(a, b, c, d).is_shared() - }).collect(); +fn is_shared4<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u32>, +) -> PyResult>> { + let out: Vec = x + .as_array() + .iter() + .map(|&x| { + let (a, b, c, d) = x.to_ne_bytes().into(); + Ipv4Addr::new(a, b, c, d).is_shared() + }) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn is_benchmarking4<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u32>) -> PyResult>> { - let out: Vec = x.as_array().iter().map(|&x|{ - let (a, b, c, d) = x.to_ne_bytes().into(); - Ipv4Addr::new(a, b, c, d).is_benchmarking() - }).collect(); +fn is_benchmarking4<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u32>, +) -> PyResult>> { + let out: Vec = x + .as_array() + .iter() + .map(|&x| { + let (a, b, c, d) = x.to_ne_bytes().into(); + Ipv4Addr::new(a, b, c, d).is_benchmarking() + }) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn is_reserved4<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u32>) -> PyResult>> { - let out: Vec = x.as_array().iter().map(|&x|{ - let (a, b, c, d) = x.to_ne_bytes().into(); - Ipv4Addr::new(a, b, c, d).is_reserved() - }).collect(); +fn is_reserved4<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u32>, +) -> PyResult>> { + let out: Vec = x + .as_array() + .iter() + .map(|&x| { + let (a, b, c, d) = x.to_ne_bytes().into(); + Ipv4Addr::new(a, b, c, d).is_reserved() + }) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn is_multicast4<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u32>) -> PyResult>> { - let out: Vec = x.as_array().iter().map(|&x|{ - let (a, b, c, d) = x.to_ne_bytes().into(); - Ipv4Addr::new(a, b, c, d).is_multicast() - }).collect(); +fn is_multicast4<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u32>, +) -> PyResult>> { + let out: Vec = x + .as_array() + .iter() + .map(|&x| { + let (a, b, c, d) = x.to_ne_bytes().into(); + Ipv4Addr::new(a, b, c, d).is_multicast() + }) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn is_documentation4<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u32>) -> PyResult>> { - let out: Vec = x.as_array().iter().map(|&x|{ - let (a, b, c, d) = x.to_ne_bytes().into(); - Ipv4Addr::new(a, b, c, d).is_documentation() - }).collect(); +fn is_documentation4<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u32>, +) -> PyResult>> { + let out: Vec = x + .as_array() + .iter() + .map(|&x| { + let (a, b, c, d) = x.to_ne_bytes().into(); + Ipv4Addr::new(a, b, c, d).is_documentation() + }) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn is_benchmarking6<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u8>) -> PyResult>> { - let out: Vec = x.as_slice().unwrap().chunks_exact(16).map(|sl | { - Ipv6Addr::from_bits(u128::from_be_bytes(sl.try_into().unwrap())).is_benchmarking() - }).collect(); +fn is_benchmarking6<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u8>, +) -> PyResult>> { + let out: Vec = x + .as_slice() + .unwrap() + .chunks_exact(16) + .map(|sl| { + Ipv6Addr::from_bits(u128::from_be_bytes(sl.try_into().unwrap())).is_benchmarking() + }) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn is_documentation6<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u8>) -> PyResult>> { - let out: Vec = x.as_slice().unwrap().chunks_exact(16).map(|sl | { - Ipv6Addr::from_bits(u128::from_be_bytes(sl.try_into().unwrap())).is_documentation() - }).collect(); +fn is_documentation6<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u8>, +) -> PyResult>> { + let out: Vec = x + .as_slice() + .unwrap() + .chunks_exact(16) + .map(|sl| { + Ipv6Addr::from_bits(u128::from_be_bytes(sl.try_into().unwrap())).is_documentation() + }) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn is_global6<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u8>) -> PyResult>> { - let out: Vec = x.as_slice().unwrap().chunks_exact(16).map(|sl | { - Ipv6Addr::from_bits(u128::from_be_bytes(sl.try_into().unwrap())).is_global() - }).collect(); +fn is_global6<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u8>, +) -> PyResult>> { + let out: Vec = x + .as_slice() + .unwrap() + .chunks_exact(16) + .map(|sl| Ipv6Addr::from_bits(u128::from_be_bytes(sl.try_into().unwrap())).is_global()) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn is_ipv4_mapped<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u8>) -> PyResult>> { - let out: Vec = x.as_slice().unwrap().chunks_exact(16).map(|sl | { - Ipv6Addr::from_bits(u128::from_be_bytes(sl.try_into().unwrap())).is_ipv4_mapped() - }).collect(); +fn is_ipv4_mapped<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u8>, +) -> PyResult>> { + let out: Vec = x + .as_slice() + .unwrap() + .chunks_exact(16) + .map(|sl| Ipv6Addr::from_bits(u128::from_be_bytes(sl.try_into().unwrap())).is_ipv4_mapped()) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn is_loopback6<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u8>) -> PyResult>> { - let out: Vec = x.as_slice().unwrap().chunks_exact(16).map(|sl | { - Ipv6Addr::from_bits(u128::from_be_bytes(sl.try_into().unwrap())).is_loopback() - }).collect(); +fn is_loopback6<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u8>, +) -> PyResult>> { + let out: Vec = x + .as_slice() + .unwrap() + .chunks_exact(16) + .map(|sl| Ipv6Addr::from_bits(u128::from_be_bytes(sl.try_into().unwrap())).is_loopback()) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn is_multicast6<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u8>) -> PyResult>> { - let out: Vec = x.as_slice().unwrap().chunks_exact(16).map(|sl | { - Ipv6Addr::from_bits(u128::from_be_bytes(sl.try_into().unwrap())).is_multicast() - }).collect(); +fn is_multicast6<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u8>, +) -> PyResult>> { + let out: Vec = x + .as_slice() + .unwrap() + .chunks_exact(16) + .map(|sl| Ipv6Addr::from_bits(u128::from_be_bytes(sl.try_into().unwrap())).is_multicast()) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn is_unicast6<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u8>) -> PyResult>> { - let out: Vec = x.as_slice().unwrap().chunks_exact(16).map(|sl | { - Ipv6Addr::from_bits(u128::from_be_bytes(sl.try_into().unwrap())).is_unicast() - }).collect(); +fn is_unicast6<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u8>, +) -> PyResult>> { + let out: Vec = x + .as_slice() + .unwrap() + .chunks_exact(16) + .map(|sl| Ipv6Addr::from_bits(u128::from_be_bytes(sl.try_into().unwrap())).is_unicast()) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn is_unicast_link_local<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u8>) -> PyResult>> { - let out: Vec = x.as_slice().unwrap().chunks_exact(16).map(|sl | { - Ipv6Addr::from_bits(u128::from_be_bytes(sl.try_into().unwrap())).is_unicast_link_local() - }).collect(); +fn is_unicast_link_local<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u8>, +) -> PyResult>> { + let out: Vec = x + .as_slice() + .unwrap() + .chunks_exact(16) + .map(|sl| { + Ipv6Addr::from_bits(u128::from_be_bytes(sl.try_into().unwrap())).is_unicast_link_local() + }) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn is_unique_local<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u8>) -> PyResult>> { - let out: Vec = x.as_slice().unwrap().chunks_exact(16).map(|sl | { - Ipv6Addr::from_bits(u128::from_be_bytes(sl.try_into().unwrap())).is_unique_local() - }).collect(); +fn is_unique_local<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u8>, +) -> PyResult>> { + let out: Vec = x + .as_slice() + .unwrap() + .chunks_exact(16) + .map(|sl| { + Ipv6Addr::from_bits(u128::from_be_bytes(sl.try_into().unwrap())).is_unique_local() + }) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn is_unspecified6<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u8>) -> PyResult>> { - let out: Vec = x.as_slice().unwrap().chunks_exact(16).map(|sl | { - Ipv6Addr::from_bits(u128::from_be_bytes(sl.try_into().unwrap())).is_unspecified() - }).collect(); +fn is_unspecified6<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u8>, +) -> PyResult>> { + let out: Vec = x + .as_slice() + .unwrap() + .chunks_exact(16) + .map(|sl| Ipv6Addr::from_bits(u128::from_be_bytes(sl.try_into().unwrap())).is_unspecified()) + .collect(); Ok(out.into_pyarray_bound(py)) } #[pyfunction] -fn to_ipv6_mapped<'py>(py: Python<'py>, x: PyReadonlyArray1<'py, u32>) -> PyResult>> { +fn to_ipv6_mapped<'py>( + py: Python<'py>, + x: PyReadonlyArray1<'py, u32>, +) -> PyResult>> { let mut out: Vec = Vec::with_capacity(x.len() * 16); for &x in x.as_array().iter() { let bit = Ipv4Addr::from(x).to_ipv6_mapped().octets(); out.extend(bit); - }; + } Ok(out.into_pyarray_bound(py)) } @@ -514,4 +782,4 @@ fn akimbo_ip(m: &Bound<'_, PyModule>) -> PyResult<()> { m.add_function(wrap_pyfunction!(to_text6, m)?)?; m.add_function(wrap_pyfunction!(parse6, m)?)?; Ok(()) -} \ No newline at end of file +} diff --git a/tests/test_core.py b/tests/test_core.py index aea8e1c..83a6b88 100644 --- a/tests/test_core.py +++ b/tests/test_core.py @@ -12,7 +12,7 @@ def test_simple4(): assert out[0] is False out2 = s1.ak.ip.to_string4() assert out2[0] == "0.0.0.0" - + s2 = pd.Series("0.0.0.0") out = s2.ak.ip.parse_address4() assert out[0] == b"\x00\x00\x00\x00" @@ -24,7 +24,7 @@ def test_simple6(): dtype=bytestring16) out = s1.ak.ip.is_global6() assert out.tolist() == [False, False] - + out2 = s1.ak.ip.to_string6() assert out2.tolist() == ["::", "::1"] out3 = out2.ak.ip.parse_address6() @@ -42,7 +42,7 @@ def test_to_lists(): ] out2 = out.ak.ip.to_bytestring() assert s1.to_list() == out2.to_list() - + s2 = pd.Series([0, 1], dtype="uint32") out = s2.ak.ip.to_int_list() assert out.to_list() == [[0, 0, 0, 0], [1, 0, 0, 0]] @@ -60,7 +60,7 @@ def test_simple_net4(): s = pd.Series(["0.0.0.0/24"]) out = s.ak.ip.parse_net4() assert out[0] == {"prefix": 24, "address": b"\x00\x00\x00\x00"} - + out2 = out.ak.ip.contains4(1) assert out2[0] is True out2 = out.ak.ip.contains4(b"\x00\x00\x00\x01") @@ -69,7 +69,6 @@ def test_simple_net4(): assert out2[0] is True -@pytest.mark.xfail(message="Optional not implemented") def test_err(): s = pd.Series(["not-an-ip"]) s.ak.ip.parse_address4() @@ -79,10 +78,10 @@ def test_6_out(): s1 = pd.Series([1], dtype="u4") out = s1.ak.ip.to_ipv6_mapped() assert out[0] == b'\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\xff\xff\x00\x00\x00\x01' - + def test_rename(): - s = pd.DataFrame({"address": pd.Series([1], dtype="u4"), + s = pd.DataFrame({"address": pd.Series([1], dtype="u4"), "end": pd.Series([16], dtype="u1")}).ak.merge() out = s.ak.ip.contains4(b"\x00\x00\x00\x01") assert s.tolist() == out.tolist() # no change, no match @@ -92,12 +91,12 @@ def test_rename(): def test_inner_list_hosts(): # note: both addresses are rounded down - s = pd.DataFrame({"address": pd.Series([b"\x00\x00\x00\x00", b"\x01\x00\x00\x00"], dtype=bytestring4), + s = pd.DataFrame({"address": pd.Series([b"\x00\x00\x00\x00", b"\x01\x00\x00\x00"], dtype=bytestring4), "prefix": pd.Series([31, 29], dtype="u1")}).ak.merge() out = s.ak.ip.hosts4() assert out.to_list() == [ # includes gateway/broadcast - [b'\x00\x00\x00\x00', b'\x00\x00\x00\x01'], + [b'\x00\x00\x00\x00', b'\x00\x00\x00\x01'], # does not include gateway/broadcast [b'\x01\x00\x00\x01', b'\x01\x00\x00\x02', b'\x01\x00\x00\x03', b'\x01\x00\x00\x04', b'\x01\x00\x00\x05', b'\x01\x00\x00\x06'] ] @@ -107,7 +106,6 @@ def test_masks(): s = pd.Series(["7.7.7.7", "8.8.8.8"]).ak.ip.parse_address4() out1 = s.ak.ip | s.ak.array[:1] assert out1.ak.ip.to_int_list().tolist() == [[7, 7, 7, 7], [15, 15, 15, 15]] - + out2 = s.ak.ip | "255.0.0.0" assert out2.ak.ip.to_int_list().tolist() == [[255, 7, 7, 7], [255, 8, 8, 8]] - \ No newline at end of file