Struct Reader

Source
pub struct Reader<S: AsRef<[u8]>> {
    pub metadata: Metadata,
    /* private fields */
}
Expand description

A reader for the MaxMind DB format. The lifetime 'data is tied to the lifetime of the underlying buffer holding the contents of the database file.

The Reader supports both file-based and memory-mapped access to MaxMind DB files, including GeoIP2 and GeoLite2 databases.

§Features

  • mmap: Enable memory-mapped file access for better performance
  • simdutf8: Use SIMD-accelerated UTF-8 validation (faster string decoding)
  • unsafe-str-decode: Skip UTF-8 validation entirely (unsafe, but ~20% faster)

Fields§

§metadata: Metadata

Implementations§

Source§

impl Reader<Vec<u8>>

Source

pub fn open_readfile<P: AsRef<Path>>( database: P, ) -> Result<Reader<Vec<u8>>, MaxMindDbError>

Open a MaxMind DB database file by loading it into memory.

§Example
let reader = maxminddb::Reader::open_readfile(
    "test-data/test-data/GeoIP2-City-Test.mmdb").unwrap();
Source§

impl<'de, S: AsRef<[u8]>> Reader<S>

Source

pub fn from_source(buf: S) -> Result<Reader<S>, MaxMindDbError>

Open a MaxMind DB database from anything that implements AsRef<u8>

§Example
use std::fs;
let buf = fs::read("test-data/test-data/GeoIP2-City-Test.mmdb").unwrap();
let reader = maxminddb::Reader::from_source(buf).unwrap();
Source

pub fn lookup<T>( &'de self, address: IpAddr, ) -> Result<Option<T>, MaxMindDbError>
where T: Deserialize<'de>,

Lookup the socket address in the opened MaxMind DB. Returns Ok(None) if the address is not found in the database.

§Examples

Basic city lookup:

let reader = maxminddb::Reader::open_readfile(
    "test-data/test-data/GeoIP2-City-Test.mmdb")?;

let ip: IpAddr = FromStr::from_str("89.160.20.128").unwrap();
match reader.lookup::<geoip2::City>(ip)? {
    Some(city) => {
        if let Some(city_names) = city.city.and_then(|c| c.names) {
            if let Some(name) = city_names.get("en") {
                println!("City: {}", name);
            }
        }
        if let Some(country) = city.country.and_then(|c| c.iso_code) {
            println!("Country: {}", country);
        }
    }
    None => println!("No data found for IP {}", ip),
}

Lookup with different record types:

let reader = maxminddb::Reader::open_readfile(
    "test-data/test-data/GeoIP2-City-Test.mmdb")?;
let ip: IpAddr = "89.160.20.128".parse().unwrap();

// Different record types for the same IP
let city: Option<geoip2::City> = reader.lookup(ip)?;
let country: Option<geoip2::Country> = reader.lookup(ip)?;

println!("City data available: {}", city.is_some());
println!("Country data available: {}", country.is_some());
Source

pub fn lookup_prefix<T>( &'de self, address: IpAddr, ) -> Result<(Option<T>, usize), MaxMindDbError>
where T: Deserialize<'de>,

Lookup the socket address in the opened MaxMind DB, returning the found value (if any) and the prefix length of the network associated with the lookup.

Returns Ok((None, prefix_len)) if the address is found in the tree but has no data record. Returns Err(...) for database errors (IO, corruption, decoding).

Example:

let reader = maxminddb::Reader::open_readfile(
    "test-data/test-data/GeoIP2-City-Test.mmdb")?;

let ip: IpAddr = "89.160.20.128".parse().unwrap(); // Known IP
let ip_unknown: IpAddr = "10.0.0.1".parse().unwrap(); // Unknown IP

let (city_option, prefix_len) = reader.lookup_prefix::<geoip2::City>(ip)?;
if let Some(city) = city_option {
    println!("Found {:?} at prefix length {}", city.city.unwrap().names.unwrap().get("en").unwrap(), prefix_len);
} else {
    // This case is less likely with lookup_prefix if the IP resolves in the tree
    println!("IP found in tree but no data (prefix_len: {})", prefix_len);
}

let (city_option_unknown, prefix_len_unknown) = reader.lookup_prefix::<geoip2::City>(ip_unknown)?;
assert!(city_option_unknown.is_none());
println!("Unknown IP resolved to prefix_len: {}", prefix_len_unknown);
Source

pub fn within<T>( &'de self, cidr: IpNetwork, ) -> Result<Within<'de, T, S>, MaxMindDbError>
where T: Deserialize<'de>,

Iterate over blocks of IP networks in the opened MaxMind DB

This method returns an iterator that yields all IP network blocks that fall within the specified CIDR range and have associated data in the database.

§Examples

Iterate over all IPv4 networks:

use ipnetwork::IpNetwork;
use maxminddb::{geoip2, Within};

let reader = maxminddb::Reader::open_readfile(
    "test-data/test-data/GeoIP2-City-Test.mmdb").unwrap();

let ipv4_all = IpNetwork::V4("0.0.0.0/0".parse().unwrap());
let mut count = 0;
for result in reader.within::<geoip2::City>(ipv4_all).unwrap() {
    let item = result.unwrap();
    let city_name = item.info.city.as_ref().and_then(|c| c.names.as_ref()).and_then(|n| n.get("en"));
    println!("Network: {}, City: {:?}", item.ip_net, city_name);
    count += 1;
    if count >= 10 { break; } // Limit output for example
}

Search within a specific subnet:

use ipnetwork::IpNetwork;
use maxminddb::geoip2;

let reader = maxminddb::Reader::open_readfile(
    "test-data/test-data/GeoIP2-City-Test.mmdb").unwrap();

let subnet = IpNetwork::V4("192.168.0.0/16".parse().unwrap());
match reader.within::<geoip2::City>(subnet) {
    Ok(iter) => {
        for result in iter {
            match result {
                Ok(item) => println!("Found: {}", item.ip_net),
                Err(e) => eprintln!("Error processing item: {}", e),
            }
        }
    }
    Err(e) => eprintln!("Failed to create iterator: {}", e),
}

Trait Implementations§

Source§

impl<S: Debug + AsRef<[u8]>> Debug for Reader<S>

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<S> Freeze for Reader<S>
where S: Freeze,

§

impl<S> RefUnwindSafe for Reader<S>
where S: RefUnwindSafe,

§

impl<S> Send for Reader<S>
where S: Send,

§

impl<S> Sync for Reader<S>
where S: Sync,

§

impl<S> Unpin for Reader<S>
where S: Unpin,

§

impl<S> UnwindSafe for Reader<S>
where S: UnwindSafe,

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.