pub struct Reader<'a> { /* private fields */ }Expand description
Parsed MaxMind DB reader.
Opening from &[u8] does not copy the database bytes. Opening prepares
native-endian children for every valid record size; common 24/28/32-bit
records also use a cache-aligned tree and bounded byte-stride or radix tables.
This increases open time and reader memory use, but the first lookup performs
no index construction. Generic lookup_value materializes map and
array containers; typed borrowed decoding avoids those containers.
Implementations§
Source§impl Reader<'static>
impl Reader<'static>
Sourcepub fn open(path: impl AsRef<Path>) -> Result<Self>
pub fn open(path: impl AsRef<Path>) -> Result<Self>
Opens a MaxMind DB file into an owned byte buffer.
Returns an I/O or format error if the file cannot be read or validated. Preparing the search-tree index is part of the open cost.
§Examples
use libmaxminddb_rs::Reader;
let path = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/doc.mmdb");
let reader = Reader::open(path)?;
assert_eq!(reader.metadata().ip_version, 4);Sourcepub unsafe fn open_mmap(path: impl AsRef<Path>) -> Result<Self>
pub unsafe fn open_mmap(path: impl AsRef<Path>) -> Result<Self>
Opens a MaxMind DB file through a read-only memory mapping. The search-tree index is prepared before this method returns.
§Safety
The mapped file must not be modified or truncated for as long as the returned reader exists. Violating this operating-system mmap requirement can make subsequent memory accesses invalid.
§Examples
use libmaxminddb_rs::Reader;
let path = concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/doc.mmdb");
// SAFETY: This checked-in fixture is not changed while the reader exists.
let reader = unsafe { Reader::open_mmap(path)? };
assert_eq!(reader.metadata().ip_version, 4);Sourcepub fn from_vec(data: Vec<u8>) -> Result<Self>
pub fn from_vec(data: Vec<u8>) -> Result<Self>
Builds a reader that owns the provided bytes.
Returns a format error when the byte vector is not a valid MMDB. The search-tree index is prepared before this method returns.
§Examples
use libmaxminddb_rs::Reader;
let bytes = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/doc.mmdb"));
let reader = Reader::from_vec(bytes.to_vec())?;
assert_eq!(reader.metadata().ip_version, 4);Source§impl<'a> Reader<'a>
impl<'a> Reader<'a>
Sourcepub fn from_bytes(data: &'a [u8]) -> Result<Self>
pub fn from_bytes(data: &'a [u8]) -> Result<Self>
Opens a MaxMind DB directly from a borrowed byte slice without copying it. Returns a format error when the bytes are not a valid MMDB. The search-tree index is prepared before this method returns.
§Examples
use libmaxminddb_rs::Reader;
let bytes = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/doc.mmdb"));
let reader = Reader::from_bytes(bytes)?;
assert_eq!(reader.metadata().ip_version, 4);Sourcepub const fn metadata(&self) -> &Metadata
pub const fn metadata(&self) -> &Metadata
Returns parsed database metadata.
§Examples
use libmaxminddb_rs::Reader;
let bytes = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/doc.mmdb"));
let reader = Reader::from_bytes(bytes)?;
assert_eq!(reader.metadata().database_type, "libmaxminddb-rs-compat");Sourcepub fn as_bytes(&self) -> &[u8] ⓘ
pub fn as_bytes(&self) -> &[u8] ⓘ
Returns the underlying database bytes.
§Examples
use libmaxminddb_rs::Reader;
let bytes = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/doc.mmdb"));
let reader = Reader::from_bytes(bytes)?;
assert_eq!(reader.as_bytes(), bytes);Sourcepub fn lookup_value(&self, ip: IpAddr) -> Result<ValueRef<'_>>
pub fn lookup_value(&self, ip: IpAddr) -> Result<ValueRef<'_>>
Looks up an IP and returns a borrowed generic value.
Returns Error::NotFound on a miss; malformed data can also produce a decode error.
§Examples
use libmaxminddb_rs::Reader;
let bytes = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/doc.mmdb"));
let reader = Reader::from_bytes(bytes)?;
let value = reader.lookup_value("203.0.113.7".parse()?)?;
assert!(value.get("country").is_some());Sourcepub fn lookup_value_with_prefix(&self, ip: IpAddr) -> Result<(ValueRef<'_>, u8)>
pub fn lookup_value_with_prefix(&self, ip: IpAddr) -> Result<(ValueRef<'_>, u8)>
Looks up an IP and returns the borrowed value and matched prefix length.
Returns Error::NotFound on a miss. The prefix is the matched network’s
CIDR length, not the address width.
§Examples
use libmaxminddb_rs::Reader;
let bytes = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/doc.mmdb"));
let reader = Reader::from_bytes(bytes)?;
let (_, prefix) = reader.lookup_value_with_prefix("203.0.113.7".parse()?)?;
assert_eq!(prefix, 24);Sourcepub fn lookup_borrowed<'s, T>(&'s self, ip: IpAddr) -> Result<T>where
T: MmdbDecode<'s>,
pub fn lookup_borrowed<'s, T>(&'s self, ip: IpAddr) -> Result<T>where
T: MmdbDecode<'s>,
Decodes an IP record into a user type generated with #[derive(MmdbDecode)].
Derived types are decoded in a single pass straight from the database
bytes: strings borrow the buffer, unknown fields are skipped without
being decoded, and no intermediate ValueRef tree is built, so the
lookup performs no heap allocation beyond the Vec/String fields the
target type itself owns.
Returns Error::NotFound when the IP matches no network in the
database. No record is decoded on this miss path.
The traversal and miss handling stay on the inlined fast path; only a
hit enters the (cold) decode machinery. This keeps the dominant miss
case from materializing the large Result<T, Error> return value that
a user-sized T (for example a CityRecord) would force onto the
hot loop, and lets lookup_borrowed match tree-only traversal on the miss
path.
§Examples
use libmaxminddb_rs::{MmdbDecode, Reader};
#[derive(MmdbDecode)]
struct Record<'a> { category: &'a str }
let bytes = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/doc.mmdb"));
let reader = Reader::from_bytes(bytes)?;
let record: Record<'_> = reader.lookup_borrowed("203.0.113.7".parse()?)?;
assert_eq!(record.category, "compat");Sourcepub fn lookup_borrowed_opt<'s, T>(&'s self, ip: IpAddr) -> Option<T>where
T: MmdbDecode<'s>,
pub fn lookup_borrowed_opt<'s, T>(&'s self, ip: IpAddr) -> Option<T>where
T: MmdbDecode<'s>,
Like lookup_borrowed but returns Option<T>
instead of Result<T, Error>.
On a miss the function returns None without ever constructing the
Error enum. This avoids the out-of-line Error drop-glue that the
Result<T, Error> return type forces on every miss when the caller
discards the error (via .ok(), match, etc.). Because Error has
String-bearing variants, its drop-glue is a non-inlined function
call; eliminating it shaves several nanoseconds from the miss path —
the dominant shape for random/absent workloads.
Decode failures (only reachable on a corrupt or malicious database)
are also folded into None. Callers that must distinguish “not found”
from “found but undecodable” should use lookup_borrowed
instead.
§Performance
On the miss path this matches tree-only traversal — no Error
is constructed or dropped. On the hit path it is identical to
lookup_borrowed.
§Examples
use libmaxminddb_rs::{MmdbDecode, Reader};
#[derive(MmdbDecode)]
struct Record<'a> { category: &'a str }
let bytes = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/doc.mmdb"));
let reader = Reader::from_bytes(bytes)?;
let record: Option<Record<'_>> = reader.lookup_borrowed_opt("192.0.2.1".parse()?);
assert!(record.is_none());Sourcepub fn lookup_borrowed_map<'s, T, R>(
&'s self,
ip: IpAddr,
on_hit: impl FnOnce(T) -> R,
) -> Result<Option<R>>where
T: MmdbDecode<'s>,
pub fn lookup_borrowed_map<'s, T, R>(
&'s self,
ip: IpAddr,
on_hit: impl FnOnce(T) -> R,
) -> Result<Option<R>>where
T: MmdbDecode<'s>,
Decodes a borrowed record and passes it to on_hit, returning None
when no network matches the address.
A caller that only needs a small result can return it from the callback
without carrying a potentially large T through the miss path. Decode
and invalid-pointer errors are preserved as Error values.
§Examples
use libmaxminddb_rs::{MmdbDecode, Reader};
#[derive(MmdbDecode)]
struct Record<'a> { category: &'a str }
let bytes = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/doc.mmdb"));
let reader = Reader::from_bytes(bytes)?;
let category = reader.lookup_borrowed_map("203.0.113.7".parse()?, |r: Record<'_>| r.category)?;
assert_eq!(category, Some("compat"));Sourcepub fn lookup<T: DeserializeOwned>(&self, ip: IpAddr) -> Result<T>
pub fn lookup<T: DeserializeOwned>(&self, ip: IpAddr) -> Result<T>
Deserializes through serde into an owned type.
Returns Error::NotFound on a miss and a conversion error if the
stored value does not match the requested type. This path allocates.
§Examples
use libmaxminddb_rs::Reader;
let bytes = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/doc.mmdb"));
let reader = Reader::from_bytes(bytes)?;
let value: serde_json::Value = reader.lookup("203.0.113.7".parse()?)?;
assert_eq!(value["category"], "compat");Sourcepub fn lookup_many(&self, ips: &[IpAddr]) -> Vec<Result<ValueRef<'_>>> ⓘ
pub fn lookup_many(&self, ips: &[IpAddr]) -> Vec<Result<ValueRef<'_>>> ⓘ
Looks up many IPs and returns borrowed values in the same order as ips.
The output vector and decoded map/array containers allocate. For
large batches, work is split across threads with std::thread::scope.
Each result independently reports a miss or decode error.
§Examples
use libmaxminddb_rs::{Error, Reader};
let bytes = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/doc.mmdb"));
let reader = Reader::from_bytes(bytes)?;
let ips = ["203.0.113.7".parse()?, "192.0.2.1".parse()?];
let results = reader.lookup_many(&ips);
assert!(results[0].is_ok());
assert!(matches!(results[1], Err(Error::NotFound)));Sourcepub fn lookup_exists(&self, ip: IpAddr) -> bool
pub fn lookup_exists(&self, ip: IpAddr) -> bool
Checks if an IP address exists in the database without decoding or allocating.
It traverses the tree and validates the resulting data offset.
§Examples
use libmaxminddb_rs::Reader;
let bytes = include_bytes!(concat!(env!("CARGO_MANIFEST_DIR"), "/tests/fixtures/doc.mmdb"));
let reader = Reader::from_bytes(bytes)?;
assert!(reader.lookup_exists("203.0.113.7".parse()?));
assert!(!reader.lookup_exists("192.0.2.1".parse()?));