Skip to main content

xdb_parse/
lib.rs

1//! A high-performance, zero-copy parser and query engine for xdb IP geolocation
2//! database files (ip2region-compatible format).
3//!
4//! Supports both IPv4 and IPv6 lookup via an optimized two-level binary search.
5//!
6//! # Quick start
7//!
8//! ```no_run
9//! use xdb_parse::{load_file, search_ip};
10//!
11//! let data = load_file("./assets/ip2region_v4.xdb".into())?;
12//! let location = search_ip("73.24.63.66", &data)?;
13//! println!("{}", location);
14//! # Ok::<(), xdb_parse::error::XdbError>(())
15//! ```
16//!
17//! # Flexible input
18//!
19//! [`search_ip`] accepts any type that implements [`IntoIpAddr`]:
20//!
21//! ```no_run
22//! use xdb_parse::{load_file, search_ip};
23//!
24//! let data = load_file("./assets/ip2region_v4.xdb".into())?;
25//!
26//! // &str or String
27//! search_ip("73.24.63.66", &data)?;
28//!
29//! // raw u32 (fastest IPv4 path)
30//! search_ip(0x4918_3F42u32, &data)?;
31//!
32//! // IpAddr from socket
33//! search_ip("::1".parse::<std::net::IpAddr>()?, &data)?;
34//! # Ok::<(), xdb_parse::error::XdbError>(())
35//! ```
36//!
37//! # Performance
38//!
39//! All search functions return `&str` borrowing from the loaded buffer —
40//! zero allocation per query. For the fastest path, use
41//! [`search_by_uint`] / [`search_by_u128`] to skip trait dispatch.
42//!
43//! # Thread safety
44//!
45//! The loaded `Vec<u8>` is `Send + Sync`. Wrap it in `Arc` to share across threads:
46//!
47//! ```no_run
48//! use std::sync::Arc;
49//! use xdb_parse::{load_file, search_ip};
50//!
51//! let data = Arc::new(load_file("./assets/ip2region_v6.xdb".into())?);
52//! let handle = std::thread::spawn({
53//!     let data = Arc::clone(&data);
54//!     move || search_ip("::1", &data).unwrap()
55//! });
56//! # Ok::<(), xdb_parse::error::XdbError>(())
57//! ```
58
59use std::fs::File;
60use std::io::Read;
61use std::path::PathBuf;
62
63use crate::error::XdbError;
64
65pub(crate) const TOTAL_HEADER_SIZE: usize = 256;
66
67pub(crate) const VECTOR_COL_SIZE: usize = 256;
68pub(crate) const VECTOR_ROW_SIZE: usize = 256;
69pub(crate) const VECTOR_INDEX_BLOCK_SIZE: usize = 8;
70pub(crate) const TOTAL_VECTOR_INDEX_SIZE: usize =
71    VECTOR_COL_SIZE * VECTOR_ROW_SIZE * VECTOR_INDEX_BLOCK_SIZE;
72
73pub(crate) const IPV4_SEGMENT_INDEX_BLOCK_SIZE: u32 = 14;
74pub(crate) const IPV6_SEGMENT_INDEX_BLOCK_SIZE: u32 = 38;
75
76pub mod error;
77pub mod ip;
78pub mod search;
79pub mod xdb;
80
81pub use ip::IntoIpAddr;
82pub use search::{search_by_ipaddr, search_by_u128, search_by_uint, search_ip};
83pub use xdb::{Header, IpVersion, detect_version};
84
85/// Load an xdb database file into memory.
86///
87/// Pre-allocates the buffer with the exact file size to avoid reallocation
88/// during reading.
89///
90/// # Example
91///
92/// ```no_run
93/// let data = xdb_parse::load_file("./assets/ip2region_v4.xdb".into())?;
94/// # Ok::<(), xdb_parse::error::XdbError>(())
95/// ```
96pub fn load_file(path: PathBuf) -> Result<Vec<u8>, XdbError> {
97    let mut file = File::open(&path)?;
98    let mut buf = Vec::with_capacity(file.metadata()?.len() as usize);
99    file.read_to_end(&mut buf)?;
100    Ok(buf)
101}