xdb-parse 0.2.0

High-performance, zero-copy xdb IP geolocation parser (ip2region-compatible)
Documentation
use std::net::{IpAddr, Ipv4Addr, Ipv6Addr};
use std::str::FromStr;

use crate::error::XdbError;

/// Types that can be converted to an [`IpAddr`] for IP lookup.
///
/// Implemented for common IP representations so [`crate::search_ip`] accepts
/// `&str`, `String`, `u32`, `u128`, `IpAddr`, `Ipv4Addr`, and `Ipv6Addr`.
pub trait IntoIpAddr {
    fn into_ip_addr(self) -> Result<IpAddr, XdbError>;
}

impl IntoIpAddr for IpAddr {
    fn into_ip_addr(self) -> Result<IpAddr, XdbError> {
        Ok(self)
    }
}

impl IntoIpAddr for Ipv4Addr {
    fn into_ip_addr(self) -> Result<IpAddr, XdbError> {
        Ok(IpAddr::V4(self))
    }
}

impl IntoIpAddr for Ipv6Addr {
    fn into_ip_addr(self) -> Result<IpAddr, XdbError> {
        Ok(IpAddr::V6(self))
    }
}

impl IntoIpAddr for u32 {
    fn into_ip_addr(self) -> Result<IpAddr, XdbError> {
        Ok(IpAddr::V4(Ipv4Addr::from(self)))
    }
}

impl IntoIpAddr for u128 {
    fn into_ip_addr(self) -> Result<IpAddr, XdbError> {
        Ok(IpAddr::V6(Ipv6Addr::from(self)))
    }
}

impl IntoIpAddr for &str {
    fn into_ip_addr(self) -> Result<IpAddr, XdbError> {
        parse_ip(self)
    }
}

impl IntoIpAddr for String {
    fn into_ip_addr(self) -> Result<IpAddr, XdbError> {
        parse_ip(&self)
    }
}

impl IntoIpAddr for &String {
    fn into_ip_addr(self) -> Result<IpAddr, XdbError> {
        parse_ip(self)
    }
}

pub(crate) fn parse_ip(ip: &str) -> Result<IpAddr, XdbError> {
    if ip.contains('.') || ip.contains(':') {
        return Ok(IpAddr::from_str(ip)?);
    }
    if let Ok(num) = ip.parse::<u32>() {
        return Ok(IpAddr::V4(Ipv4Addr::from(num)));
    }
    if let Ok(num) = ip.parse::<u128>() {
        return Ok(IpAddr::V6(Ipv6Addr::from(num)));
    }
    Err(XdbError::InvalidIP("invalid IP or number".into()))
}