Skip to main content

LookupResult

Struct LookupResult 

Source
pub struct LookupResult<'a, S: AsRef<[u8]>> { /* private fields */ }
Expand description

The result of looking up an IP address in a MaxMind DB.

This is a lightweight handle (~40 bytes) that stores the lookup result without immediately decoding the data. You can:

§Example

use maxminddb::{geoip2, path, Reader};
use std::net::IpAddr;

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

let result = reader.lookup(ip).unwrap();

if result.has_data() {
    // Full decode
    let city: geoip2::City = result.decode().unwrap().unwrap();

    // Or selective decode via path
    let country_code: Option<String> = result
        .decode_path(&path!["country", "iso_code"])
        .unwrap();
    println!("Country: {:?}", country_code);
}

Implementations§

Source§

impl<'a, S: AsRef<[u8]>> LookupResult<'a, S>

Source

pub fn has_data(&self) -> bool

Returns true if the database contains data for this IP address.

Note that false means the database has no data for this IP, which is different from an error during lookup.

Source

pub fn network(&self) -> Result<IpNetwork, MaxMindDbError>

Returns the network containing the looked-up IP address.

This is the most specific network in the database that contains the IP, regardless of whether data was found.

The returned network preserves the IP version of the original lookup:

  • IPv4 lookups return IPv4 networks (unless the match occurs before the IPv4 subtree begins, see below)
  • IPv6 lookups return IPv6 networks (including IPv4-mapped addresses)

Special case: If an IPv4 address is looked up in an IPv6 database but the matching record is above the IPv4 subtree (e.g., a database with no IPv4 subtree), an IPv6 network is returned since there’s no valid IPv4 representation.

Source

pub fn offset(&self) -> Option<usize>

Returns the data section offset if found, for use as a cache key.

Multiple IP addresses often point to the same data record. This offset can be used to deduplicate decoding or cache results.

Returns None if the IP was not found.

Source

pub fn decode<T>(&self) -> Result<Option<T>, MaxMindDbError>
where T: Deserialize<'a>,

Decodes the full record into the specified type.

Returns:

  • Ok(Some(T)) if found and successfully decoded
  • Ok(None) if the IP was not found in the database
  • Err(...) if decoding fails

Any operation that enters an MMDB map or array has an expansion budget of 65,536 logical values and 2 MiB of string and bytes payload. Dynamic deserialize_any, enum, and raw-string-helper entry points activate the budget before the value’s type is known. Only scalar values requested directly through a typed scalar entry point avoid this bookkeeping. The decoder reserves a container’s declared children before Serde can allocate for them, repeated pointer targets are charged on every expansion, and ignored fields do not expand pointer targets. Exceeding either decoder-wide operation limit returns MaxMindDbError::ResourceLimit rather than treating the database as necessarily corrupt.

Concrete-schema identifiers get a 32-byte allowance per logical value before using the 2 MiB payload counter, whether they are encoded inline or behind a pointer. The logical-value limit bounds all such allowances to another 2 MiB. Thus, after an operation activates its budget, expanded string and byte payload remains bounded to at most 4 MiB even for custom identifier visitors. A scalar-only typed decode remains limited only by the MMDB format’s maximum encoded payload size.

These general limits do not replace tighter bounds implied by an application’s schema. A collection with a small semantic maximum should enforce it in its Deserialize implementation or a Serde deserialize_with visitor, before allocating or consuming its elements. The built-in crate::geoip2::City and crate::geoip2::Enterprise schemas cap their subdivision lists at crate::geoip2::MAX_SUBDIVISIONS in every Serde format. An otherwise valid oversized MMDB list that reaches the schema visitor returns MaxMindDbError::Decoding; malformed data and decoder-wide limits may fail earlier with their corresponding error variants. Custom deserializers that bypass Serde’s map and sequence entry points remain responsible for bounding their own traversal over untrusted data.

§Example
use maxminddb::{Reader, geoip2};
use std::net::IpAddr;

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

let result = reader.lookup(ip).unwrap();
if let Some(city) = result.decode::<geoip2::City>()? {
    println!("Found city data");
}
Source

pub fn decode_path<T>( &self, path: &[PathElement<'_>], ) -> Result<Option<T>, MaxMindDbError>
where T: Deserialize<'a>,

Decodes a value at a specific path within the record.

Returns:

  • Ok(Some(T)) if the path exists and was successfully decoded
  • Ok(None) if the path doesn’t exist (key missing, index out of bounds)
  • Err(...) if there’s a type mismatch during navigation (e.g., Key on an array)

If has_data() == false, returns Ok(None). Path traversal does not expand skipped pointer targets. Navigation and the selected value share the container and payload budgets described by decode(); resource-limit errors include the path reached when the limit was detected.

§Path Elements
  • PathElement::Key("name") - Navigate into a map by key
  • PathElement::Index(0) - Navigate into an array by index (0 = first element)
  • PathElement::IndexFromEnd(0) - Navigate from the end (0 = last element)
§Example
use maxminddb::{path, Reader};
use std::net::IpAddr;

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

let result = reader.lookup(ip).unwrap();

// Navigate to country.iso_code
let iso_code: Option<String> = result
    .decode_path(&path!["country", "iso_code"])
    .unwrap();

// Navigate to subdivisions[0].names.en
let subdiv_name: Option<String> = result
    .decode_path(&path!["subdivisions", 0, "names", "en"])
    .unwrap();

Trait Implementations§

Source§

impl<'a, S: Clone + AsRef<[u8]>> Clone for LookupResult<'a, S>

Source§

fn clone(&self) -> LookupResult<'a, S>

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl<'a, S: Copy + AsRef<[u8]>> Copy for LookupResult<'a, S>

Source§

impl<'a, S: Debug + AsRef<[u8]>> Debug for LookupResult<'a, S>

Source§

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

Formats the value using the given formatter. Read more

Auto Trait Implementations§

§

impl<'a, S> Freeze for LookupResult<'a, S>

§

impl<'a, S> RefUnwindSafe for LookupResult<'a, S>
where S: RefUnwindSafe,

§

impl<'a, S> Send for LookupResult<'a, S>
where S: Sync,

§

impl<'a, S> Sync for LookupResult<'a, S>
where S: Sync,

§

impl<'a, S> Unpin for LookupResult<'a, S>

§

impl<'a, S> UnsafeUnpin for LookupResult<'a, S>

§

impl<'a, S> UnwindSafe for LookupResult<'a, S>
where S: RefUnwindSafe,

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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. 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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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.