ipnet/
mask.rs

1use crate::PrefixLenError;
2#[cfg(not(feature = "std"))]
3use core::net::{IpAddr, Ipv4Addr, Ipv6Addr};
4#[cfg(feature = "std")]
5use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
6
7/// Converts a `IpAddr` network mask into a prefix.
8///
9/// # Errors
10/// If the mask is invalid this will return an `PrefixLenError`.
11pub fn ip_mask_to_prefix(mask: IpAddr) -> Result<u8, PrefixLenError> {
12    match mask {
13        IpAddr::V4(mask) => ipv4_mask_to_prefix(mask),
14        IpAddr::V6(mask) => ipv6_mask_to_prefix(mask),
15    }
16}
17
18/// Converts a `Ipv4Addr` network mask into a prefix.
19///
20/// # Errors
21/// If the mask is invalid this will return an `PrefixLenError`.
22pub fn ipv4_mask_to_prefix(mask: Ipv4Addr) -> Result<u8, PrefixLenError> {
23    let mask = u32::from(mask);
24
25    let prefix = mask.leading_ones();
26    if mask.checked_shl(prefix).unwrap_or(0) == 0 {
27        Ok(prefix as u8)
28    } else {
29        Err(PrefixLenError)
30    }
31}
32
33/// Converts a `Ipv6Addr` network mask into a prefix.
34///
35/// # Errors
36/// If the mask is invalid this will return an `PrefixLenError`.
37pub fn ipv6_mask_to_prefix(mask: Ipv6Addr) -> Result<u8, PrefixLenError> {
38    let mask = u128::from(mask);
39
40    let prefix = mask.leading_ones();
41    if mask.checked_shl(prefix).unwrap_or(0) == 0 {
42        Ok(prefix as u8)
43    } else {
44        Err(PrefixLenError)
45    }
46}
47
48#[cfg(test)]
49mod tests {
50    use super::*;
51    use crate::{Ipv4Net, Ipv6Net};
52
53    #[test]
54    fn v4_mask_to_prefix() {
55        let mask = Ipv4Addr::new(255, 255, 255, 128);
56        let prefix = ipv4_mask_to_prefix(mask);
57        assert_eq!(prefix, Ok(25));
58    }
59
60    #[test]
61    fn v4_mask_to_prefix_max() {
62        let mask = Ipv4Addr::from(u32::MAX);
63        let prefix = ipv4_mask_to_prefix(mask);
64        assert_eq!(prefix, Ok(32));
65    }
66
67    #[test]
68    fn invalid_v4_mask_to_prefix() {
69        let mask = Ipv4Addr::new(255, 0, 255, 0);
70        let prefix = ipv4_mask_to_prefix(mask);
71        assert!(prefix.is_err());
72    }
73
74    #[test]
75    fn ipv4net_with_netmask() {
76        {
77            // Positive test-case.
78            let addr = Ipv4Addr::new(127, 0, 0, 1);
79            let mask = Ipv4Addr::new(255, 0, 0, 0);
80            let net = Ipv4Net::with_netmask(addr, mask).unwrap();
81            let expected = Ipv4Net::new(Ipv4Addr::new(127, 0, 0, 1), 8).unwrap();
82            assert_eq!(net, expected);
83        }
84        {
85            // Negative test-case.
86            let addr = Ipv4Addr::new(127, 0, 0, 1);
87            let mask = Ipv4Addr::new(255, 0, 255, 0);
88            Ipv4Net::with_netmask(addr, mask).unwrap_err();
89        }
90    }
91
92    #[test]
93    fn v6_mask_to_prefix() {
94        let mask = Ipv6Addr::new(0xffff, 0xffff, 0xffff, 0, 0, 0, 0, 0);
95        let prefix = ipv6_mask_to_prefix(mask);
96        assert_eq!(prefix, Ok(48));
97    }
98
99    #[test]
100    fn v6_mask_to_prefix_max() {
101        let mask = Ipv6Addr::from(u128::MAX);
102        let prefix = ipv6_mask_to_prefix(mask);
103        assert_eq!(prefix, Ok(128));
104    }
105
106    #[test]
107    fn invalid_v6_mask_to_prefix() {
108        let mask = Ipv6Addr::new(0, 0, 0xffff, 0xffff, 0, 0, 0, 0);
109        let prefix = ipv6_mask_to_prefix(mask);
110        assert!(prefix.is_err());
111    }
112
113    #[test]
114    fn ipv6net_with_netmask() {
115        {
116            // Positive test-case.
117            let addr = Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2);
118            let mask = Ipv6Addr::new(0xffff, 0xffff, 0xffff, 0, 0, 0, 0, 0);
119            let net = Ipv6Net::with_netmask(addr, mask).unwrap();
120            let expected =
121                Ipv6Net::new(Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2), 48).unwrap();
122            assert_eq!(net, expected);
123        }
124        {
125            // Negative test-case.
126            let addr = Ipv6Addr::new(0xff01, 0, 0, 0x17, 0, 0, 0, 0x2);
127            let mask = Ipv6Addr::new(0, 0, 0xffff, 0xffff, 0, 0, 0, 0);
128            Ipv6Net::with_netmask(addr, mask).unwrap_err();
129        }
130    }
131}