Skip to content

Commit a04c46c

Browse files
Reimplementation using tree node data structure
Fixing critical bug Removing many erroneous cases and need for Results being used everywhere Still desperate need for tests
1 parent 65c6ed3 commit a04c46c

File tree

5 files changed

+331
-229
lines changed

5 files changed

+331
-229
lines changed

src/cidr.rs

+113-67
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,14 @@ use std::{
44
str::FromStr,
55
};
66

7+
use crate::Error;
8+
79
#[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)]
810
pub struct Cidr {
911
network: Ipv4Addr,
1012
prefix: u8,
1113
}
1214

13-
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
14-
pub enum Error {
15-
CidrNotInRange(String),
16-
InvalidNetwork(String),
17-
InvalidPrefix(String),
18-
Parse(String),
19-
TypeCast(String),
20-
Impossible(String),
21-
}
22-
23-
impl Display for Error {
24-
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
25-
write!(f, "{self:?}")
26-
}
27-
}
28-
2915
impl Cidr {
3016
pub fn new(network: Ipv4Addr, prefix: u8) -> Result<Self, Error> {
3117
if prefix as u32 > u32::BITS {
@@ -84,22 +70,58 @@ impl Cidr {
8470
Ipv4Addr::from(last)
8571
}
8672

87-
pub fn contains<T>(&self, net: T) -> Result<bool, Error>
73+
pub fn contains<T>(&self, net: T) -> bool
8874
where
89-
T: Copy + Debug + TryInto<Cidr>,
75+
T: Copy + Debug + Into<Cidr>,
9076
{
91-
let cidr: Cidr = net
92-
.try_into()
93-
.map_err(|_| Error::TypeCast(format!("could not cast value '{:?}' to cidr", net)))?;
94-
Ok(cidr.first() >= self.first() && cidr.last() <= self.last())
77+
let cidr: Cidr = net.into();
78+
cidr.first() >= self.first() && cidr.last() <= self.last()
79+
}
80+
81+
pub fn parent(&self) -> Option<Cidr> {
82+
match self.prefix {
83+
0 => None,
84+
1 => Some(Self::default()),
85+
_ => {
86+
let prefix = self.prefix - 1;
87+
let shift = u32::BITS - prefix as u32;
88+
Some(Self {
89+
network: (u32::from(self.network) >> shift << shift).into(),
90+
prefix,
91+
})
92+
}
93+
}
9594
}
9695

97-
pub fn split(&self) -> Result<[Cidr; 2], Error> {
98-
let prefix = self.prefix + 1;
99-
Ok([
100-
Self::new(self.network, prefix)?,
101-
Self::new(self.mid(), prefix)?,
102-
])
96+
pub fn left_subnet(&self) -> Option<Cidr> {
97+
match self.prefix as u32 {
98+
u32::BITS => None,
99+
_ => Some(Self {
100+
network: self.network,
101+
prefix: self.prefix + 1,
102+
}),
103+
}
104+
}
105+
106+
pub fn right_subnet(&self) -> Option<Cidr> {
107+
match self.prefix as u32 {
108+
u32::BITS => None,
109+
_ => {
110+
let prefix = self.prefix + 1;
111+
let shift = u32::BITS - prefix as u32;
112+
Some(Self {
113+
network: (((u32::from(self.network) >> shift) | 1) << shift).into(),
114+
prefix: prefix,
115+
})
116+
}
117+
}
118+
}
119+
120+
pub fn split(&self) -> Option<[Cidr; 2]> {
121+
match (self.left_subnet(), self.right_subnet()) {
122+
(Some(left), Some(right)) => Some([left, right]),
123+
_ => None,
124+
}
103125
}
104126
}
105127

@@ -140,46 +162,70 @@ impl FromStr for Cidr {
140162
.map_err(|e| Error::Parse(e.to_string()))?,
141163
)
142164
} else {
143-
Err(Error::Parse("missing network prefix delimiter".to_owned()))
165+
Err(Error::Parse("missing network prefix delimiter".to_string()))
144166
}
145167
}
146168
}
147169

