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}