xdb-parse 0.2.0

High-performance, zero-copy xdb IP geolocation parser (ip2region-compatible)
Documentation
# xdb-parse

高性能、零拷贝的 xdb IP 地理位置数据库查询库(兼容 ip2region 格式)。基于优化的两级二分查找算法,同时支持 IPv4 和 IPv6。

[English](README.md)

## 特性

- **双协议支持**:完整的 IPv4 和 IPv6 查询
- **极速查询**:IPv4 `search_ip(u32)` 约 258ns,`search_ip(&str)` 约 527ns(全量 segment IP 池)
- **零拷贝**:返回 `&str` 直接从已加载数据借用,每次查询无堆分配
- **原始整数 API**`search_by_uint` / `search_by_u128` 完全跳过字符串解析
- **线程安全**`Send + Sync`,加载一次即可通过 `Arc` 在多线程中共享

## 安装

```toml
[dependencies]
xdb-parse = "0.2.0"
```

## 快速上手

```rust
use xdb_parse::{load_file, search_ip};

fn main() -> anyhow::Result<()> {
    let data = load_file("./assets/ip2region_v4.xdb".into())?;
    let location = search_ip("73.24.63.66", &data)?;
    println!("{}", location);
    Ok(())
}
```

## API 参考

### 加载

```rust
pub fn load_file(path: PathBuf) -> Result<Vec<u8>, XdbError>
```

预分配精确文件大小的缓冲区,避免读取时多次重分配。

### 查询

```rust
// 通过 IP 字符串查询(支持点分十进制、冒号十六进制、数字字符串)
pub fn search_ip(ip: &str, data: &[u8]) -> Result<&str, XdbError>

// 通过原始 u32 查询(IPv4)— 最快路径
pub fn search_by_uint(ip: u32, data: &[u8]) -> Result<&str, XdbError>

// 通过原始 u128 查询(IPv6)— 最快路径
pub fn search_by_u128(ip: u128, data: &[u8]) -> Result<&str, XdbError>

// 通过 std::net::IpAddr 查询
pub fn search_by_ipaddr(ip: IpAddr, data: &[u8]) -> Result<&str, XdbError>
```

所有查询函数返回 `&str` 借用已加载数据 — 每次查询零堆分配。

### 支持的 IP 格式

```rust
search_ip("192.168.1.1", &data)?;                                // 标准 IPv4
search_ip("2001:0db8:85a3::0370:7334", &data)?;                  // 标准 IPv6
search_ip("3232235777", &data)?;                                  // 数字格式 IPv4
search_ip("42540766411282592856903984951653826560", &data)?;      // 数字格式 IPv6
```

### Header 与版本检测

```rust
use xdb_parse::{Header, IpVersion, detect_version};

let data = load_file("./assets/ip2region_v4.xdb".into())?;
let version = detect_version(&data)?;
assert_eq!(version, IpVersion::V4);

let header = Header::parse(&data)?;
println!("xdb 版本: {}, 生成时间戳: {}", header.version, header.generation_time);
```

## 多线程使用

```rust
use std::sync::Arc;
use xdb_parse::{load_file, search_ip};

let data = Arc::new(load_file("./assets/ip2region_v6.xdb".into())?);

let data_clone = Arc::clone(&data);
std::thread::spawn(move || {
    let result = search_ip("2408:8352:da10:1ad:c283:c9ff:fec6:4046", &data_clone).unwrap();
    println!("{}", result);
}).join().unwrap();
```

## 性能

使用全量 segment IP 池测量(52 万 IPv4 / 70 万 IPv6),criterion release 模式:

| 场景 | 耗时 |
|------|------|
| IPv4 `search_by_uint` | ~272 ns |
| IPv4 `search_ip(u32)` | ~258 ns |
| IPv4 `search_ip(&str)` | ~527 ns |
| IPv6 `search_ip(&str)` | ~476 ns |

运行基准测试:
```bash
cargo bench
```

## 数据库文件格式

```
┌─────────────────┐
│     Header      │ 256 字节
├─────────────────┤
│   Vector Index  │ 256×256×8 字节
├─────────────────┤
│  Segment Data   │ 可变长度
└─────────────────┘
```

IPv4 segment:14 字节(`u32` 起始, `u32` 结束, `u16` 数据长度, `u32` 数据指针)。
IPv6 segment:38 字节(`u128` 起始, `u128` 结束, `u16` 数据长度, `u32` 数据指针)。

## 算法

1. 解析 IP 字符串为 `IpAddr`(支持 `"192.168.1.1"``"::1"`、数字 `"3232235777"` 等格式)
2. 取 IP 的前两个字节作为 row(`il0`)和 col(`il1`),在 256×256 向量索引中查找
3. 向量索引条目给出 segment 数据中的 `[start_ptr, end_ptr)` 范围
4. 在该范围内对 segment 进行二分查找(segment 按 IP 起始地址排序)
5. 返回匹配 segment 对应的地理位置字符串

## License

MIT OR Apache-2.0