#![crate_type = "lib"]
#![deny(
missing_debug_implementations,
unsafe_code,
unused_extern_crates,
unused_import_braces
)]
use std::{convert::TryFrom, fmt, net::IpAddr, str::FromStr};
mod error;
mod ipv4;
mod ipv6;
mod parse;
mod size;
pub use crate::error::{NetworkSizeError, IpNetworkError};
pub use crate::ipv4::Ipv4NetworkIterator;
pub use crate::ipv4::{ipv4_mask_to_prefix, Ipv4Network};
pub use crate::ipv6::Ipv6NetworkIterator;
pub use crate::ipv6::{ipv6_mask_to_prefix, Ipv6Network};
pub use crate::size::NetworkSize;
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
pub enum IpNetwork {
V4(Ipv4Network),
V6(Ipv6Network),
}
#[cfg(feature = "serde")]
impl<'de> serde::Deserialize<'de> for IpNetwork {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: serde::Deserializer<'de>,
{
let s = <String>::deserialize(deserializer)?;
IpNetwork::from_str(&s).map_err(serde::de::Error::custom)
}
}
#[cfg(feature = "serde")]
impl serde::Serialize for IpNetwork {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: serde::Serializer,
{
serializer.collect_str(self)
}
}
#[cfg(feature = "schemars")]
impl schemars::JsonSchema for IpNetwork {
fn schema_name() -> String {
"IpNetwork".to_string()
}
fn json_schema(gen: &mut schemars::gen::SchemaGenerator) -> schemars::schema::Schema {
schemars::schema::SchemaObject {
metadata: Some(
schemars::schema::Metadata {
..Default::default()
}
.into(),
),
subschemas: Some(
schemars::schema::SubschemaValidation {
one_of: Some(vec![
schemars::schema::SchemaObject {
metadata: Some(
schemars::schema::Metadata {
title: Some("v4".to_string()),
..Default::default()
}
.into(),
),
subschemas: Some(
schemars::schema::SubschemaValidation {
all_of: Some(vec![gen.subschema_for::<Ipv4Network>()]),
..Default::default()
}
.into(),
),
..Default::default()
}
.into(),
schemars::schema::SchemaObject {
metadata: Some(
schemars::schema::Metadata {
title: Some("v6".to_string()),
..Default::default()
}
.into(),
),
subschemas: Some(
schemars::schema::SubschemaValidation {
all_of: Some(vec![gen.subschema_for::<Ipv6Network>()]),
..Default::default()
}
.into(),
),
..Default::default()
}
.into(),
]),
..Default::default()
}
.into(),
),
extensions: [("x-rust-type".to_string(), "ipnetwork::IpNetwork".into())]
.iter()
.cloned()
.collect(),
..Default::default()
}
.into()
}
}
impl IpNetwork {
pub fn new(ip: IpAddr, prefix: u8) -> Result<IpNetwork, IpNetworkError> {
match ip {
IpAddr::V4(a) => Ok(IpNetwork::V4(Ipv4Network::new(a, prefix)?)),
IpAddr::V6(a) => Ok(IpNetwork::V6(Ipv6Network::new(a, prefix)?)),
}
}
pub fn with_netmask(netaddr: IpAddr, netmask: IpAddr) -> Result<Self, IpNetworkError> {
let prefix = ip_mask_to_prefix(netmask)?;
Self::new(netaddr, prefix)
}
pub fn ip(&self) -> IpAddr {
match *self {
IpNetwork::V4(ref a) => IpAddr::V4(a.ip()),
IpNetwork::V6(ref a) => IpAddr::V6(a.ip()),
}
}
pub fn prefix(&self) -> u8 {
match *self {
IpNetwork::V4(ref a) => a.prefix(),
IpNetwork::V6(ref a) => a.prefix(),
}
}
pub fn network(&self) -> IpAddr {
match *self {
IpNetwork::V4(ref a) => IpAddr::V4(a.network()),
IpNetwork::V6(ref a) => IpAddr::V6(a.network()),
}
}
pub fn broadcast(&self) -> IpAddr {
match *self {
IpNetwork::V4(ref a) => IpAddr::V4(a.broadcast()),
IpNetwork::V6(ref a) => IpAddr::V6(a.broadcast()),
}
}
pub fn mask(&self) -> IpAddr {
match *self {
IpNetwork::V4(ref a) => IpAddr::V4(a.mask()),
IpNetwork::V6(ref a) => IpAddr::V6(a.mask()),
}
}
pub fn is_ipv4(&self) -> bool {
match *self {
IpNetwork::V4(_) => true,
IpNetwork::V6(_) => false,
}
}
pub fn is_ipv6(&self) -> bool {
match *self {
IpNetwork::V4(_) => false,
IpNetwork::V6(_) => true,
}
}
#[inline]
pub fn contains(&self, ip: IpAddr) -> bool {
match (*self, ip) {
(IpNetwork::V4(net), IpAddr::V4(ip)) => net.contains(ip),
(IpNetwork::V6(net), IpAddr::V6(ip)) => net.contains(ip),
_ => false,
}
}
pub fn size(&self) -> NetworkSize {
match *self {
IpNetwork::V4(ref ip) => NetworkSize::V4(ip.size()),
IpNetwork::V6(ref ip) => NetworkSize::V6(ip.size()),
}
}
pub fn iter(&self) -> IpNetworkIterator {
let inner = match self {
IpNetwork::V4(ip) => IpNetworkIteratorInner::V4(ip.iter()),
IpNetwork::V6(ip) => IpNetworkIteratorInner::V6(ip.iter()),
};
IpNetworkIterator { inner }
}
}
impl FromStr for IpNetwork {
type Err = IpNetworkError;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Ok(net) = Ipv4Network::from_str(s) {
Ok(IpNetwork::V4(net))
} else if let Ok(net) = Ipv6Network::from_str(s) {
Ok(IpNetwork::V6(net))
} else {
Err(IpNetworkError::InvalidAddr(s.to_string()))
}
}
}
impl TryFrom<&str> for IpNetwork {
type Error = IpNetworkError;
fn try_from(s: &str) -> Result<Self, Self::Error> {
IpNetwork::from_str(s)
}
}
impl From<Ipv4Network> for IpNetwork {
fn from(v4: Ipv4Network) -> IpNetwork {
IpNetwork::V4(v4)
}
}
impl From<Ipv6Network> for IpNetwork {
fn from(v6: Ipv6Network) -> IpNetwork {
IpNetwork::V6(v6)
}
}
impl From<IpAddr> for IpNetwork {
fn from(addr: IpAddr) -> IpNetwork {
match addr {
IpAddr::V4(a) => IpNetwork::V4(Ipv4Network::from(a)),
IpAddr::V6(a) => IpNetwork::V6(Ipv6Network::from(a)),
}
}
}
impl fmt::Display for IpNetwork {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match *self {
IpNetwork::V4(net) => net.fmt(f),
IpNetwork::V6(net) => net.fmt(f),
}
}
}
#[derive(Clone, Debug)]
enum IpNetworkIteratorInner {
V4(Ipv4NetworkIterator),
V6(Ipv6NetworkIterator),
}
#[derive(Clone, Debug)]
pub struct IpNetworkIterator {
inner: IpNetworkIteratorInner,
}
impl Iterator for IpNetworkIterator {
type Item = IpAddr;
fn next(&mut self) -> Option<IpAddr> {
match &mut self.inner {
IpNetworkIteratorInner::V4(iter) => iter.next().map(IpAddr::V4),
IpNetworkIteratorInner::V6(iter) => iter.next().map(IpAddr::V6),
}
}
}
impl IntoIterator for &'_ IpNetwork {
type IntoIter = IpNetworkIterator;
type Item = IpAddr;
fn into_iter(self) -> IpNetworkIterator {
self.iter()
}
}
pub fn ip_mask_to_prefix(mask: IpAddr) -> Result<u8, IpNetworkError> {
match mask {
IpAddr::V4(mask) => ipv4_mask_to_prefix(mask),
IpAddr::V6(mask) => ipv6_mask_to_prefix(mask),
}
}
#[cfg(test)]
mod test {
#[test]
#[cfg(feature = "serde")]
fn deserialize_from_serde_json_value() {
use super::*;
let network = IpNetwork::from_str("0.0.0.0/0").unwrap();
let val: serde_json::value::Value =
serde_json::from_str(&serde_json::to_string(&network).unwrap()).unwrap();
let _deser: IpNetwork = serde_json::from_value(val)
.expect("Fails to deserialize from json_value::value::Value");
}
}