mirror of
https://github.com/achanda/ipnetwork.git
synced 2025-06-17 09:18:51 +00:00
Added needed traits to NetworkSize
(#175)
* Add conversion and better equality traits to NetworkSize * Add tests for NetworkSize conversion/equality * impl Display for NetworkSize
This commit is contained in:
50
src/error.rs
Normal file
50
src/error.rs
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
use std::{error::Error, fmt};
|
||||||
|
|
||||||
|
use crate::error::IpNetworkError::*;
|
||||||
|
|
||||||
|
/// Represents a bunch of errors that can occur while working with a `IpNetwork`
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum IpNetworkError {
|
||||||
|
InvalidAddr(String),
|
||||||
|
InvalidPrefix,
|
||||||
|
InvalidCidrFormat(String),
|
||||||
|
NetworkSizeError(NetworkSizeError)
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for IpNetworkError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match *self {
|
||||||
|
InvalidAddr(ref s) => write!(f, "invalid address: {s}"),
|
||||||
|
InvalidPrefix => write!(f, "invalid prefix"),
|
||||||
|
InvalidCidrFormat(ref s) => write!(f, "invalid cidr format: {s}"),
|
||||||
|
NetworkSizeError(ref e) => write!(f, "network size error: {e}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for IpNetworkError {
|
||||||
|
fn description(&self) -> &str {
|
||||||
|
match *self {
|
||||||
|
InvalidAddr(_) => "address is invalid",
|
||||||
|
InvalidPrefix => "prefix is invalid",
|
||||||
|
InvalidCidrFormat(_) => "cidr is invalid",
|
||||||
|
NetworkSizeError(_) => "network size error"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Cannot convert an IPv6 network size to a u32 as it is a 128-bit value.
|
||||||
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
|
#[non_exhaustive]
|
||||||
|
pub enum NetworkSizeError {
|
||||||
|
NetworkIsTooLarge
|
||||||
|
}
|
||||||
|
|
||||||
|
impl fmt::Display for NetworkSizeError {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
f.write_str("Network is too large to fit into an unsigned 32-bit integer!")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Error for NetworkSizeError {}
|
@ -1,4 +1,5 @@
|
|||||||
use crate::common::{cidr_parts, parse_prefix, IpNetworkError};
|
use crate::error::IpNetworkError;
|
||||||
|
use crate::parse::{cidr_parts, parse_prefix};
|
||||||
use std::{convert::TryFrom, fmt, net::Ipv4Addr, str::FromStr};
|
use std::{convert::TryFrom, fmt, net::Ipv4Addr, str::FromStr};
|
||||||
|
|
||||||
const IPV4_BITS: u8 = 32;
|
const IPV4_BITS: u8 = 32;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
use crate::common::{cidr_parts, parse_prefix, IpNetworkError};
|
use crate::error::IpNetworkError;
|
||||||
|
use crate::parse::{cidr_parts, parse_prefix};
|
||||||
use std::{cmp, convert::TryFrom, fmt, net::Ipv6Addr, str::FromStr};
|
use std::{cmp, convert::TryFrom, fmt, net::Ipv6Addr, str::FromStr};
|
||||||
|
|
||||||
const IPV6_BITS: u8 = 128;
|
const IPV6_BITS: u8 = 128;
|
||||||
|
14
src/lib.rs
14
src/lib.rs
@ -10,15 +10,18 @@
|
|||||||
|
|
||||||
use std::{convert::TryFrom, fmt, net::IpAddr, str::FromStr};
|
use std::{convert::TryFrom, fmt, net::IpAddr, str::FromStr};
|
||||||
|
|
||||||
mod common;
|
mod error;
|
||||||
mod ipv4;
|
mod ipv4;
|
||||||
mod ipv6;
|
mod ipv6;
|
||||||
|
mod parse;
|
||||||
|
mod size;
|
||||||
|
|
||||||
pub use crate::common::IpNetworkError;
|
pub use crate::error::{NetworkSizeError, IpNetworkError};
|
||||||
pub use crate::ipv4::Ipv4NetworkIterator;
|
pub use crate::ipv4::Ipv4NetworkIterator;
|
||||||
pub use crate::ipv4::{ipv4_mask_to_prefix, Ipv4Network};
|
pub use crate::ipv4::{ipv4_mask_to_prefix, Ipv4Network};
|
||||||
pub use crate::ipv6::Ipv6NetworkIterator;
|
pub use crate::ipv6::Ipv6NetworkIterator;
|
||||||
pub use crate::ipv6::{ipv6_mask_to_prefix, Ipv6Network};
|
pub use crate::ipv6::{ipv6_mask_to_prefix, Ipv6Network};
|
||||||
|
pub use crate::size::NetworkSize;
|
||||||
|
|
||||||
/// Represents a generic network range. This type can have two variants:
|
/// Represents a generic network range. This type can have two variants:
|
||||||
/// the v4 and the v6 case.
|
/// the v4 and the v6 case.
|
||||||
@ -117,13 +120,6 @@ impl schemars::JsonSchema for IpNetwork {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Represents a generic network size. For IPv4, the max size is a u32 and for IPv6, it is a u128
|
|
||||||
#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
|
|
||||||
pub enum NetworkSize {
|
|
||||||
V4(u32),
|
|
||||||
V6(u128),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl IpNetwork {
|
impl IpNetwork {
|
||||||
/// Constructs a new `IpNetwork` from a given `IpAddr` and a prefix denoting the
|
/// Constructs a new `IpNetwork` from a given `IpAddr` and a prefix denoting the
|
||||||
/// network size. If the prefix is larger than 32 (for IPv4) or 128 (for IPv6), this
|
/// network size. If the prefix is larger than 32 (for IPv4) or 128 (for IPv6), this
|
||||||
|
@ -1,34 +1,4 @@
|
|||||||
use std::{error::Error, fmt};
|
use crate::error::IpNetworkError;
|
||||||
|
|
||||||
/// Represents a bunch of errors that can occur while working with a `IpNetwork`
|
|
||||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
|
||||||
pub enum IpNetworkError {
|
|
||||||
InvalidAddr(String),
|
|
||||||
InvalidPrefix,
|
|
||||||
InvalidCidrFormat(String),
|
|
||||||
}
|
|
||||||
|
|
||||||
impl fmt::Display for IpNetworkError {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
||||||
use crate::IpNetworkError::*;
|
|
||||||
match *self {
|
|
||||||
InvalidAddr(ref s) => write!(f, "invalid address: {s}"),
|
|
||||||
InvalidPrefix => write!(f, "invalid prefix"),
|
|
||||||
InvalidCidrFormat(ref s) => write!(f, "invalid cidr format: {s}"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Error for IpNetworkError {
|
|
||||||
fn description(&self) -> &str {
|
|
||||||
use crate::IpNetworkError::*;
|
|
||||||
match *self {
|
|
||||||
InvalidAddr(_) => "address is invalid",
|
|
||||||
InvalidPrefix => "prefix is invalid",
|
|
||||||
InvalidCidrFormat(_) => "cidr is invalid",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn cidr_parts(cidr: &str) -> Result<(&str, Option<&str>), IpNetworkError> {
|
pub fn cidr_parts(cidr: &str) -> Result<(&str, Option<&str>), IpNetworkError> {
|
||||||
// Try to find a single slash
|
// Try to find a single slash
|
161
src/size.rs
Normal file
161
src/size.rs
Normal file
@ -0,0 +1,161 @@
|
|||||||
|
use std::{cmp::Ordering, fmt::Display};
|
||||||
|
|
||||||
|
use crate::error::NetworkSizeError;
|
||||||
|
|
||||||
|
/// Represents a generic network size. For IPv4, the max size is a u32 and for IPv6, it is a u128
|
||||||
|
#[derive(Debug, Clone, Copy, Hash)]
|
||||||
|
pub enum NetworkSize {
|
||||||
|
V4(u32),
|
||||||
|
V6(u128),
|
||||||
|
}
|
||||||
|
use NetworkSize::*;
|
||||||
|
|
||||||
|
// Conversions
|
||||||
|
|
||||||
|
impl From<u128> for NetworkSize {
|
||||||
|
fn from(value: u128) -> Self {
|
||||||
|
V6(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<u32> for NetworkSize {
|
||||||
|
fn from(value: u32) -> Self {
|
||||||
|
V4(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TryInto<u32> for NetworkSize {
|
||||||
|
type Error = NetworkSizeError;
|
||||||
|
fn try_into(self) -> Result<u32, Self::Error> {
|
||||||
|
match self {
|
||||||
|
V4(a) => Ok(a),
|
||||||
|
V6(_) => Err(NetworkSizeError::NetworkIsTooLarge),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Into<u128> for NetworkSize {
|
||||||
|
fn into(self) -> u128 {
|
||||||
|
match self {
|
||||||
|
V4(a) => a as u128,
|
||||||
|
V6(a) => a,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Equality/comparisons
|
||||||
|
|
||||||
|
impl PartialEq for NetworkSize {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
let a: u128 = (*self).into();
|
||||||
|
let b: u128 = (*other).into();
|
||||||
|
a == b
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Ord for NetworkSize {
|
||||||
|
fn cmp(&self, other: &Self) -> Ordering {
|
||||||
|
let a: u128 = (*self).into();
|
||||||
|
let b: u128 = (*other).into();
|
||||||
|
return a.cmp(&b);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialOrd for NetworkSize {
|
||||||
|
fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
|
||||||
|
Some(self.cmp(other))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Eq for NetworkSize {}
|
||||||
|
|
||||||
|
// Display
|
||||||
|
|
||||||
|
impl Display for NetworkSize {
|
||||||
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
|
write!(f, "{}", Into::<u128>::into(*self))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Tests
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from_u128() {
|
||||||
|
let value: u128 = 100;
|
||||||
|
let ns = NetworkSize::from(value);
|
||||||
|
assert_eq!(ns, V6(100));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_from_u32() {
|
||||||
|
let value: u32 = 100;
|
||||||
|
let ns = NetworkSize::from(value);
|
||||||
|
assert_eq!(ns, V4(100));
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_try_into_u32() {
|
||||||
|
let value: u32 = 100;
|
||||||
|
let ns = V4(value);
|
||||||
|
let result: Result<u32, _> = ns.try_into();
|
||||||
|
assert!(result.is_ok());
|
||||||
|
assert_eq!(result.unwrap(), value);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_try_into_u32_error() {
|
||||||
|
let value: u128 = u32::MAX as u128 + 1;
|
||||||
|
let ns = V6(value);
|
||||||
|
let result: Result<u32, _> = ns.try_into();
|
||||||
|
assert!(result.is_err());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_into_u128() {
|
||||||
|
let value: u32 = 100;
|
||||||
|
let ns = V4(value);
|
||||||
|
let result: u128 = ns.into();
|
||||||
|
assert_eq!(result, value as u128);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_eq() {
|
||||||
|
let ns1 = V4(100);
|
||||||
|
let ns2 = V4(100);
|
||||||
|
assert_eq!(ns1, ns2);
|
||||||
|
|
||||||
|
let ns1 = V6(100);
|
||||||
|
let ns2 = V6(100);
|
||||||
|
assert_eq!(ns1, ns2);
|
||||||
|
|
||||||
|
let ns1 = V4(100);
|
||||||
|
let ns2 = V6(100);
|
||||||
|
assert_eq!(ns1, ns2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_cmp() {
|
||||||
|
let ns1 = V4(100);
|
||||||
|
let ns2 = V4(200);
|
||||||
|
assert!(ns1 < ns2);
|
||||||
|
|
||||||
|
let ns1 = V6(200);
|
||||||
|
let ns2 = V6(100);
|
||||||
|
assert!(ns1 > ns2);
|
||||||
|
|
||||||
|
let ns1 = V4(100);
|
||||||
|
let ns2 = V6(200);
|
||||||
|
assert!(ns1 < ns2);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_display() {
|
||||||
|
let ns1 = V4(u32::MAX);
|
||||||
|
let ns2 = V6(ns1.into());
|
||||||
|
assert_eq!(ns1.to_string(), ns2.to_string());
|
||||||
|
}
|
||||||
|
}
|
Reference in New Issue
Block a user