Skip to main content

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 [`crate::geoip2::Country`] and
355/// [`crate::geoip2::City`] records.
356pub mod country {
357    use super::Names;
358    use serde::{Deserialize, Serialize};
359
360    /// Continent data for an IP address.
361    #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
362    pub struct Continent<'a> {
363        /// Two-character continent code (e.g., "NA" for North America, "EU" for Europe).
364        #[serde(default, skip_serializing_if = "Option::is_none")]
365        pub code: Option<&'a str>,
366        /// GeoNames ID for the continent.
367        #[serde(default, skip_serializing_if = "Option::is_none")]
368        pub geoname_id: Option<u32>,
369        /// Localized continent names.
370        #[serde(borrow, default, skip_serializing_if = "Names::is_empty")]
371        pub names: Names<'a>,
372    }
373
374    impl_is_empty_via_default!(Continent<'_>);
375
376    /// Country data for an IP address.
377    #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
378    pub struct Country<'a> {
379        /// GeoNames ID for the country.
380        #[serde(default, skip_serializing_if = "Option::is_none")]
381        pub geoname_id: Option<u32>,
382        /// True if the country is a member state of the European Union.
383        #[serde(default, skip_serializing_if = "Option::is_none")]
384        pub is_in_european_union: Option<bool>,
385        /// Two-character ISO 3166-1 alpha-2 country code.
386        /// See <https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2>.
387        #[serde(default, skip_serializing_if = "Option::is_none")]
388        pub iso_code: Option<&'a str>,
389        /// Localized country names.
390        #[serde(borrow, default, skip_serializing_if = "Names::is_empty")]
391        pub names: Names<'a>,
392    }
393
394    impl_is_empty_via_default!(Country<'_>);
395
396    /// Represented country data.
397    ///
398    /// The represented country is the country represented by something like a
399    /// military base or embassy.
400    #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
401    pub struct RepresentedCountry<'a> {
402        /// GeoNames ID for the represented country.
403        #[serde(default, skip_serializing_if = "Option::is_none")]
404        pub geoname_id: Option<u32>,
405        /// True if the represented country is a member state of the European Union.
406        #[serde(default, skip_serializing_if = "Option::is_none")]
407        pub is_in_european_union: Option<bool>,
408        /// Two-character ISO 3166-1 alpha-2 country code.
409        /// See <https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2>.
410        #[serde(default, skip_serializing_if = "Option::is_none")]
411        pub iso_code: Option<&'a str>,
412        /// Localized country names.
413        #[serde(borrow, default, skip_serializing_if = "Names::is_empty")]
414        pub names: Names<'a>,
415        /// Type of entity representing the country (e.g., "military").
416        #[serde(rename = "type", default, skip_serializing_if = "Option::is_none")]
417        pub representation_type: Option<&'a str>,
418    }
419
420    impl_is_empty_via_default!(RepresentedCountry<'_>);
421
422    /// Traits data for Country/City records.
423    #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
424    pub struct Traits {
425        /// True if the IP belongs to an anycast network.
426        /// See <https://en.wikipedia.org/wiki/Anycast>.
427        #[serde(default, skip_serializing_if = "Option::is_none")]
428        pub is_anycast: Option<bool>,
429    }
430
431    impl_is_empty_via_default!(Traits);
432}
433
434/// City database model structs.
435///
436/// City-specific structs. Country-level structs are re-exported from
437/// [`crate::geoip2::country`].
438pub mod city {
439    use super::Names;
440    use serde::{Deserialize, Serialize};
441
442    pub use super::country::{Continent, Country, RepresentedCountry, Traits};
443
444    /// City data for an IP address.
445    #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
446    pub struct City<'a> {
447        /// GeoNames ID for the city.
448        #[serde(default, skip_serializing_if = "Option::is_none")]
449        pub geoname_id: Option<u32>,
450        /// Localized city names.
451        #[serde(borrow, default, skip_serializing_if = "Names::is_empty")]
452        pub names: Names<'a>,
453    }
454
455    impl_is_empty_via_default!(City<'_>);
456
457    /// Location data for an IP address.
458    #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
459    pub struct Location<'a> {
460        /// Approximate accuracy radius in kilometers around the coordinates.
461        /// This is the radius where we have a 67% confidence that the device
462        /// using the IP address resides within.
463        #[serde(default, skip_serializing_if = "Option::is_none")]
464        pub accuracy_radius: Option<u16>,
465        /// Approximate latitude of the location. This value is not precise and
466        /// should not be used to identify a particular address or household.
467        #[serde(default, skip_serializing_if = "Option::is_none")]
468        pub latitude: Option<f64>,
469        /// Approximate longitude of the location. This value is not precise and
470        /// should not be used to identify a particular address or household.
471        #[serde(default, skip_serializing_if = "Option::is_none")]
472        pub longitude: Option<f64>,
473        /// Metro code for the location, used for targeting advertisements.
474        ///
475        /// **Deprecated:** Metro codes are no longer maintained and should not be used.
476        #[serde(default, skip_serializing_if = "Option::is_none")]
477        pub metro_code: Option<u16>,
478        /// Time zone associated with the location, as specified by the
479        /// IANA Time Zone Database (e.g., "America/New_York").
480        #[serde(default, skip_serializing_if = "Option::is_none")]
481        pub time_zone: Option<&'a str>,
482    }
483
484    impl_is_empty_via_default!(Location<'_>);
485
486    /// Postal data for an IP address.
487    #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
488    pub struct Postal<'a> {
489        /// Postal code for the location. Not available for all countries.
490        /// In some countries, this will only contain part of the postal code.
491        #[serde(default, skip_serializing_if = "Option::is_none")]
492        pub code: Option<&'a str>,
493    }
494
495    impl_is_empty_via_default!(Postal<'_>);
496
497    /// Subdivision (state, province, etc.) data for an IP address.
498    #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
499    pub struct Subdivision<'a> {
500        /// GeoNames ID for the subdivision.
501        #[serde(default, skip_serializing_if = "Option::is_none")]
502        pub geoname_id: Option<u32>,
503        /// ISO 3166-2 subdivision code (up to 3 characters).
504        /// See <https://en.wikipedia.org/wiki/ISO_3166-2>.
505        #[serde(default, skip_serializing_if = "Option::is_none")]
506        pub iso_code: Option<&'a str>,
507        /// Localized subdivision names.
508        #[serde(borrow, default, skip_serializing_if = "Names::is_empty")]
509        pub names: Names<'a>,
510    }
511
512    impl_is_empty_via_default!(Subdivision<'_>);
513}
514
515/// Enterprise database model structs.
516///
517/// Enterprise-specific structs with confidence scores. Some structs are
518/// re-exported from [`crate::geoip2::country`].
519pub mod enterprise {
520    use super::Names;
521    use serde::{Deserialize, Serialize};
522
523    pub use super::country::{Continent, RepresentedCountry};
524
525    /// City data with confidence score.
526    #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
527    pub struct City<'a> {
528        /// Confidence score (0-100) indicating MaxMind's certainty that the
529        /// city is correct.
530        #[serde(default, skip_serializing_if = "Option::is_none")]
531        pub confidence: Option<u8>,
532        /// GeoNames ID for the city.
533        #[serde(default, skip_serializing_if = "Option::is_none")]
534        pub geoname_id: Option<u32>,
535        /// Localized city names.
536        #[serde(borrow, default, skip_serializing_if = "Names::is_empty")]
537        pub names: Names<'a>,
538    }
539
540    impl_is_empty_via_default!(City<'_>);
541
542    /// Country data with confidence score.
543    #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
544    pub struct Country<'a> {
545        /// Confidence score (0-100) indicating MaxMind's certainty that the
546        /// country is correct.
547        #[serde(default, skip_serializing_if = "Option::is_none")]
548        pub confidence: Option<u8>,
549        /// GeoNames ID for the country.
550        #[serde(default, skip_serializing_if = "Option::is_none")]
551        pub geoname_id: Option<u32>,
552        /// True if the country is a member state of the European Union.
553        #[serde(default, skip_serializing_if = "Option::is_none")]
554        pub is_in_european_union: Option<bool>,
555        /// Two-character ISO 3166-1 alpha-2 country code.
556        /// See <https://en.wikipedia.org/wiki/ISO_3166-1_alpha-2>.
557        #[serde(default, skip_serializing_if = "Option::is_none")]
558        pub iso_code: Option<&'a str>,
559        /// Localized country names.
560        #[serde(borrow, default, skip_serializing_if = "Names::is_empty")]
561        pub names: Names<'a>,
562    }
563
564    impl_is_empty_via_default!(Country<'_>);
565
566    /// Location data for an IP address.
567    #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
568    pub struct Location<'a> {
569        /// Approximate accuracy radius in kilometers around the coordinates.
570        /// This is the radius where we have a 67% confidence that the device
571        /// using the IP address resides within.
572        #[serde(default, skip_serializing_if = "Option::is_none")]
573        pub accuracy_radius: Option<u16>,
574        /// Approximate latitude of the location. This value is not precise and
575        /// should not be used to identify a particular address or household.
576        #[serde(default, skip_serializing_if = "Option::is_none")]
577        pub latitude: Option<f64>,
578        /// Approximate longitude of the location. This value is not precise and
579        /// should not be used to identify a particular address or household.
580        #[serde(default, skip_serializing_if = "Option::is_none")]
581        pub longitude: Option<f64>,
582        /// Metro code for the location, used for targeting advertisements.
583        ///
584        /// **Deprecated:** Metro codes are no longer maintained and should not be used.
585        #[serde(default, skip_serializing_if = "Option::is_none")]
586        pub metro_code: Option<u16>,
587        /// Time zone associated with the location, as specified by the
588        /// IANA Time Zone Database (e.g., "America/New_York").
589        #[serde(default, skip_serializing_if = "Option::is_none")]
590        pub time_zone: Option<&'a str>,
591    }
592
593    impl_is_empty_via_default!(Location<'_>);
594
595    /// Postal data with confidence score.
596    #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
597    pub struct Postal<'a> {
598        /// Postal code for the location. Not available for all countries.
599        /// In some countries, this will only contain part of the postal code.
600        #[serde(default, skip_serializing_if = "Option::is_none")]
601        pub code: Option<&'a str>,
602        /// Confidence score (0-100) indicating MaxMind's certainty that the
603        /// postal code is correct.
604        #[serde(default, skip_serializing_if = "Option::is_none")]
605        pub confidence: Option<u8>,
606    }
607
608    impl_is_empty_via_default!(Postal<'_>);
609
610    /// Subdivision data with confidence score.
611    #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
612    pub struct Subdivision<'a> {
613        /// Confidence score (0-100) indicating MaxMind's certainty that the
614        /// subdivision is correct.
615        #[serde(default, skip_serializing_if = "Option::is_none")]
616        pub confidence: Option<u8>,
617        /// GeoNames ID for the subdivision.
618        #[serde(default, skip_serializing_if = "Option::is_none")]
619        pub geoname_id: Option<u32>,
620        /// ISO 3166-2 subdivision code (up to 3 characters).
621        /// See <https://en.wikipedia.org/wiki/ISO_3166-2>.
622        #[serde(default, skip_serializing_if = "Option::is_none")]
623        pub iso_code: Option<&'a str>,
624        /// Localized subdivision names.
625        #[serde(borrow, default, skip_serializing_if = "Names::is_empty")]
626        pub names: Names<'a>,
627    }
628
629    impl_is_empty_via_default!(Subdivision<'_>);
630
631    /// Extended traits data for Enterprise records.
632    ///
633    /// Contains ISP, organization, connection type, and anonymity information.
634    #[derive(Deserialize, Serialize, Clone, Debug, Default, PartialEq)]
635    pub struct Traits<'a> {
636        /// The autonomous system number (ASN) for the IP address.
637        #[serde(default, skip_serializing_if = "Option::is_none")]
638        pub autonomous_system_number: Option<u32>,
639        /// The organization associated with the registered ASN.
640        #[serde(default, skip_serializing_if = "Option::is_none")]
641        pub autonomous_system_organization: Option<&'a str>,
642        /// The connection type. Possible values include "Dialup", "Cable/DSL",
643        /// "Corporate", "Cellular", and "Satellite".
644        #[serde(default, skip_serializing_if = "Option::is_none")]
645        pub connection_type: Option<&'a str>,
646        /// The second-level domain associated with the IP address
647        /// (e.g., "example.com").
648        #[serde(default, skip_serializing_if = "Option::is_none")]
649        pub domain: Option<&'a str>,
650        /// True if the IP belongs to any sort of anonymous network.
651        #[serde(default, skip_serializing_if = "Option::is_none")]
652        pub is_anonymous: Option<bool>,
653        /// True if the IP is registered to an anonymous VPN provider.
654        #[serde(default, skip_serializing_if = "Option::is_none")]
655        pub is_anonymous_vpn: Option<bool>,
656        /// True if the IP belongs to an anycast network.
657        /// See <https://en.wikipedia.org/wiki/Anycast>.
658        #[serde(default, skip_serializing_if = "Option::is_none")]
659        pub is_anycast: Option<bool>,
660        /// True if the IP belongs to a hosting or VPN provider.
661        #[serde(default, skip_serializing_if = "Option::is_none")]
662        pub is_hosting_provider: Option<bool>,
663        /// The name of the ISP associated with the IP address.
664        #[serde(default, skip_serializing_if = "Option::is_none")]
665        pub isp: Option<&'a str>,
666        /// True if the IP belongs to a public proxy.
667        #[serde(default, skip_serializing_if = "Option::is_none")]
668        pub is_public_proxy: Option<bool>,
669        /// True if the IP is on a suspected anonymizing network and belongs to
670        /// a residential ISP.
671        #[serde(default, skip_serializing_if = "Option::is_none")]
672        pub is_residential_proxy: Option<bool>,
673        /// True if the IP is a Tor exit node.
674        #[serde(default, skip_serializing_if = "Option::is_none")]
675        pub is_tor_exit_node: Option<bool>,
676        /// The mobile country code (MCC) associated with the IP.
677        /// See <https://en.wikipedia.org/wiki/Mobile_country_code>.
678        #[serde(default, skip_serializing_if = "Option::is_none")]
679        pub mobile_country_code: Option<&'a str>,
680        /// The mobile network code (MNC) associated with the IP.
681        /// See <https://en.wikipedia.org/wiki/Mobile_network_code>.
682        #[serde(default, skip_serializing_if = "Option::is_none")]
683        pub mobile_network_code: Option<&'a str>,
684        /// The name of the organization associated with the IP address.
685        #[serde(default, skip_serializing_if = "Option::is_none")]
686        pub organization: Option<&'a str>,
687        /// The user type associated with the IP address. Possible values include
688        /// "business", "cafe", "cellular", "college", "government", "hosting",
689        /// "library", "military", "residential", "router", "school",
690        /// "search_engine_spider", and "traveler".
691        #[serde(default, skip_serializing_if = "Option::is_none")]
692        pub user_type: Option<&'a str>,
693    }
694
695    impl_is_empty_via_default!(Traits<'_>);
696}