From f5123bbe731d6152a142dc91e5dd454b82559c6d Mon Sep 17 00:00:00 2001 From: gongzhengyang Date: Mon, 19 Dec 2022 14:36:09 +0800 Subject: [PATCH] =?UTF-8?q?feat:=20=E5=88=9D=E5=A7=8B=E5=8C=96=E5=A2=9E?= =?UTF-8?q?=E5=8A=A0rust=E6=9F=A5=E8=AF=A2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- binding/rust/Cargo.toml | 8 ++++ binding/rust/src/lib.rs | 88 ++++++++++++++++++++++++++++++++++++++++ binding/rust/src/main.rs | 5 +++ 3 files changed, 101 insertions(+) create mode 100644 binding/rust/Cargo.toml create mode 100644 binding/rust/src/lib.rs create mode 100644 binding/rust/src/main.rs diff --git a/binding/rust/Cargo.toml b/binding/rust/Cargo.toml new file mode 100644 index 0000000..1ec6963 --- /dev/null +++ b/binding/rust/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "rust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/binding/rust/src/lib.rs b/binding/rust/src/lib.rs new file mode 100644 index 0000000..5896672 --- /dev/null +++ b/binding/rust/src/lib.rs @@ -0,0 +1,88 @@ +use std::fs::File; +use std::net::{IpAddr, Ipv4Addr}; +use std::io::{Read, Bytes}; + +fn main() {} + +const HEADER_INFO_LENGTH: u32 = 256; +const VECTOR_INDEX_ROWS: u32 = 256; +const VECTOR_INDEX_COLS: u32 = 256; +const VECTOR_INDEX_SIZE: u32 = 8; +const SEGMENT_INDEX_SIZE: usize = 14; + +pub struct Searcher { + pub buffer: Vec, +} + +impl Searcher { + pub fn new(filepath: &'static str) -> Result> { + 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> { + let ip = ip.parse::().unwrap_or_else(|_| { + let ip = ip.parse::().expect("ip is not a valid ip or valid int"); + Ipv4Addr::from(ip) + }); + println!("{:?}", ip); + + let ip = u32::from(ip); + let il0 = (ip >> 24) & 0xFF; + let il1 = (ip >> 16) & 0xFF; + let idx = VECTOR_INDEX_SIZE * (il0 * VECTOR_INDEX_SIZE * VECTOR_INDEX_COLS + il1); + + let start_ptr = get_u32(&self.buffer, (HEADER_INFO_LENGTH + idx) as usize); + let end_ptr = get_u32(&self.buffer, (HEADER_INFO_LENGTH + idx+4) as usize); + + let mut left: usize= 0; + let mut right: usize = ((end_ptr - start_ptr) as usize )/SEGMENT_INDEX_SIZE; + while left < right { + let mid = (left + right) >> 1; + let offset = start_ptr as usize + mid * SEGMENT_INDEX_SIZE; + let buffer_ip_value = self.buffer_value(offset, SEGMENT_INDEX_SIZE); + let start_ip = get_u32(buffer_ip_value, 0); + if ip < start_ip { + right = mid - 1; + } else if ip > get_u32(buffer_ip_value, 4) { + left = mid + 1; + } else { + let length = (self.buffer[offset] as usize & 0x000000FF) | (self.buffer[offset + 1] as usize & 0x0000FF00); + let offset = get_u32(&self.buffer, 10); + let result = self.buffer_value(offset as usize, length as usize).iter().map(|x| x.to_owned()).collect::>(); + return Ok(String::from_utf8(result)?); + } + } + Err("not matched".into()) + + } + + pub fn buffer_value(&self, offset: usize, length: usize) -> &[u8] { + &self.buffer[offset..offset+length] + } +} + +fn get_u32(bytes: &[u8], offset: usize) -> u32 { + let offset = offset as usize; + let tmp = (bytes[offset] as i64) & 0x000000FF + | ((bytes[offset + 1] as i64) << 8) & 0x0000FF00 + | ((bytes[offset + 2] as i64) << 16) & 0x00FF0000 + | ((bytes[offset + 3] as i64) << 24) & 0xFF000000; + tmp as u32 +} + +#[cfg(test)] +mod tests { + use super::*; + + #[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("1.0.0.0"); + println!("{:?}", result); + + } +} \ No newline at end of file diff --git a/binding/rust/src/main.rs b/binding/rust/src/main.rs new file mode 100644 index 0000000..7605184 --- /dev/null +++ b/binding/rust/src/main.rs @@ -0,0 +1,5 @@ +mod lib; + +fn main() { + println!("Hello, world!"); +}