Skip to content

Commit b3258ec

Browse files
authored
Merge pull request #90 from oschwald/greg/no-vec
Use integer enum for internal IP uses
2 parents 997a739 + 5c79da9 commit b3258ec

File tree

2 files changed

+77
-81
lines changed

2 files changed

+77
-81
lines changed

src/maxminddb/decoder.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -382,7 +382,7 @@ struct ArrayAccess<'a, 'de: 'a> {
382382

383383
// `SeqAccess` is provided to the `Visitor` to give it the ability to iterate
384384
// through elements of the sequence.
385-
impl<'de, 'a> SeqAccess<'de> for ArrayAccess<'a, 'de> {
385+
impl<'de> SeqAccess<'de> for ArrayAccess<'_, 'de> {
386386
type Error = MaxMindDBError;
387387

388388
fn next_element_seed<T>(&mut self, seed: T) -> DecodeResult<Option<T::Value>>
@@ -407,7 +407,7 @@ struct MapAccessor<'a, 'de: 'a> {
407407

408408
// `MapAccess` is provided to the `Visitor` to give it the ability to iterate
409409
// through entries of the map.
410-
impl<'de, 'a> MapAccess<'de> for MapAccessor<'a, 'de> {
410+
impl<'de> MapAccess<'de> for MapAccessor<'_, 'de> {
411411
type Error = MaxMindDBError;
412412

413413
fn next_key_seed<K>(&mut self, seed: K) -> DecodeResult<Option<K::Value>>

src/maxminddb/lib.rs

Lines changed: 75 additions & 79 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,7 @@ pub struct Metadata {
8181
#[derive(Debug)]
8282
struct WithinNode {
8383
node: usize,
84-
ip_bytes: Vec<u8>,
84+
ip_int: IpInt,
8585
prefix_len: usize,
8686
}
8787

@@ -99,32 +99,66 @@ pub struct WithinItem<T> {
9999
pub info: T,
100100
}
101101

102+
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
103+
enum IpInt {
104+
V4(u32),
105+
V6(u128),
106+
}
107+
108+
impl IpInt {
109+
fn new(ip_addr: IpAddr) -> Self {
110+
match ip_addr {
111+
IpAddr::V4(v4) => IpInt::V4(v4.into()),
112+
IpAddr::V6(v6) => IpInt::V6(v6.into()),
113+
}
114+
}
115+
116+
fn get_bit(&self, index: usize) -> bool {
117+
match self {
118+
IpInt::V4(ip) => (ip >> (31 - index)) & 1 == 1,
119+
IpInt::V6(ip) => (ip >> (127 - index)) & 1 == 1,
120+
}
121+
}
122+
123+
fn bit_count(&self) -> usize {
124+
match self {
125+
IpInt::V4(_) => 32,
126+
IpInt::V6(_) => 128,
127+
}
128+
}
129+
130+
fn is_ipv4_in_ipv6(&self) -> bool {
131+
match self {
132+
IpInt::V4(_) => false,
133+
IpInt::V6(ip) => *ip <= 0xFFFFFFFF,
134+
}
135+
}
136+
}
137+
102138
impl<'de, T: Deserialize<'de>, S: AsRef<[u8]>> Iterator for Within<'de, T, S> {
103139
type Item = Result<WithinItem<T>, MaxMindDBError>;
104140

105141
fn next(&mut self) -> Option<Self::Item> {
106142
while let Some(current) = self.stack.pop() {
107-
let bit_count = current.ip_bytes.len() * 8;
143+
let bit_count = current.ip_int.bit_count();
108144

109145
// Skip networks that are aliases for the IPv4 network
110146
if self.reader.ipv4_start != 0
111147
&& current.node == self.reader.ipv4_start
112148
&& bit_count == 128
113-
&& current.ip_bytes[..12].iter().any(|&b| b != 0)
149+
&& !current.ip_int.is_ipv4_in_ipv6()
114150
{
115151
continue;
116152
}
117153

118154
match current.node.cmp(&self.node_count) {
119155
Ordering::Greater => {
120156
// This is a data node, emit it and we're done (until the following next call)
121-
let ip_net = match bytes_and_prefix_to_net(
122-
&current.ip_bytes,
123-
current.prefix_len as u8,
124-
) {
125-
Ok(ip_net) => ip_net,
126-
Err(e) => return Some(Err(e)),
127-
};
157+
let ip_net =
158+
match bytes_and_prefix_to_net(&current.ip_int, current.prefix_len as u8) {
159+
Ok(ip_net) => ip_net,
160+
Err(e) => return Some(Err(e)),
161+
};
128162
// TODO: should this block become a helper method on reader?
129163
let rec = match self.reader.resolve_data_pointer(current.node) {
130164
Ok(rec) => rec,
@@ -145,16 +179,23 @@ impl<'de, T: Deserialize<'de>, S: AsRef<[u8]>> Iterator for Within<'de, T, S> {
145179
Ordering::Less => {
146180
// In order traversal of our children
147181
// right/1-bit
148-
let mut right_ip_bytes = current.ip_bytes.clone();
149-
right_ip_bytes[current.prefix_len >> 3] |=
150-
1 << ((bit_count - current.prefix_len - 1) % 8);
182+
let mut right_ip_int = current.ip_int;
183+
184+
if current.prefix_len < bit_count {
185+
let bit = current.prefix_len;
186+
match &mut right_ip_int {
187+
IpInt::V4(ip) => *ip |= 1 << (31 - bit),
188+
IpInt::V6(ip) => *ip |= 1 << (127 - bit),
189+
};
190+
}
191+
151192
let node = match self.reader.read_node(current.node, 1) {
152193
Ok(node) => node,
153194
Err(e) => return Some(Err(e)),
154195
};
155196
self.stack.push(WithinNode {
156197
node,
157-
ip_bytes: right_ip_bytes,
198+
ip_int: right_ip_int,
158199
prefix_len: current.prefix_len + 1,
159200
});
160201
// left/0-bit
@@ -164,7 +205,7 @@ impl<'de, T: Deserialize<'de>, S: AsRef<[u8]>> Iterator for Within<'de, T, S> {
164205
};
165206
self.stack.push(WithinNode {
166207
node,
167-
ip_bytes: current.ip_bytes.clone(),
208+
ip_int: current.ip_int,
168209
prefix_len: current.prefix_len + 1,
169210
});
170211
}
@@ -286,8 +327,8 @@ impl<'de, S: AsRef<[u8]>> Reader<S> {
286327
where
287328
T: Deserialize<'de>,
288329
{
289-
let ip_bytes = ip_to_bytes(address);
290-
let (pointer, prefix_len) = self.find_address_in_tree(&ip_bytes)?;
330+
let ip_int = IpInt::new(address);
331+
let (pointer, prefix_len) = self.find_address_in_tree(&ip_int)?;
291332
if pointer == 0 {
292333
return Err(MaxMindDBError::AddressNotFoundError(
293334
"Address not found in database".to_owned(),
@@ -317,14 +358,14 @@ impl<'de, S: AsRef<[u8]>> Reader<S> {
317358
/// println!("ip_net={}, city={:?}", item.ip_net, item.info);
318359
/// }
319360
/// ```
320-
pub fn within<T>(&'de self, cidr: IpNetwork) -> Result<Within<T, S>, MaxMindDBError>
361+
pub fn within<T>(&'de self, cidr: IpNetwork) -> Result<Within<'de, T, S>, MaxMindDBError>
321362
where
322363
T: Deserialize<'de>,
323364
{
324365
let ip_address = cidr.network();
325366
let prefix_len = cidr.prefix() as usize;
326-
let ip_bytes = ip_to_bytes(ip_address);
327-
let bit_count = ip_bytes.len() * 8;
367+
let ip_int = IpInt::new(ip_address);
368+
let bit_count = ip_int.bit_count();
328369

329370
let mut node = self.start_node(bit_count);
330371
let node_count = self.metadata.node_count as usize;
@@ -334,8 +375,8 @@ impl<'de, S: AsRef<[u8]>> Reader<S> {
334375
// Traverse down the tree to the level that matches the cidr mark
335376
let mut i = 0_usize;
336377
while i < prefix_len {
337-
let bit = 1 & (ip_bytes[i >> 3] >> (7 - (i % 8))) as usize;
338-
node = self.read_node(node, bit)?;
378+
let bit = ip_int.get_bit(i);
379+
node = self.read_node(node, bit as usize)?;
339380
if node >= node_count {
340381
// We've hit a dead end before we exhausted our prefix
341382
break;
@@ -349,7 +390,7 @@ impl<'de, S: AsRef<[u8]>> Reader<S> {
349390
// traversed to as our to be processed stack.
350391
stack.push(WithinNode {
351392
node,
352-
ip_bytes,
393+
ip_int,
353394
prefix_len,
354395
});
355396
}
@@ -366,8 +407,8 @@ impl<'de, S: AsRef<[u8]>> Reader<S> {
366407
Ok(within)
367408
}
368409

369-
fn find_address_in_tree(&self, ip_address: &[u8]) -> Result<(usize, usize), MaxMindDBError> {
370-
let bit_count = ip_address.len() * 8;
410+
fn find_address_in_tree(&self, ip_int: &IpInt) -> Result<(usize, usize), MaxMindDBError> {
411+
let bit_count = ip_int.bit_count();
371412
let mut node = self.start_node(bit_count);
372413

373414
let node_count = self.metadata.node_count as usize;
@@ -378,8 +419,7 @@ impl<'de, S: AsRef<[u8]>> Reader<S> {
378419
prefix_len = i;
379420
break;
380421
}
381-
let bit = 1 & (ip_address[i >> 3] >> (7 - (i % 8)));
382-
422+
let bit = ip_int.get_bit(i);
383423
node = self.read_node(node, bit as usize)?;
384424
}
385425
match node_count {
@@ -472,60 +512,16 @@ fn to_usize(base: u8, bytes: &[u8]) -> usize {
472512
.fold(base as usize, |acc, &b| (acc << 8) | b as usize)
473513
}
474514

475-
fn ip_to_bytes(address: IpAddr) -> Vec<u8> {
476-
match address {
477-
IpAddr::V4(a) => a.octets().to_vec(),
478-
IpAddr::V6(a) => a.octets().to_vec(),
479-
}
480-
}
481-
482-
#[allow(clippy::many_single_char_names)]
483-
fn bytes_and_prefix_to_net(bytes: &[u8], prefix: u8) -> Result<IpNetwork, MaxMindDBError> {
484-
let (ip, pre) = match bytes.len() {
485-
4 => (
486-
IpAddr::V4(Ipv4Addr::new(bytes[0], bytes[1], bytes[2], bytes[3])),
487-
prefix,
488-
),
489-
16 => {
490-
if bytes[0] == 0
491-
&& bytes[1] == 0
492-
&& bytes[2] == 0
493-
&& bytes[3] == 0
494-
&& bytes[4] == 0
495-
&& bytes[5] == 0
496-
&& bytes[6] == 0
497-
&& bytes[7] == 0
498-
&& bytes[8] == 0
499-
&& bytes[9] == 0
500-
&& bytes[10] == 0
501-
&& bytes[11] == 0
502-
{
503-
// It's actually v4, but in v6 form, convert would be nice if ipnetwork had this
504-
// logic.
505-
(
506-
IpAddr::V4(Ipv4Addr::new(bytes[12], bytes[13], bytes[14], bytes[15])),
507-
prefix - 96,
508-
)
509-
} else {
510-
let a = u16::from(bytes[0]) << 8 | u16::from(bytes[1]);
511-
let b = u16::from(bytes[2]) << 8 | u16::from(bytes[3]);
512-
let c = u16::from(bytes[4]) << 8 | u16::from(bytes[5]);
513-
let d = u16::from(bytes[6]) << 8 | u16::from(bytes[7]);
514-
let e = u16::from(bytes[8]) << 8 | u16::from(bytes[9]);
515-
let f = u16::from(bytes[10]) << 8 | u16::from(bytes[11]);
516-
let g = u16::from(bytes[12]) << 8 | u16::from(bytes[13]);
517-
let h = u16::from(bytes[14]) << 8 | u16::from(bytes[15]);
518-
(IpAddr::V6(Ipv6Addr::new(a, b, c, d, e, f, g, h)), prefix)
519-
}
520-
}
521-
// This should never happen
522-
_ => {
523-
return Err(MaxMindDBError::InvalidNetworkError(
524-
"invalid address".to_owned(),
525-
))
515+
#[inline]
516+
fn bytes_and_prefix_to_net(bytes: &IpInt, prefix: u8) -> Result<IpNetwork, MaxMindDBError> {
517+
let (ip, prefix) = match bytes {
518+
IpInt::V4(ip) => (IpAddr::V4(Ipv4Addr::from(*ip)), prefix),
519+
IpInt::V6(ip) if bytes.is_ipv4_in_ipv6() => {
520+
(IpAddr::V4(Ipv4Addr::from(*ip as u32)), prefix - 96)
526521
}
522+
IpInt::V6(ip) => (IpAddr::V6(Ipv6Addr::from(*ip)), prefix),
527523
};
528-
IpNetwork::new(ip, pre).map_err(|e| MaxMindDBError::InvalidNetworkError(e.to_string()))
524+
IpNetwork::new(ip, prefix).map_err(|e| MaxMindDBError::InvalidNetworkError(e.to_string()))
529525
}
530526

531527
fn find_metadata_start(buf: &[u8]) -> Result<usize, MaxMindDBError> {

0 commit comments

Comments
 (0)