xdb-parse 0.2.0

High-performance, zero-copy xdb IP geolocation parser (ip2region-compatible)
Documentation
//! A high-performance, zero-copy parser and query engine for xdb IP geolocation
//! database files (ip2region-compatible format).
//!
//! Supports both IPv4 and IPv6 lookup via an optimized two-level binary search.
//!
//! # Quick start
//!
//! ```no_run
//! use xdb_parse::{load_file, search_ip};
//!
//! let data = load_file("./assets/ip2region_v4.xdb".into())?;
//! let location = search_ip("73.24.63.66", &data)?;
//! println!("{}", location);
//! # Ok::<(), xdb_parse::error::XdbError>(())
//! ```
//!
//! # Flexible input
//!
//! [`search_ip`] accepts any type that implements [`IntoIpAddr`]:
//!
//! ```no_run
//! use xdb_parse::{load_file, search_ip};
//!
//! let data = load_file("./assets/ip2region_v4.xdb".into())?;
//!
//! // &str or String
//! search_ip("73.24.63.66", &data)?;
//!
//! // raw u32 (fastest IPv4 path)
//! search_ip(0x4918_3F42u32, &data)?;
//!
//! // IpAddr from socket
//! search_ip("::1".parse::<std::net::IpAddr>()?, &data)?;
//! # Ok::<(), xdb_parse::error::XdbError>(())
//! ```
//!
//! # Performance
//!
//! All search functions return `&str` borrowing from the loaded buffer —
//! zero allocation per query. For the fastest path, use
//! [`search_by_uint`] / [`search_by_u128`] to skip trait dispatch.
//!
//! # Thread safety
//!
//! The loaded `Vec<u8>` is `Send + Sync`. Wrap it in `Arc` to share across threads:
//!
//! ```no_run
//! use std::sync::Arc;
//! use xdb_parse::{load_file, search_ip};
//!
//! let data = Arc::new(load_file("./assets/ip2region_v6.xdb".into())?);
//! let handle = std::thread::spawn({
//!     let data = Arc::clone(&data);
//!     move || search_ip("::1", &data).unwrap()
//! });
//! # Ok::<(), xdb_parse::error::XdbError>(())
//! ```

use std::fs::File;
use std::io::Read;
use std::path::PathBuf;

use crate::error::XdbError;

pub(crate) const TOTAL_HEADER_SIZE: usize = 256;

pub(crate) const VECTOR_COL_SIZE: usize = 256;
pub(crate) const VECTOR_ROW_SIZE: usize = 256;
pub(crate) const VECTOR_INDEX_BLOCK_SIZE: usize = 8;
pub(crate) const TOTAL_VECTOR_INDEX_SIZE: usize =
    VECTOR_COL_SIZE * VECTOR_ROW_SIZE * VECTOR_INDEX_BLOCK_SIZE;

pub(crate) const IPV4_SEGMENT_INDEX_BLOCK_SIZE: u32 = 14;
pub(crate) const IPV6_SEGMENT_INDEX_BLOCK_SIZE: u32 = 38;

pub mod error;
pub mod ip;
pub mod search;
pub mod xdb;

pub use ip::IntoIpAddr;
pub use search::{search_by_ipaddr, search_by_u128, search_by_uint, search_ip};
pub use xdb::{Header, IpVersion, detect_version};

/// Load an xdb database file into memory.
///
/// Pre-allocates the buffer with the exact file size to avoid reallocation
/// during reading.
///
/// # Example
///
/// ```no_run
/// let data = xdb_parse::load_file("./assets/ip2region_v4.xdb".into())?;
/// # Ok::<(), xdb_parse::error::XdbError>(())
/// ```
pub fn load_file(path: PathBuf) -> Result<Vec<u8>, XdbError> {
    let mut file = File::open(&path)?;
    let mut buf = Vec::with_capacity(file.metadata()?.len() as usize);
    file.read_to_end(&mut buf)?;
    Ok(buf)
}