148-
#[cfg(test)]
149-
mod tests {
150-
use super::*;
151-
152-
// #[test]
153-
// fn cidr_constructor() {
154-
// for prefix in 0..=32 {
155-
// println!("{}", Cidr::new(Ipv4Addr::new(0b10000000, 0, 0, 0), prefix).unwrap());
156-
// println!("{}", Cidr::new(Ipv4Addr::new(0xFF, 0xFF, 0xFF, 0xFF), prefix).unwrap());
157-
// }
158-
// }
159-
160-
// #[test]
161-
// fn cidr_first() {
162-
// let cidr: Cidr = "10.0.0.0/8".parse().unwrap();
163-
// println!("{} / {} : {} -> {}", cidr.network(), cidr.prefix(), cidr.first(), cidr.last());
164-
// let cidr: Cidr = "10.0.0.0/9".parse().unwrap();
165-
// println!("{} / {} : {} -> {}", cidr.network(), cidr.prefix(), cidr.first(), cidr.last());
166-
// let cidr: Cidr = "10.128.0.0/9".parse().unwrap();
167-
// println!("{} / {} : {} -> {}", cidr.network(), cidr.prefix(), cidr.first(), cidr.last());
168-
// let cidr: Cidr = "10.128.0.0/8".parse().unwrap();
169-
// println!("{} / {} : {} -> {}", cidr.network(), cidr.prefix(), cidr.first(), cidr.last());
170-
// }
171-
172-
#[test]
173-
fn it_works() {
174-
// let c: Cidr = "10.0.0.0/8".parse().unwrap();
175-
// let [l, r] = c.split().unwrap();
176-
// println!("{l}, {r}");
177-
// for i in 0..=32 {
178-
// println!("{} {}", i / 8, i % 8);
179-
// }
180-
// let o = 127_u8;
181-
// println!("{}", o == o >> 1 << 1);
182-
// println!("{}", "127.0.343.0".parse::<Ipv4Addr>().unwrap());
183-
// println!("{}", "127.0.343.0".parse::<Cidr>().unwrap());
184-
}
185-
}
170+
// #[cfg(test)]
171+
// mod tests {
172+
// use super::*;
173+
174+
// // #[test]
175+
// // fn does_it_work() {
176+
// // let cidr = Cidr::default();
177+
// // println!("{cidr}");
178+
// // println!("{:?}", cidr.parent());
179+
// // println!("{:?}\n", cidr.split());
180+
// // let cidr: Cidr = "0.0.0.0/0".parse().unwrap();
181+
// // println!("{cidr}");
182+
// // println!("{:?}", cidr.parent());
183+
// // println!("{:?}\n", cidr.split());
184+
// // let cidr: Cidr = "48.0.0.0/4".parse().unwrap();
185+
// // println!("{cidr}");
186+
// // println!("{:?}", cidr.parent());
187+
// // println!("{:?}\n", cidr.split());
188+
// // let cidr: Cidr = "10.0.128.0/25".parse().unwrap();
189+
// // println!("{cidr}");
190+
// // println!("{:?}", cidr.parent());
191+
// // println!("{:?}\n", cidr.split());
192+
// // let cidr: Cidr = "255.255.255.255/32".parse().unwrap();
193+
// // println!("{cidr}");
194+
// // println!("{:?}", cidr.parent());
195+
// // println!("{:?}", cidr.split());
196+
// // }
197+
198+
// // #[test]
199+
// // fn cidr_constructor() {
200+
// // for prefix in 0..=32 {
201+
// // println!("{}", Cidr::new(Ipv4Addr::new(0b10000000, 0, 0, 0), prefix).unwrap());
202+
// // println!("{}", Cidr::new(Ipv4Addr::new(0xFF, 0xFF, 0xFF, 0xFF), prefix).unwrap());
203+
// // }
204+
// // }
205+
206+
// // #[test]
207+
// // fn cidr_first() {
208+
// // let cidr: Cidr = "10.0.0.0/8".parse().unwrap();
209+
// // println!("{} / {} : {} -> {}", cidr.network(), cidr.prefix(), cidr.first(), cidr.last());
210+
// // let cidr: Cidr = "10.0.0.0/9".parse().unwrap();
211+
// // println!("{} / {} : {} -> {}", cidr.network(), cidr.prefix(), cidr.first(), cidr.last());
212+
// // let cidr: Cidr = "10.128.0.0/9".parse().unwrap();
213+
// // println!("{} / {} : {} -> {}", cidr.network(), cidr.prefix(), cidr.first(), cidr.last());
214+
// // let cidr: Cidr = "10.128.0.0/8".parse().unwrap();
215+
// // println!("{} / {} : {} -> {}", cidr.network(), cidr.prefix(), cidr.first(), cidr.last());
216+
// // }
217+
218+
// // #[test]
219+
// // fn it_works() {
220+
// // let c: Cidr = "10.0.0.0/8".parse().unwrap();
221+
// // let [l, r] = c.split().unwrap();
222+
// // println!("{l}, {r}");
223+
// // for i in 0..=32 {
224+
// // println!("{} {}", i / 8, i % 8);
225+
// // }
226+
// // let o = 127_u8;
227+
// // println!("{}", o == o >> 1 << 1);
228+
// // println!("{}", "127.0.343.0".parse::<Ipv4Addr>().unwrap());
229+
// // println!("{}", "127.0.343.0".parse::<Cidr>().unwrap());
230+
// // }
231+
// }

src/error.rs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
use std::{error, fmt};
2+
3+
#[derive(Clone, Debug, Eq, Ord, PartialEq, PartialOrd)]
4+
pub enum Error {
5+
InvalidNetwork(String),
6+
InvalidPrefix(String),
7+
Parse(String),
8+
}
9+
10+
impl fmt::Display for Error {
11+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> std::fmt::Result {
12+
write!(f, "{self:?}")
13+
}
14+
}
15+
16+
impl error::Error for Error {}

0 commit comments

Comments
 (0)