1use core::fmt;
2use core::str::FromStr;
3
4#[cfg(any(test, feature = "arbitrary"))]
5use proptest::{
6 arbitrary::{any_with, Arbitrary, ParamsFor},
7 prop_oneof,
8 strategy::{BoxedStrategy, Strategy},
9};
10
11use super::{delegate, Address, Hostmask, Netmask};
12use crate::{
13 concrete::{self, Ipv4, Ipv6},
14 error::{err, Error, Kind},
15 traits,
16};
17
18mod len;
19pub use self::len::Length;
20
21mod range;
22pub use self::range::Range;
23
24#[cfg(feature = "std")]
25mod set;
26#[cfg(feature = "std")]
27pub use self::set::Set;
28
29mod subprefixes;
30pub use self::subprefixes::Subprefixes;
31
32#[allow(variant_size_differences)]
56#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd)]
57pub enum Prefix {
58 Ipv4(concrete::Prefix<Ipv4>),
60 Ipv6(concrete::Prefix<Ipv6>),
62}
63
64impl traits::Prefix for Prefix {
65 type Address = Address;
66 type Length = Length;
67 type Hostmask = Hostmask;
68 type Netmask = Netmask;
69 type Subprefixes = Subprefixes;
70
71 delegate! {
72 fn network(&self) -> Self::Address;
73 fn hostmask(&self) -> Self::Hostmask;
74 fn netmask(&self) -> Self::Netmask;
75 fn max_prefix_len(&self) -> Self::Length;
76 fn prefix_len(&self) -> Self::Length;
77 fn broadcast(&self) -> Self::Address;
78 }
79
80 fn supernet(&self) -> Option<Self> {
81 match self {
82 Self::Ipv4(prefix) => prefix.supernet().map(Self::Ipv4),
83 Self::Ipv6(prefix) => prefix.supernet().map(Self::Ipv6),
84 }
85 }
86
87 fn is_sibling(&self, other: &Self) -> bool {
88 match (self, other) {
89 (Self::Ipv4(prefix), Self::Ipv4(other)) => prefix.is_sibling(other),
90 (Self::Ipv6(prefix), Self::Ipv6(other)) => prefix.is_sibling(other),
91 _ => false,
92 }
93 }
94
95 fn subprefixes(&self, new_prefix_length: Self::Length) -> Result<Self::Subprefixes, Error> {
96 match (self, new_prefix_length) {
97 (Self::Ipv4(prefix), Self::Length::Ipv4(length)) => {
98 prefix.subprefixes(length).map(Self::Subprefixes::Ipv4)
99 }
100 (Self::Ipv6(prefix), Self::Length::Ipv6(length)) => {
101 prefix.subprefixes(length).map(Self::Subprefixes::Ipv6)
102 }
103 _ => Err(err!(Kind::AfiMismatch)),
104 }
105 }
106
107 fn new_prefix_length(&self, length: u8) -> Result<Self::Length, Error> {
108 self.afi().new_prefix_length(length)
109 }
110}
111
112impl From<concrete::Prefix<Ipv4>> for Prefix {
113 fn from(prefix: concrete::Prefix<Ipv4>) -> Self {
114 Self::Ipv4(prefix)
115 }
116}
117
118impl From<concrete::Prefix<Ipv6>> for Prefix {
119 fn from(prefix: concrete::Prefix<Ipv6>) -> Self {
120 Self::Ipv6(prefix)
121 }
122}
123
124impl FromStr for Prefix {
125 type Err = Error;
126
127 fn from_str(s: &str) -> Result<Self, Self::Err> {
128 concrete::Prefix::<Ipv4>::from_str(s)
129 .map(Self::from)
130 .or_else(|_| concrete::Prefix::<Ipv6>::from_str(s).map(Self::from))
131 }
132}
133
134impl fmt::Display for Prefix {
135 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
136 match self {
137 Self::Ipv4(prefix) => prefix.fmt(f),
138 Self::Ipv6(prefix) => prefix.fmt(f),
139 }
140 }
141}
142
143#[cfg(any(test, feature = "arbitrary"))]
144impl Arbitrary for Prefix {
145 type Parameters = (
146 ParamsFor<concrete::Prefix<Ipv4>>,
147 ParamsFor<concrete::Prefix<Ipv6>>,
148 );
149 type Strategy = BoxedStrategy<Self>;
150
151 fn arbitrary_with(params: Self::Parameters) -> Self::Strategy {
152 prop_oneof![
153 any_with::<concrete::Prefix<Ipv4>>(params.0).prop_map(Self::Ipv4),
154 any_with::<concrete::Prefix<Ipv6>>(params.1).prop_map(Self::Ipv6),
155 ]
156 .boxed()
157 }
158}