feat: add ToUIntIP for types ip value
This commit is contained in:
parent
6de37990df
commit
b71f242ce4
|
|
@ -0,0 +1,61 @@
|
|||
use std::error::Error;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::str::FromStr;
|
||||
|
||||
pub trait ToUIntIP {
|
||||
fn to_u32_ip(&self) -> Result<u32, Box<dyn Error>>;
|
||||
}
|
||||
|
||||
impl ToUIntIP for u32 {
|
||||
fn to_u32_ip(&self) -> Result<u32, Box<dyn Error>> {
|
||||
Ok(self.to_owned())
|
||||
}
|
||||
}
|
||||
|
||||
impl ToUIntIP for &str {
|
||||
fn to_u32_ip(&self) -> Result<u32, Box<dyn Error>> {
|
||||
if let Ok(ip_addr) = Ipv4Addr::from_str(self) {
|
||||
return Ok(u32::from(ip_addr));
|
||||
}
|
||||
Ok(self.parse::<u32>()?)
|
||||
}
|
||||
}
|
||||
|
||||
impl ToUIntIP for Ipv4Addr {
|
||||
fn to_u32_ip(&self) -> Result<u32, Box<dyn Error>> {
|
||||
Ok(u32::from(*self))
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod test_ip {
|
||||
use super::*;
|
||||
|
||||
#[test]
|
||||
fn test_ip_str_2_u32() {
|
||||
let ip_str = "1.1.1.1";
|
||||
let result = ip_str.to_u32_ip().unwrap();
|
||||
assert_eq!(result, 1 << 24 | 1 << 16 | 1 << 8 | 1);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ip_u32_str() {
|
||||
let ip = "12";
|
||||
let result = ip.to_u32_ip().unwrap();
|
||||
assert_eq!(result, 12);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ip_u32() {
|
||||
let ip: u32 = 33;
|
||||
let result = ip.to_u32_ip().unwrap();
|
||||
assert_eq!(result, 33);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_ip_addr() {
|
||||
let ip = Ipv4Addr::from_str("0.0.3.12").unwrap();
|
||||
let result = ip.to_u32_ip().unwrap();
|
||||
assert_eq!(result, 3 << 8 | 12)
|
||||
}
|
||||
}
|
||||
|
|
@ -1,8 +1,10 @@
|
|||
mod lib;
|
||||
mod ip_value;
|
||||
mod search;
|
||||
|
||||
fn main() {
|
||||
let filepath = "../../data/ip2region.xdb";
|
||||
let searcher = lib::Searcher::new(filepath).expect("load file error");
|
||||
let result = searcher.search_by_ip("1.2.165.128");
|
||||
println!("{:?}", result);
|
||||
println!("");
|
||||
// let filepath = "../../data/ip2region.xdb";
|
||||
// let searcher = lib::Searcher::new(filepath).expect("load file error");
|
||||
// let result = searcher.search_by_ip("1.2.165.128");
|
||||
// println!("{:?}", result);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,9 @@
|
|||
use std::error::Error;
|
||||
use std::fs::File;
|
||||
use std::io::Read;
|
||||
use std::net::Ipv4Addr;
|
||||
use std::str::FromStr;
|
||||
use crate::ip_value::ToUIntIP;
|
||||
|
||||
const HEADER_INFO_LENGTH: u32 = 256;
|
||||
// const VECTOR_INDEX_ROWS: u32 = 256;
|
||||
|
|
@ -13,22 +16,22 @@ pub struct Searcher {
|
|||
}
|
||||
|
||||
impl Searcher {
|
||||
pub fn new(filepath: &'static str) -> Result<Self, Box<dyn std::error::Error>> {
|
||||
pub fn new(filepath: &'static str) -> Result<Self, Box<dyn Error>> {
|
||||
let mut f = File::open(filepath)?;
|
||||
let mut buffer = Vec::new();
|
||||
f.read_to_end(&mut buffer)?;
|
||||
Ok(Self { buffer })
|
||||
}
|
||||
|
||||
pub fn search_by_ip(&self, ip: &'static str) -> Result<String, Box<dyn std::error::Error>> {
|
||||
let ip = ip.parse::<Ipv4Addr>().unwrap_or_else(|_| {
|
||||
let ip = ip
|
||||
.parse::<u32>()
|
||||
.expect("ip is not a valid ip or valid int");
|
||||
Ipv4Addr::from(ip)
|
||||
});
|
||||
pub fn search_by_ip<T>(&self, ip: T) -> Result<String, Box<dyn Error>>
|
||||
where
|
||||
T: ToUIntIP
|
||||
{
|
||||
let changed_value = ip.to_u32_ip()?;
|
||||
self.search_by_ip_u32(changed_value)
|
||||
}
|
||||
|
||||
let ip = u32::from(ip);
|
||||
pub fn search_by_ip_u32(&self, ip: u32) -> Result<String, Box<dyn Error>> {
|
||||
let il0 = (ip >> 24) & 0xFF;
|
||||
let il1 = (ip >> 16) & 0xFF;
|
||||
let idx = VECTOR_INDEX_SIZE * (il0 * VECTOR_INDEX_COLS + il1);
|
||||
|
|
@ -80,13 +83,39 @@ fn get_u32(bytes: &[u8], offset: usize) -> u32 {
|
|||
mod tests {
|
||||
use super::*;
|
||||
|
||||
///test all types find correct
|
||||
#[test]
|
||||
fn test_search_by_ip() {
|
||||
let filepath = "../../data/ip2region.xdb";
|
||||
let searcher = Searcher::new(filepath).expect("load file error");
|
||||
let result = searcher.search_by_ip("2.0.0.0");
|
||||
println!("{:?}", result);
|
||||
let searcher = Searcher::new(get_xdb_filepath()).expect("load file error");
|
||||
searcher.search_by_ip("2.0.0.0").unwrap();
|
||||
searcher.search_by_ip("32").unwrap();
|
||||
searcher.search_by_ip(32).unwrap();
|
||||
searcher.search_by_ip(Ipv4Addr::from_str("1.1.1.1").unwrap()).unwrap();
|
||||
}
|
||||
|
||||
fn get_xdb_filepath() -> &'static str {
|
||||
"../../data/ip2region.xdb"
|
||||
}
|
||||
|
||||
/// test find ip correct use the file ip.test.txt in ../../data
|
||||
#[test]
|
||||
fn test_random_choose_ip() {
|
||||
let searcher = Searcher::new(get_xdb_filepath()).unwrap();
|
||||
let mut file = File::open("../../data/ip.test.txt").unwrap();
|
||||
let mut contents = String::new();
|
||||
file.read_to_string(&mut contents).unwrap();
|
||||
for line in contents.split("\n") {
|
||||
if !line.contains("|") {
|
||||
continue
|
||||
}
|
||||
let ip_test_line = line.splitn(3, "|").collect::<Vec<&str>>();
|
||||
let start_ip = Ipv4Addr::from_str(ip_test_line[0]).unwrap();
|
||||
let end_ip = Ipv4Addr::from_str(ip_test_line[1]).unwrap();
|
||||
for value in u32::from(start_ip)..u32::from(end_ip) + 1 {
|
||||
let result = searcher.search_by_ip(value).unwrap();
|
||||
assert_eq!(result.as_str(), ip_test_line[2])
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
Loading…
Reference in New Issue