Skip to content

Commit b51c3da

Browse files
Merge pull request #12 from nicholaschiasson/minor/tree-node-bugfix
Reimplementation using tree node data structure
2 parents 65c6ed3 + a04c46c commit b51c3da

File tree

5 files changed

+331
-229
lines changed

5 files changed

+331
-229
lines changed

src/cidr.rs

Lines changed: 113 additions & 67 deletions
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

Lines changed: 16 additions & 0 deletions
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)