maxminddb/geoip2.rs
1//! GeoIP2 and GeoLite2 database record structures
2//!
3//! This module provides strongly-typed Rust structures that correspond to the
4//! various GeoIP2 and GeoLite2 database record formats.
5//!
6//! # Record Types
7//!
8//! - [`City`] - Complete city-level geolocation data (most comprehensive)
9//! - [`Country`] - Country-level geolocation data
10//! - [`Enterprise`] - Enterprise database with additional confidence scores
11//! - [`Isp`] - Internet Service Provider information
12//! - [`AnonymousIp`] - Anonymous proxy and VPN detection
13//! - [`ConnectionType`] - Connection type classification
14//! - [`Domain`] - Domain information
15//! - [`Asn`] - Autonomous System Number data
16//! - [`DensityIncome`] - Population density and income data
17//!
18//! # Usage Examples
19//!
20//! ```rust
21//! use maxminddb::{Reader, geoip2};
22//! use std::net::IpAddr;
23//!
24//! # fn main() -> Result<(), maxminddb::MaxMindDbError> {
25//! let reader = Reader::open_readfile(
26//! "test-data/test-data/GeoIP2-City-Test.mmdb")?;
27//! let ip: IpAddr = "89.160.20.128".parse().unwrap();
28//!
29//! // City lookup - nested structs are always present (default to empty)
30//! let result = reader.lookup(ip)?;
31//! if let Some(city) = result.decode::<geoip2::City>()? {
32//! // Direct access to nested structs - no Option unwrapping needed
33//! if let Some(name) = city.city.names.english {
34//! println!("City: {}", name);
35//! }
36//! if let Some(code) = city.country.iso_code {
37//! println!("Country: {}", code);
38//! }
39//! // Subdivisions is a Vec, empty if not present
40//! for sub in &city.subdivisions {
41//! if let Some(code) = sub.iso_code {
42//! println!("Subdivision: {}", code);
43//! }
44//! }
45//! }
46//!
47//! // Country-only lookup (smaller/faster)
48//! let result = reader.lookup(ip)?;
49//! if let Some(country) = result.decode::<geoip2::Country>()? {
50//! if let Some(name) = country.country.names.english {
51//! println!("Country: {}", name);
52//! }
53//! }
54//! # Ok(())
55//! # }
56//! ```
57
58use serde::{Deserialize, Serialize};
59
60/// Localized names for geographic entities.
61///
62/// Contains name translations in the languages supported by MaxMind databases.
63/// Access names directly via fields like `names.english` or `names.german`.
64/// Each field is `Option<&str>` - `None` if not available in that language.
65///
66/// # Example
67///
68/// ```
69/// use maxminddb::{Reader, geoip2};
70/// use std::net::IpAddr;
71///
72/// let reader = Reader::open_readfile("test-data/test-data/GeoIP2-City-Test.mmdb").unwrap();
73/// let ip: IpAddr = "89.160.20.128".parse().unwrap();
74/// let result = reader.lookup(ip).unwrap();
75///
76/// if let Some(city) = result.decode::<geoip2::City>().unwrap() {
77/// // Access names directly - Option<&str>
78/// if let Some(name) = city.city.names.english {
79/// println!("City (en): {}", name);
80/// }
81/// if let Some(name) = city.city.names.german {
82/// println!("City (de): {}", name);
83/// }
84/// }
85/// ```
86#[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq, Eq)]
87pub struct Names<'a> {
88 /// German name (de)
89 #[serde(
90 borrow,
91 rename = "de",
92 default,
93 skip_serializing_if = "Option::is_none"
94 )]
95 pub german: Option<&'a str>,
96 /// English name (en)
97 #[serde(rename = "en", default, skip_serializing_if = "Option::is_none")]
98 pub english: Option<&'a str>,
99 /// Spanish name (es)
100 #[serde(rename = "es", default, skip_serializing_if = "Option::is_none")]
101 pub spanish: Option<&'a str>,
102 /// French name (fr)
103 #[serde(rename = "fr", default, skip_serializing_if = "Option::is_none")]
104 pub french: Option<&'a str>,
105 /// Japanese name (ja)
106 #[serde(rename = "ja", default, skip_serializing_if = "Option::is_none")]
107 pub japanese: Option<&'a str>,
108 /// Brazilian Portuguese name (pt-BR)
109 #[serde(rename = "pt-BR", default, skip_serializing_if = "Option::is_none")]
110 pub brazilian_portuguese: Option<&'a str>,
111 /// Russian name (ru)
112 #[serde(rename = "ru", default, skip_serializing_if = "Option::is_none")]
113 pub russian: Option<&'a str>,
114 /// Simplified Chinese name (zh-CN)
115 #[serde(rename = "zh-CN", default, skip_serializing_if = "Option::is_none")]
116 pub simplified_chinese: Option<&'a str>,
117}
118
119impl Names<'_> {
120 /// Returns true if all name fields are `None`.
121 #[must_use]
122 pub fn is_empty(&self) -> bool {
123 self.german.is_none()
124 && self.english.is_none()
125 && self.spanish.is_none()
126 && self.french.is_none()
127 && self.japanese.is_none()
128 && self.brazilian_portuguese.is_none()
129 && self.russian.is_none()
130 && self.simplified_chinese.is_none()
131 }
132}
133
134macro_rules! impl_is_empty_via_default {
135 ($ty:ty) => {
136 impl $ty {
137 /// Returns true if all fields are empty/None.
138 #[must_use]
139 pub fn is_empty(&self) -> bool {
140 *self == Self::default()
141 }
142 }
143 };
144}
145
146/// GeoIP2/GeoLite2 Country database record.
147///
148/// Contains country-level geolocation data for an IP address. This is the
149/// simplest geolocation record type, suitable when you only need country
150/// information.
151#[derive(Deserialize, Serialize, Clone, Debug, Default)]
152pub struct Country<'a> {
153 /// Continent data for the IP address.
154 #[serde(borrow, default, skip_serializing_if = "country::Continent::is_empty")]
155 pub continent: country::Continent<'a>,
156 /// Country where MaxMind believes the IP is located.
157 #[serde(default, skip_serializing_if = "country::Country::is_empty")]
158 pub country: country::Country<'a>,
159 /// Country where the ISP has registered the IP block.
160 /// May differ from `country` (e.g., for mobile networks or VPNs).
161 #[serde(default, skip_serializing_if = "country::Country::is_empty")]
162 pub registered_country: country::Country<'a>,
163 /// Country represented by users of this IP (e.g., military base or embassy).
164 #[serde(default, skip_serializing_if = "country::RepresentedCountry::is_empty")]
165 pub represented_country: country::RepresentedCountry<'a>,
166 /// Various traits associated with the IP address.
167 #[serde(default, skip_serializing_if = "country::Traits::is_empty")]
168 pub traits: country::Traits,
169}
170
171/// GeoIP2/GeoLite2 City database record.
172///
173/// Contains city-level geolocation data including location coordinates,
174/// postal code, subdivisions (states/provinces), and country information.
175/// This is the most comprehensive free geolocation record type.
176#[derive(Deserialize, Serialize, Clone, Debug, Default)]
177pub struct City<'a> {
178 /// City data for the IP address.
179 #[serde(borrow, default, skip_serializing_if = "city::City::is_empty")]
180 pub city: city::City<'a>,
181 /// Continent data for the IP address.
182 #[serde(default, skip_serializing_if = "city::Continent::is_empty")]
183 pub continent: city::Continent<'a>,
184 /// Country where MaxMind believes the IP is located.
185 #[serde(default, skip_serializing_if = "city::Country::is_empty")]
186 pub country: city::Country<'a>,
187 /// Location data including coordinates and time zone.
188 #[serde(default, skip_serializing_if = "city::Location::is_empty")]
189 pub location: city::Location<'a>,
190 /// Postal code data for the IP address.
191 #[serde(default, skip_serializing_if = "city::Postal::is_empty")]
192 pub postal: city::Postal<'a>,
193 /// Country where the ISP has registered the IP block.
194 #[serde(default, skip_serializing_if = "city::Country::is_empty")]
195 pub registered_country: city::Country<'a>,
196 /// Country represented by users of this IP (e.g., military base or embassy).
197 #[serde(default, skip_serializing_if = "city::RepresentedCountry::is_empty")]
198 pub represented_country: city::RepresentedCountry<'a>,
199 /// Subdivisions (states, provinces, etc.) ordered from largest to smallest.
200 /// For example, Oxford, UK would have England first, then Oxfordshire.
201 #[serde(default, skip_serializing_if = "Vec::is_empty")]
202 pub subdivisions: Vec<city::Subdivision<'a>>,
203 /// Various traits associated with the IP address.
204 #[serde(default, skip_serializing_if = "city::Traits::is_empty")]
205 pub traits: city::Traits,
206}
207
208/// GeoIP2 Enterprise database record.
209///
210/// Contains all City data plus additional confidence scores and traits.
211/// Enterprise records include confidence values (0-100) indicating MaxMind's
212/// certainty about the accuracy of each field.
213#[derive(Deserialize, Serialize, Clone, Debug, Default)]
214pub struct Enterprise<'a> {
215 /// City data with confidence score.
216 #[serde(borrow, default, skip_serializing_if = "enterprise::City::is_empty")]
217 pub city: enterprise::City<'a>,
218 /// Continent data for the IP address.
219 #[serde(default, skip_serializing_if = "enterprise::Continent::is_empty")]
220 pub continent: enterprise::Continent<'a>,
221 /// Country data with confidence score.
222 #[serde(default, skip_serializing_if = "enterprise::Country::is_empty")]
223 pub country: enterprise::Country<'a>,
224 /// Location data including coordinates and time zone.
225 #[serde(default, skip_serializing_if = "enterprise::Location::is_empty")]
226 pub location: enterprise::Location<'a>,
227 /// Postal code data with confidence score.
228 #[serde(default, skip_serializing_if = "enterprise::Postal::is_empty")]
229 pub postal: enterprise::Postal<'a>,
230 /// Country where the ISP has registered the IP block.
231 #[serde(default, skip_serializing_if = "enterprise::Country::is_empty")]
232 pub registered_country: enterprise::Country<'a>,
233 /// Country represented by users of this IP (e.g., military base or embassy).
234 #[serde(
235 default,
236 skip_serializing_if = "enterprise::RepresentedCountry::is_empty"
237 )]
238 pub represented_country: enterprise::RepresentedCountry<'a>,
239 /// Subdivisions with confidence scores, ordered from largest to smallest.
240 #[serde(default, skip_serializing_if = "Vec::is_empty")]
241 pub subdivisions: Vec<enterprise::Subdivision<'a>>,
242 /// Extended traits including ISP, organization, and connection information.
243 #[serde(default, skip_serializing_if = "enterprise::Traits::is_empty")]
244 pub traits: enterprise::Traits<'a>,
245}
246
247/// GeoIP2 ISP database record.
248///
249/// Contains Internet Service Provider and organization information for an IP.
250#[derive(Deserialize, Serialize, Clone, Debug)]
251pub struct Isp<'a> {
252 /// The autonomous system number (ASN) for the IP address.
253 #[serde(skip_serializing_if = "Option::is_none")]
254 pub autonomous_system_number: Option<u32>,
255 /// The organization associated with the registered ASN.
256 #[serde(skip_serializing_if = "Option::is_none")]
257 pub autonomous_system_organization: Option<&'a str>,
258 /// The name of the ISP associated with the IP address.
259 #[serde(skip_serializing_if = "Option::is_none")]
260 pub isp: Option<&'a str>,
261 /// The mobile country code (MCC) associated with the IP.
262 /// See <https://en.wikipedia.org/wiki/Mobile_country_code>.
263 #[serde(skip_serializing_if = "Option::is_none")]
264 pub mobile_country_code: Option<&'a str>,
265 /// The mobile network code (MNC) associated with the IP.
266 /// See <https://en.wikipedia.org/wiki/Mobile_network_code>.
267 #[serde(skip_serializing_if = "Option::is_none")]
268 pub mobile_network_code: Option<&'a str>,
269 /// The name of the organization associated with the IP address.
270 #[serde(skip_serializing_if = "Option::is_none")]
271 pub organization: Option<&'a str>,
272}
273
274/// GeoIP2 Connection-Type database record.
275///
276/// Contains the connection type for an IP address.
277#[derive(Deserialize, Serialize, Clone, Debug)]
278pub struct ConnectionType<'a> {
279 /// The connection type. Possible values include "Dialup", "Cable/DSL",
280 /// "Corporate", "Cellular", and "Satellite". Additional values may be
281 /// added in the future.
282 #[serde(skip_serializing_if = "Option::is_none")]
283 pub connection_type: Option<&'a str>,
284}
285
286/// GeoIP2 Anonymous IP database record.
287///
288/// Contains information about whether an IP address is associated with
289/// anonymous or proxy services.
290#[derive(Deserialize, Serialize, Clone, Debug)]
291pub struct AnonymousIp {
292 /// True if the IP belongs to any sort of anonymous network.
293 #[serde(skip_serializing_if = "Option::is_none")]
294 pub is_anonymous: Option<bool>,
295 /// True if the IP is registered to an anonymous VPN provider.
296 /// Note: If a VPN provider does not register subnets under names associated
297 /// with them, we will likely only flag their IP ranges using `is_hosting_provider`.
298 #[serde(skip_serializing_if = "Option::is_none")]
299 pub is_anonymous_vpn: Option<bool>,
300 /// True if the IP belongs to a hosting or VPN provider.
301 #[serde(skip_serializing_if = "Option::is_none")]
302 pub is_hosting_provider: Option<bool>,
303 /// True if the IP belongs to a public proxy.
304 #[serde(skip_serializing_if = "Option::is_none")]
305 pub is_public_proxy: Option<bool>,
306 /// True if the IP is on a suspected anonymizing network and belongs to
307 /// a residential ISP.
308 #[serde(skip_serializing_if = "Option::is_none")]
309 pub is_residential_proxy: Option<bool>,
310 /// True if the IP is a Tor exit node.
311 #[serde(skip_serializing_if = "Option::is_none")]
312 pub is_tor_exit_node: Option<bool>,
313}
314
315/// GeoIP2 DensityIncome database record.
316///
317/// Contains population density and income data for an IP address location.
318#[derive(Deserialize, Serialize, Clone, Debug)]
319pub struct DensityIncome {
320 /// The average income in US dollars associated with the IP address.
321 #[serde(skip_serializing_if = "Option::is_none")]
322 pub average_income: Option<u32>,
323 /// The estimated number of people per square kilometer.
324 #[serde(skip_serializing_if = "Option::is_none")]
325 pub population_density: Option<u32>,
326}
327
328/// GeoIP2 Domain database record.
329///
330/// Contains the second-level domain associated with an IP address.
331#[derive(Deserialize, Serialize, Clone, Debug)]
332pub struct Domain<'a> {
333 /// The second-level domain associated with the IP address
334 /// (e.g., "example.com").
335 #[serde(skip_serializing_if = "Option::is_none")]
336 pub domain: Option<&'a str>,
337}
338
339/// GeoLite2 ASN database record.
340///
341/// Contains Autonomous System Number (ASN) data for an IP address.
342#[derive(Deserialize, Serialize, Clone, Debug)]
343pub struct Asn<'a> {
344 /// The autonomous system number for the IP address.
345 #[serde(skip_serializing_if = "Option::is_none")]
346 pub autonomous_system_number: Option<u32>,
347 /// The organization associated with the registered ASN.
348 #[serde(skip_serializing_if = "Option::is_none")]
349 pub autonomous_system_organization: Option<&'a str>,
350}
351
352/// Country/City database model structs.
353///
354/// These structs are used by both [`super::Country`] and [`super::City`] records.
355pub mod country {
356 use super::Names;
357 use serde::{Deserialize, Serialize};
358
359 /// Continent data for an IP address.
360 #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
361 pub struct Continent<'a> {
362 /// Two-character continent code (e.g., "NA" for North America, "EU" for Europe).
363 #[serde(default, skip_serializing_if = "Option::is_none")]
364 pub code: Option<&'a str>,
365 /// GeoNames ID for the continent.
366 #[serde(default, skip_serializing_if = "Option::is_none")]
367 pub geoname_id: Option<u32>,
368 /// Localized continent names.
369 #[serde(borrow, default, skip_serializing_if = "Names::is_empty")]
370 pub names: Names<'a>,
371 }
372
373 impl_is_empty_via_default!(Continent<'_>);
374
375 /// Country data for an IP address.
376 #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
377 pub struct Country<'a> {
378 /// GeoNames ID for the country.
379 #[serde(default, skip_serializing_if = "Option::is_none")]
380 pub geoname_id: Option<u32>,
381 /// True if the country is a member state of the European Union.
382 #[serde(default, skip_serializing_if = "Option::is_none")]
383 pub is_in_european_union: Option<bool>,
384 /// Two-character ISO 3166-1 alpha-2 country code.
385 /// See <https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2>.
386 #[serde(default, skip_serializing_if = "Option::is_none")]
387 pub iso_code: Option<&'a str>,
388 /// Localized country names.
389 #[serde(borrow, default, skip_serializing_if = "Names::is_empty")]
390 pub names: Names<'a>,
391 }
392
393 impl_is_empty_via_default!(Country<'_>);
394
395 /// Represented country data.
396 ///
397 /// The represented country is the country represented by something like a
398 /// military base or embassy.
399 #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
400 pub struct RepresentedCountry<'a> {
401 /// GeoNames ID for the represented country.
402 #[serde(default, skip_serializing_if = "Option::is_none")]
403 pub geoname_id: Option<u32>,
404 /// True if the represented country is a member state of the European Union.
405 #[serde(default, skip_serializing_if = "Option::is_none")]
406 pub is_in_european_union: Option<bool>,
407 /// Two-character ISO 3166-1 alpha-2 country code.
408 /// See <https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2>.
409 #[serde(default, skip_serializing_if = "Option::is_none")]
410 pub iso_code: Option<&'a str>,
411 /// Localized country names.
412 #[serde(borrow, default, skip_serializing_if = "Names::is_empty")]
413 pub names: Names<'a>,
414 /// Type of entity representing the country (e.g., "military").
415 #[serde(rename = "type", default, skip_serializing_if = "Option::is_none")]
416 pub representation_type: Option<&'a str>,
417 }
418
419 impl_is_empty_via_default!(RepresentedCountry<'_>);
420
421 /// Traits data for Country/City records.
422 #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
423 pub struct Traits {
424 /// True if the IP belongs to an anycast network.
425 /// See <https://en.wikipedia.org/wiki/Anycast>.
426 #[serde(default, skip_serializing_if = "Option::is_none")]
427 pub is_anycast: Option<bool>,
428 }
429
430 impl_is_empty_via_default!(Traits);
431}
432
433/// City database model structs.
434///
435/// City-specific structs. Country-level structs are re-exported from [`super::country`].
436pub mod city {
437 use super::Names;
438 use serde::{Deserialize, Serialize};
439
440 pub use super::country::{Continent, Country, RepresentedCountry, Traits};
441
442 /// City data for an IP address.
443 #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
444 pub struct City<'a> {
445 /// GeoNames ID for the city.
446 #[serde(default, skip_serializing_if = "Option::is_none")]
447 pub geoname_id: Option<u32>,
448 /// Localized city names.
449 #[serde(borrow, default, skip_serializing_if = "Names::is_empty")]
450 pub names: Names<'a>,
451 }
452
453 impl_is_empty_via_default!(City<'_>);
454
455 /// Location data for an IP address.
456 #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
457 pub struct Location<'a> {
458 /// Approximate accuracy radius in kilometers around the coordinates.
459 /// This is the radius where we have a 67% confidence that the device
460 /// using the IP address resides within.
461 #[serde(default, skip_serializing_if = "Option::is_none")]
462 pub accuracy_radius: Option<u16>,
463 /// Approximate latitude of the location. This value is not precise and
464 /// should not be used to identify a particular address or household.
465 #[serde(default, skip_serializing_if = "Option::is_none")]
466 pub latitude: Option<f64>,
467 /// Approximate longitude of the location. This value is not precise and
468 /// should not be used to identify a particular address or household.
469 #[serde(default, skip_serializing_if = "Option::is_none")]
470 pub longitude: Option<f64>,
471 /// Metro code for the location, used for targeting advertisements.
472 ///
473 /// **Deprecated:** Metro codes are no longer maintained and should not be used.
474 #[serde(default, skip_serializing_if = "Option::is_none")]
475 pub metro_code: Option<u16>,
476 /// Time zone associated with the location, as specified by the
477 /// IANA Time Zone Database (e.g., "America/New_York").
478 #[serde(default, skip_serializing_if = "Option::is_none")]
479 pub time_zone: Option<&'a str>,
480 }
481
482 impl_is_empty_via_default!(Location<'_>);
483
484 /// Postal data for an IP address.
485 #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
486 pub struct Postal<'a> {
487 /// Postal code for the location. Not available for all countries.
488 /// In some countries, this will only contain part of the postal code.
489 #[serde(default, skip_serializing_if = "Option::is_none")]
490 pub code: Option<&'a str>,
491 }
492
493 impl_is_empty_via_default!(Postal<'_>);
494
495 /// Subdivision (state, province, etc.) data for an IP address.
496 #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
497 pub struct Subdivision<'a> {
498 /// GeoNames ID for the subdivision.
499 #[serde(default, skip_serializing_if = "Option::is_none")]
500 pub geoname_id: Option<u32>,
501 /// ISO 3166-2 subdivision code (up to 3 characters).
502 /// See <https://en.wikipedia.org/wiki/ISO_3166-2>.
503 #[serde(default, skip_serializing_if = "Option::is_none")]
504 pub iso_code: Option<&'a str>,
505 /// Localized subdivision names.
506 #[serde(borrow, default, skip_serializing_if = "Names::is_empty")]
507 pub names: Names<'a>,
508 }
509
510 impl_is_empty_via_default!(Subdivision<'_>);
511}
512
513/// Enterprise database model structs.
514///
515/// Enterprise-specific structs with confidence scores. Some structs are
516/// re-exported from [`super::country`].
517pub mod enterprise {
518 use super::Names;
519 use serde::{Deserialize, Serialize};
520
521 pub use super::country::{Continent, RepresentedCountry};
522
523 /// City data with confidence score.
524 #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
525 pub struct City<'a> {
526 /// Confidence score (0-100) indicating MaxMind's certainty that the
527 /// city is correct.
528 #[serde(default, skip_serializing_if = "Option::is_none")]
529 pub confidence: Option<u8>,
530 /// GeoNames ID for the city.
531 #[serde(default, skip_serializing_if = "Option::is_none")]
532 pub geoname_id: Option<u32>,
533 /// Localized city names.
534 #[serde(borrow, default, skip_serializing_if = "Names::is_empty")]
535 pub names: Names<'a>,
536 }
537
538 impl_is_empty_via_default!(City<'_>);
539
540 /// Country data with confidence score.
541 #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
542 pub struct Country<'a> {
543 /// Confidence score (0-100) indicating MaxMind's certainty that the
544 /// country is correct.
545 #[serde(default, skip_serializing_if = "Option::is_none")]
546 pub confidence: Option<u8>,
547 /// GeoNames ID for the country.
548 #[serde(default, skip_serializing_if = "Option::is_none")]
549 pub geoname_id: Option<u32>,
550 /// True if the country is a member state of the European Union.
551 #[serde(default, skip_serializing_if = "Option::is_none")]
552 pub is_in_european_union: Option<bool>,
553 /// Two-character ISO 3166-1 alpha-2 country code.
554 /// See <https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2>.
555 #[serde(default, skip_serializing_if = "Option::is_none")]
556 pub iso_code: Option<&'a str>,
557 /// Localized country names.
558 #[serde(borrow, default, skip_serializing_if = "Names::is_empty")]
559 pub names: Names<'a>,
560 }
561
562 impl_is_empty_via_default!(Country<'_>);
563
564 /// Location data for an IP address.
565 #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
566 pub struct Location<'a> {
567 /// Approximate accuracy radius in kilometers around the coordinates.
568 /// This is the radius where we have a 67% confidence that the device
569 /// using the IP address resides within.
570 #[serde(default, skip_serializing_if = "Option::is_none")]
571 pub accuracy_radius: Option<u16>,
572 /// Approximate latitude of the location. This value is not precise and
573 /// should not be used to identify a particular address or household.
574 #[serde(default, skip_serializing_if = "Option::is_none")]
575 pub latitude: Option<f64>,
576 /// Approximate longitude of the location. This value is not precise and
577 /// should not be used to identify a particular address or household.
578 #[serde(default, skip_serializing_if = "Option::is_none")]
579 pub longitude: Option<f64>,
580 /// Metro code for the location, used for targeting advertisements.
581 ///
582 /// **Deprecated:** Metro codes are no longer maintained and should not be used.
583 #[serde(default, skip_serializing_if = "Option::is_none")]
584 pub metro_code: Option<u16>,
585 /// Time zone associated with the location, as specified by the
586 /// IANA Time Zone Database (e.g., "America/New_York").
587 #[serde(default, skip_serializing_if = "Option::is_none")]
588 pub time_zone: Option<&'a str>,
589 }
590
591 impl_is_empty_via_default!(Location<'_>);
592
593 /// Postal data with confidence score.
594 #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
595 pub struct Postal<'a> {
596 /// Postal code for the location. Not available for all countries.
597 /// In some countries, this will only contain part of the postal code.
598 #[serde(default, skip_serializing_if = "Option::is_none")]
599 pub code: Option<&'a str>,
600 /// Confidence score (0-100) indicating MaxMind's certainty that the
601 /// postal code is correct.
602 #[serde(default, skip_serializing_if = "Option::is_none")]
603 pub confidence: Option<u8>,
604 }
605
606 impl_is_empty_via_default!(Postal<'_>);
607
608 /// Subdivision data with confidence score.
609 #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
610 pub struct Subdivision<'a> {
611 /// Confidence score (0-100) indicating MaxMind's certainty that the
612 /// subdivision is correct.
613 #[serde(default, skip_serializing_if = "Option::is_none")]
614 pub confidence: Option<u8>,
615 /// GeoNames ID for the subdivision.
616 #[serde(default, skip_serializing_if = "Option::is_none")]
617 pub geoname_id: Option<u32>,
618 /// ISO 3166-2 subdivision code (up to 3 characters).
619 /// See <https://en.wikipedia.org/wiki/ISO_3166-2>.
620 #[serde(default, skip_serializing_if = "Option::is_none")]
621 pub iso_code: Option<&'a str>,
622 /// Localized subdivision names.
623 #[serde(borrow, default, skip_serializing_if = "Names::is_empty")]
624 pub names: Names<'a>,
625 }
626
627 impl_is_empty_via_default!(Subdivision<'_>);
628
629 /// Extended traits data for Enterprise records.
630 ///
631 /// Contains ISP, organization, connection type, and anonymity information.
632 #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
633 pub struct Traits<'a> {
634 /// The autonomous system number (ASN) for the IP address.
635 #[serde(default, skip_serializing_if = "Option::is_none")]
636 pub autonomous_system_number: Option<u32>,
637 /// The organization associated with the registered ASN.
638 #[serde(default, skip_serializing_if = "Option::is_none")]
639 pub autonomous_system_organization: Option<&'a str>,
640 /// The connection type. Possible values include "Dialup", "Cable/DSL",
641 /// "Corporate", "Cellular", and "Satellite".
642 #[serde(default, skip_serializing_if = "Option::is_none")]
643 pub connection_type: Option<&'a str>,
644 /// The second-level domain associated with the IP address
645 /// (e.g., "example.com").
646 #[serde(default, skip_serializing_if = "Option::is_none")]
647 pub domain: Option<&'a str>,
648 /// True if the IP belongs to any sort of anonymous network.
649 #[serde(default, skip_serializing_if = "Option::is_none")]
650 pub is_anonymous: Option<bool>,
651 /// True if the IP is registered to an anonymous VPN provider.
652 #[serde(default, skip_serializing_if = "Option::is_none")]
653 pub is_anonymous_vpn: Option<bool>,
654 /// True if the IP belongs to an anycast network.
655 /// See <https://en.wikipedia.org/wiki/Anycast>.
656 #[serde(default, skip_serializing_if = "Option::is_none")]
657 pub is_anycast: Option<bool>,
658 /// True if the IP belongs to a hosting or VPN provider.
659 #[serde(default, skip_serializing_if = "Option::is_none")]
660 pub is_hosting_provider: Option<bool>,
661 /// The name of the ISP associated with the IP address.
662 #[serde(default, skip_serializing_if = "Option::is_none")]
663 pub isp: Option<&'a str>,
664 /// True if the IP belongs to a public proxy.
665 #[serde(default, skip_serializing_if = "Option::is_none")]
666 pub is_public_proxy: Option<bool>,
667 /// True if the IP is on a suspected anonymizing network and belongs to
668 /// a residential ISP.
669 #[serde(default, skip_serializing_if = "Option::is_none")]
670 pub is_residential_proxy: Option<bool>,
671 /// True if the IP is a Tor exit node.
672 #[serde(default, skip_serializing_if = "Option::is_none")]
673 pub is_tor_exit_node: Option<bool>,
674 /// The mobile country code (MCC) associated with the IP.
675 /// See <https://en.wikipedia.org/wiki/Mobile_country_code>.
676 #[serde(default, skip_serializing_if = "Option::is_none")]
677 pub mobile_country_code: Option<&'a str>,
678 /// The mobile network code (MNC) associated with the IP.
679 /// See <https://en.wikipedia.org/wiki/Mobile_network_code>.
680 #[serde(default, skip_serializing_if = "Option::is_none")]
681 pub mobile_network_code: Option<&'a str>,
682 /// The name of the organization associated with the IP address.
683 #[serde(default, skip_serializing_if = "Option::is_none")]
684 pub organization: Option<&'a str>,
685 /// The user type associated with the IP address. Possible values include
686 /// "business", "cafe", "cellular", "college", "government", "hosting",
687 /// "library", "military", "residential", "router", "school",
688 /// "search_engine_spider", and "traveler".
689 #[serde(default, skip_serializing_if = "Option::is_none")]
690 pub user_type: Option<&'a str>,
691 }
692
693 impl_is_empty_via_default!(Traits<'_>);
694}