1#![no_std]
4#![warn(missing_docs)]
5#![allow(clippy::style)]
6
7mod parser;
8pub use parser::{parse_ip, ParseError};
9pub mod base;
10pub mod v4;
11pub mod v6;
12
13use core::{fmt, net};
14
15#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
16pub enum Cidr {
18 V4(v4::Cidr),
20 V6(v6::Cidr),
22}
23
24impl Cidr {
25 pub const IPV4_BITS: u8 = v4::BITS_LEN;
27 pub const IPV6_BITS: u8 = v6::BITS_LEN;
29
30 #[inline(always)]
31 pub const fn new(addr: net::IpAddr, prefix: u8) -> Option<Self> {
35 match addr {
36 net::IpAddr::V4(addr) => Self::new_v4(addr, prefix),
37 net::IpAddr::V6(addr) => Self::new_v6(addr, prefix),
38 }
39 }
40
41 #[inline]
42 pub const fn new_v4(addr: net::Ipv4Addr, prefix: u8) -> Option<Self> {
46 match v4::Cidr::new(addr, prefix) {
47 Some(cidr) => Some(Self::V4(cidr)),
48 None => None,
49 }
50 }
51
52 #[inline]
53 pub const fn new_v6(addr: net::Ipv6Addr, prefix: u8) -> Option<Self> {
57 match v6::Cidr::new(addr, prefix) {
58 Some(cidr) => Some(Self::V6(cidr)),
59 None => None,
60 }
61 }
62
63 #[inline(always)]
64 pub const fn addr(&self) -> net::IpAddr {
66 match self {
67 Self::V4(cidr) => net::IpAddr::V4(cidr.addr()),
68 Self::V6(cidr) => net::IpAddr::V6(cidr.addr()),
69 }
70 }
71
72 #[inline(always)]
73 pub const fn prefix(&self) -> u8 {
75 match self {
76 Self::V4(cidr) => cidr.prefix(),
77 Self::V6(cidr) => cidr.prefix(),
78 }
79 }
80
81 #[inline(always)]
82 pub const fn network_addr(&self) -> net::IpAddr {
84 match self {
85 Self::V4(cidr) => net::IpAddr::V4(cidr.network_addr()),
86 Self::V6(cidr) => net::IpAddr::V6(cidr.network_addr()),
87 }
88 }
89
90 #[inline(always)]
91 pub const fn broadcast_addr(&self) -> net::IpAddr {
93 match self {
94 Self::V4(cidr) => net::IpAddr::V4(cidr.broadcast_addr()),
95 Self::V6(cidr) => net::IpAddr::V6(cidr.broadcast_addr()),
96 }
97 }
98
99 #[inline(always)]
100 pub const fn size(&self) -> u128 {
102 match self {
103 Self::V4(cidr) => cidr.size() as _,
104 Self::V6(cidr) => cidr.size(),
105 }
106 }
107
108 #[inline(always)]
109 pub const fn contains(&self, addr: net::IpAddr) -> bool {
111 match (self, addr) {
112 (Self::V4(cidr), net::IpAddr::V4(addr)) => cidr.contains(addr),
113 (Self::V6(cidr), net::IpAddr::V6(addr)) => cidr.contains(addr),
114 _ => false,
115 }
116 }
117
118 #[inline(always)]
119 pub const fn get(&self, idx: u128) -> Option<net::IpAddr> {
121 match self {
122 Self::V4(cidr) => match cidr.get(idx as u32) {
123 Some(ip) => Some(net::IpAddr::V4(ip)),
124 None => None,
125 }
126 Self::V6(cidr) => match cidr.get(idx) {
127 Some(ip) => Some(net::IpAddr::V6(ip)),
128 None => None,
129 }
130 }
131 }
132
133 #[inline(always)]
134 pub const fn get_unchecked(&self, idx: u128) -> net::IpAddr {
139 match self {
140 Self::V4(cidr) => net::IpAddr::V4(cidr.get_unchecked(idx as u32)),
141 Self::V6(cidr) => net::IpAddr::V6(cidr.get_unchecked(idx)),
142 }
143 }
144}
145
146impl fmt::Display for Cidr {
147 #[inline(always)]
148 fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result {
149 match self {
150 Self::V4(cidr) => fmt::Display::fmt(cidr, fmt),
151 Self::V6(cidr) => fmt::Display::fmt(cidr, fmt),
152 }
153 }
154}
155
156#[inline]
157pub const fn parse_cidr(text: &str) -> Result<Option<Cidr>, parser::ParseError<'_>> {
167 match parse_ip(text) {
168 Ok((net::IpAddr::V4(addr), None)) => Ok(Some(Cidr::V4(v4::Cidr::new_single(addr)))),
169 Ok((net::IpAddr::V4(addr), Some(prefix))) => Ok(Cidr::new_v4(addr, prefix)),
170 Ok((net::IpAddr::V6(addr), None)) => Ok(Some(Cidr::V6(v6::Cidr::new_single(addr)))),
171 Ok((net::IpAddr::V6(addr), Some(prefix))) => Ok(Cidr::new_v6(addr, prefix)),
172 Err(error) => Err(error)
173 }
174}