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}