ip2location_bin_format/
record_field.rs

1//! https://lite.ip2location.com/ip2location-lite#db11-lite
2//! https://lite.ip2location.com/ip2proxy-lite#px11-lite
3
4use core::ops::{Deref, DerefMut};
5
6use crate::header::schema::{SchemaSubType, SchemaType};
7
8//
9pub const RECORD_FIELD_LEN_WITHOUT_IP: u32 = 4;
10
11//
12// TODO,  15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25
13pub const RECORD_FIELDS_DBN_LIST: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
14
15/*
16https://github.com/ip2location/ip2location-go/blob/v9.2.0/ip2location.go#L123-L143
17
18var country_position            = [26]uint8{0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,  2, 2,   2,  2,  2,  2,  2,  2,  2,  2,  2,  2,  2}
19var region_position             = [26]uint8{0, 0, 0, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,  3, 3,   3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3}
20var city_position               = [26]uint8{0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,  4, 4,   4,  4,  4,  4,  4,  4,  4,  4,  4,  4,  4}
21var isp_position                = [26]uint8{0, 0, 3, 0, 5, 0, 7, 5, 7, 0, 8, 0, 9,  0, 9,   0,  9,  0,  9,  7,  9,  0,  9,  7,  9,  9}
22var latitude_position           = [26]uint8{0, 0, 0, 0, 0, 5, 5, 0, 5, 5, 5, 5, 5,  5, 5,   5,  5,  5,  5,  5,  5,  5,  5,  5,  5,  5}
23var longitude_position          = [26]uint8{0, 0, 0, 0, 0, 6, 6, 0, 6, 6, 6, 6, 6,  6, 6,   6,  6,  6,  6,  6,  6,  6,  6,  6,  6,  6}
24var domain_position             = [26]uint8{0, 0, 0, 0, 0, 0, 0, 6, 8, 0, 9, 0, 10, 0, 10,  0, 10,  0, 10,  8, 10,  0, 10,  8, 10, 10}
25var zipcode_position            = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 7, 7, 7,  0,  7,  7,  7,  0,  7,  0,  7,  7,  7,  0,  7,  7}
26var timezone_position           = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8, 8,  7,  8,  8,  8,  7,  8,  0,  8,  8,  8,  0,  8,  8}
27var netspeed_position           = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  8, 11,  0, 11,  8, 11,  0, 11,  0, 11,  0, 11, 11}
28var iddcode_position            = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  9, 12,  0, 12,  0, 12,  9, 12,  0, 12, 12}
29var areacode_position           = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0, 10, 13,  0, 13,  0, 13, 10, 13,  0, 13, 13}
30var weatherstationcode_position = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  9, 14,  0, 14,  0, 14,  0, 14, 14}
31var weatherstationname_position = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0, 10, 15,  0, 15,  0, 15,  0, 15, 15}
32var mcc_position                = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,  9, 16,  0, 16,  9, 16, 16}
33var mnc_position                = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0, 10, 17,  0, 17, 10, 17, 17}
34var mobilebrand_position        = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0, 11, 18,  0, 18, 11, 18, 18}
35var elevation_position          = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0, 11, 19,  0, 19, 19}
36var usagetype_position          = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 12, 20, 20}
37var addresstype_position        = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 21}
38var category_position           = [26]uint8{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0, 22}
39
40                                               1  2  3  4  5  6  7  8  9  10 11 12  13  14  15  16  17  18  19  20  21  22  23  24 25
41*/
42
43pub const RECORD_FIELDS_DB1: &[RecordField] = &[RecordField::IP, RecordField::COUNTRY];
44pub const RECORD_FIELDS_DB2: &[RecordField] =
45    &[RecordField::IP, RecordField::COUNTRY, RecordField::ISP];
46pub const RECORD_FIELDS_DB3: &[RecordField] = &[
47    RecordField::IP,
48    RecordField::COUNTRY,
49    RecordField::REGION,
50    RecordField::CITY,
51];
52pub const RECORD_FIELDS_DB4: &[RecordField] = &[
53    RecordField::IP,
54    RecordField::COUNTRY,
55    RecordField::REGION,
56    RecordField::CITY,
57    RecordField::ISP,
58];
59pub const RECORD_FIELDS_DB5: &[RecordField] = &[
60    RecordField::IP,
61    RecordField::COUNTRY,
62    RecordField::REGION,
63    RecordField::CITY,
64    RecordField::LATITUDE,
65    RecordField::LONGITUDE,
66];
67pub const RECORD_FIELDS_DB6: &[RecordField] = &[
68    RecordField::IP,
69    RecordField::COUNTRY,
70    RecordField::REGION,
71    RecordField::CITY,
72    RecordField::LATITUDE,
73    RecordField::LONGITUDE,
74    RecordField::ISP,
75];
76pub const RECORD_FIELDS_DB7: &[RecordField] = &[
77    RecordField::IP,
78    RecordField::COUNTRY,
79    RecordField::REGION,
80    RecordField::CITY,
81    RecordField::ISP,
82    RecordField::DOMAIN,
83];
84pub const RECORD_FIELDS_DB8: &[RecordField] = &[
85    RecordField::IP,
86    RecordField::COUNTRY,
87    RecordField::REGION,
88    RecordField::CITY,
89    RecordField::LATITUDE,
90    RecordField::LONGITUDE,
91    RecordField::ISP,
92    RecordField::DOMAIN,
93];
94pub const RECORD_FIELDS_DB9: &[RecordField] = &[
95    RecordField::IP,
96    RecordField::COUNTRY,
97    RecordField::REGION,
98    RecordField::CITY,
99    RecordField::LATITUDE,
100    RecordField::LONGITUDE,
101    RecordField::ZIPCODE,
102];
103pub const RECORD_FIELDS_DB10: &[RecordField] = &[
104    RecordField::IP,
105    RecordField::COUNTRY,
106    RecordField::REGION,
107    RecordField::CITY,
108    RecordField::LATITUDE,
109    RecordField::LONGITUDE,
110    RecordField::ZIPCODE,
111    RecordField::ISP,
112    RecordField::DOMAIN,
113];
114pub const RECORD_FIELDS_DB11: &[RecordField] = &[
115    RecordField::IP,
116    RecordField::COUNTRY,
117    RecordField::REGION,
118    RecordField::CITY,
119    RecordField::LATITUDE,
120    RecordField::LONGITUDE,
121    RecordField::ZIPCODE,
122    RecordField::TIMEZONE,
123];
124pub const RECORD_FIELDS_DB12: &[RecordField] = &[
125    RecordField::IP,
126    RecordField::COUNTRY,
127    RecordField::REGION,
128    RecordField::CITY,
129    RecordField::LATITUDE,
130    RecordField::LONGITUDE,
131    RecordField::ZIPCODE,
132    RecordField::TIMEZONE,
133    RecordField::ISP,
134    RecordField::DOMAIN,
135];
136pub const RECORD_FIELDS_DB13: &[RecordField] = &[
137    RecordField::IP,
138    RecordField::COUNTRY,
139    RecordField::REGION,
140    RecordField::CITY,
141    RecordField::LATITUDE,
142    RecordField::LONGITUDE,
143    RecordField::TIMEZONE,
144    RecordField::NETSPEED,
145];
146pub const RECORD_FIELDS_DB14: &[RecordField] = &[
147    RecordField::IP,
148    RecordField::COUNTRY,
149    RecordField::REGION,
150    RecordField::CITY,
151    RecordField::LATITUDE,
152    RecordField::LONGITUDE,
153    RecordField::ZIPCODE,
154    RecordField::TIMEZONE,
155    RecordField::ISP,
156    RecordField::DOMAIN,
157    RecordField::NETSPEED,
158];
159
160// TODO, RECORD_FIELDS_DB15 - RECORD_FIELDS_DB25
161
162//
163pub const RECORD_FIELDS_PXN_LIST: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
164
165/*
166https://github.com/ip2location/ip2proxy-go/blob/v3.3.2/ip2proxy.go#L99-L110
167
168var countryPosition   = [12]uint8{0, 2, 3, 3, 3, 3, 3,  3,  3,  3,  3,  3}
169var regionPosition    = [12]uint8{0, 0, 0, 4, 4, 4, 4,  4,  4,  4,  4,  4}
170var cityPosition      = [12]uint8{0, 0, 0, 5, 5, 5, 5,  5,  5,  5,  5,  5}
171var ispPosition       = [12]uint8{0, 0, 0, 0, 6, 6, 6,  6,  6,  6,  6,  6}
172var proxyTypePosition = [12]uint8{0, 0, 2, 2, 2, 2, 2,  2,  2,  2,  2,  2}
173var domainPosition    = [12]uint8{0, 0, 0, 0, 0, 7, 7,  7,  7,  7,  7,  7}
174var usageTypePosition = [12]uint8{0, 0, 0, 0, 0, 0, 8,  8,  8,  8,  8,  8}
175var asnPosition       = [12]uint8{0, 0, 0, 0, 0, 0, 0,  9,  9,  9,  9,  9}
176var asPosition        = [12]uint8{0, 0, 0, 0, 0, 0, 0, 10, 10, 10, 10, 10}
177var lastSeenPosition  = [12]uint8{0, 0, 0, 0, 0, 0, 0,  0, 11, 11, 11, 11}
178var threatPosition    = [12]uint8{0, 0, 0, 0, 0, 0, 0,  0,  0, 12, 12, 12}
179var providerPosition  = [12]uint8{0, 0, 0, 0, 0, 0, 0,  0,  0,  0,  0, 13}
180
181                                     1  2  3  4  5  6   7   8   9  10  11
182*/
183
184pub const RECORD_FIELDS_PX1: &[RecordField] = &[RecordField::IP, RecordField::COUNTRY];
185
186pub const RECORD_FIELDS_PX2: &[RecordField] = &[
187    RecordField::IP,
188    RecordField::PROXYTYPE,
189    RecordField::COUNTRY,
190];
191
192pub const RECORD_FIELDS_PX3: &[RecordField] = &[
193    RecordField::IP,
194    RecordField::PROXYTYPE,
195    RecordField::COUNTRY,
196    RecordField::REGION,
197    RecordField::CITY,
198];
199
200pub const RECORD_FIELDS_PX4: &[RecordField] = &[
201    RecordField::IP,
202    RecordField::PROXYTYPE,
203    RecordField::COUNTRY,
204    RecordField::REGION,
205    RecordField::CITY,
206    RecordField::ISP,
207];
208
209pub const RECORD_FIELDS_PX5: &[RecordField] = &[
210    RecordField::IP,
211    RecordField::PROXYTYPE,
212    RecordField::COUNTRY,
213    RecordField::REGION,
214    RecordField::CITY,
215    RecordField::ISP,
216    RecordField::DOMAIN,
217];
218
219pub const RECORD_FIELDS_PX6: &[RecordField] = &[
220    RecordField::IP,
221    RecordField::PROXYTYPE,
222    RecordField::COUNTRY,
223    RecordField::REGION,
224    RecordField::CITY,
225    RecordField::ISP,
226    RecordField::DOMAIN,
227    RecordField::USAGETYPE,
228];
229
230pub const RECORD_FIELDS_PX7: &[RecordField] = &[
231    RecordField::IP,
232    RecordField::PROXYTYPE,
233    RecordField::COUNTRY,
234    RecordField::REGION,
235    RecordField::CITY,
236    RecordField::ISP,
237    RecordField::DOMAIN,
238    RecordField::USAGETYPE,
239    RecordField::ASN,
240    RecordField::AS,
241];
242
243pub const RECORD_FIELDS_PX8: &[RecordField] = &[
244    RecordField::IP,
245    RecordField::PROXYTYPE,
246    RecordField::COUNTRY,
247    RecordField::REGION,
248    RecordField::CITY,
249    RecordField::ISP,
250    RecordField::DOMAIN,
251    RecordField::USAGETYPE,
252    RecordField::ASN,
253    RecordField::AS,
254    RecordField::LASTSEEN,
255];
256
257pub const RECORD_FIELDS_PX9: &[RecordField] = &[
258    RecordField::IP,
259    RecordField::PROXYTYPE,
260    RecordField::COUNTRY,
261    RecordField::REGION,
262    RecordField::CITY,
263    RecordField::ISP,
264    RecordField::DOMAIN,
265    RecordField::USAGETYPE,
266    RecordField::ASN,
267    RecordField::AS,
268    RecordField::LASTSEEN,
269    RecordField::THREAT,
270];
271
272pub const RECORD_FIELDS_PX10: &[RecordField] = &[
273    RecordField::IP,
274    RecordField::PROXYTYPE,
275    RecordField::COUNTRY,
276    RecordField::REGION,
277    RecordField::CITY,
278    RecordField::ISP,
279    RecordField::DOMAIN,
280    RecordField::USAGETYPE,
281    RecordField::ASN,
282    RecordField::AS,
283    RecordField::LASTSEEN,
284    RecordField::THREAT,
285];
286
287pub const RECORD_FIELDS_PX11: &[RecordField] = &[
288    RecordField::IP,
289    RecordField::PROXYTYPE,
290    RecordField::COUNTRY,
291    RecordField::REGION,
292    RecordField::CITY,
293    RecordField::ISP,
294    RecordField::DOMAIN,
295    RecordField::USAGETYPE,
296    RecordField::ASN,
297    RecordField::AS,
298    RecordField::LASTSEEN,
299    RecordField::THREAT,
300    RecordField::PROVIDER,
301];
302
303//
304#[derive(Debug, Clone, Copy, PartialEq, Eq)]
305pub enum RecordField {
306    IP,
307    // Common
308    COUNTRY,
309    REGION,
310    CITY,
311    ISP,
312    DOMAIN,
313    // IP2Location
314    LATITUDE,
315    LONGITUDE,
316    ZIPCODE,
317    TIMEZONE,
318    NETSPEED,
319    // IP2Proxy
320    PROXYTYPE,
321    USAGETYPE,
322    ASN,
323    AS,
324    LASTSEEN,
325    THREAT,
326    RESIDENTIAL,
327    PROVIDER,
328}
329
330//
331#[derive(Debug, Clone)]
332pub struct RecordFields(Vec<RecordField>);
333
334impl RecordFields {
335    pub fn record_bytes_len_for_ipv4(&self) -> u32 {
336        self.0.len() as u32 * RECORD_FIELD_LEN_WITHOUT_IP
337    }
338
339    pub fn record_bytes_len_for_ipv4_with_double_ip(&self) -> u32 {
340        self.record_bytes_len_for_ipv4() + 4
341    }
342
343    pub fn records_bytes_len_for_ipv4(&self, n: u32) -> u32 {
344        self.record_bytes_len_for_ipv4() * n
345    }
346
347    pub fn record_bytes_len_for_ipv6(&self) -> u32 {
348        // 12 = 16 - 4
349        self.0.len() as u32 * RECORD_FIELD_LEN_WITHOUT_IP + 12
350    }
351
352    pub fn record_bytes_len_for_ipv6_with_double_ip(&self) -> u32 {
353        self.record_bytes_len_for_ipv6() + 16
354    }
355
356    pub fn records_bytes_len_for_ipv6(&self, n: u32) -> u32 {
357        self.record_bytes_len_for_ipv6() * n
358    }
359
360    pub fn to_contents(&self) -> RecordFieldContents {
361        assert_eq!(self.0[0], RecordField::IP);
362
363        let inner = self.0[1..]
364            .iter()
365            .map(|x| match x {
366                RecordField::IP => {
367                    unreachable!()
368                }
369                //
370                RecordField::COUNTRY => {
371                    RecordFieldContent::COUNTRY(0, Default::default(), Default::default())
372                }
373                RecordField::REGION => RecordFieldContent::REGION(0, Default::default()),
374                RecordField::CITY => RecordFieldContent::CITY(0, Default::default()),
375                RecordField::ISP => RecordFieldContent::ISP(0, Default::default()),
376                RecordField::DOMAIN => RecordFieldContent::DOMAIN(0, Default::default()),
377                //
378                RecordField::LATITUDE => RecordFieldContent::LATITUDE(0.0),
379                RecordField::LONGITUDE => RecordFieldContent::LONGITUDE(0.0),
380                RecordField::ZIPCODE => RecordFieldContent::ZIPCODE(0, Default::default()),
381                RecordField::TIMEZONE => RecordFieldContent::TIMEZONE(0, Default::default()),
382                RecordField::NETSPEED => RecordFieldContent::NETSPEED(0, Default::default()),
383                //
384                RecordField::PROXYTYPE => RecordFieldContent::PROXYTYPE(0, Default::default()),
385                RecordField::USAGETYPE => RecordFieldContent::USAGETYPE(0, Default::default()),
386                RecordField::ASN => RecordFieldContent::ASN(0, Default::default()),
387                RecordField::AS => RecordFieldContent::AS(0, Default::default()),
388                RecordField::LASTSEEN => RecordFieldContent::LASTSEEN(0, Default::default()),
389                RecordField::THREAT => RecordFieldContent::THREAT(0, Default::default()),
390                RecordField::RESIDENTIAL => RecordFieldContent::RESIDENTIAL(0, Default::default()),
391                RecordField::PROVIDER => RecordFieldContent::PROVIDER(0, Default::default()),
392            })
393            .collect::<Vec<_>>();
394
395        RecordFieldContents(inner)
396    }
397}
398
399impl Deref for RecordFields {
400    type Target = Vec<RecordField>;
401
402    fn deref(&self) -> &Self::Target {
403        &self.0
404    }
405}
406
407impl TryFrom<(SchemaType, SchemaSubType)> for RecordFields {
408    type Error = SchemaSubType;
409
410    fn try_from((r#type, sub_type): (SchemaType, SchemaSubType)) -> Result<Self, Self::Error> {
411        match r#type {
412            SchemaType::IP2Location | SchemaType::None => match sub_type.0 {
413                1 => Ok(Self(RECORD_FIELDS_DB1.to_owned())),
414                2 => Ok(Self(RECORD_FIELDS_DB2.to_owned())),
415                3 => Ok(Self(RECORD_FIELDS_DB3.to_owned())),
416                4 => Ok(Self(RECORD_FIELDS_DB4.to_owned())),
417                5 => Ok(Self(RECORD_FIELDS_DB5.to_owned())),
418                6 => Ok(Self(RECORD_FIELDS_DB6.to_owned())),
419                7 => Ok(Self(RECORD_FIELDS_DB7.to_owned())),
420                8 => Ok(Self(RECORD_FIELDS_DB8.to_owned())),
421                9 => Ok(Self(RECORD_FIELDS_DB9.to_owned())),
422                10 => Ok(Self(RECORD_FIELDS_DB10.to_owned())),
423                11 => Ok(Self(RECORD_FIELDS_DB11.to_owned())),
424                12 => Ok(Self(RECORD_FIELDS_DB12.to_owned())),
425                13 => Ok(Self(RECORD_FIELDS_DB13.to_owned())),
426                14 => Ok(Self(RECORD_FIELDS_DB14.to_owned())),
427                _ => Err(sub_type),
428            },
429            SchemaType::IP2Proxy => match sub_type.0 {
430                1 => Ok(Self(RECORD_FIELDS_PX1.to_owned())),
431                2 => Ok(Self(RECORD_FIELDS_PX2.to_owned())),
432                3 => Ok(Self(RECORD_FIELDS_PX3.to_owned())),
433                4 => Ok(Self(RECORD_FIELDS_PX4.to_owned())),
434                5 => Ok(Self(RECORD_FIELDS_PX5.to_owned())),
435                6 => Ok(Self(RECORD_FIELDS_PX6.to_owned())),
436                7 => Ok(Self(RECORD_FIELDS_PX7.to_owned())),
437                8 => Ok(Self(RECORD_FIELDS_PX8.to_owned())),
438                9 => Ok(Self(RECORD_FIELDS_PX9.to_owned())),
439                10 => Ok(Self(RECORD_FIELDS_PX10.to_owned())),
440                11 => Ok(Self(RECORD_FIELDS_PX11.to_owned())),
441                _ => Err(sub_type),
442            },
443        }
444    }
445}
446
447//
448#[derive(Debug, Clone)]
449pub enum RecordFieldContent {
450    // Common
451    COUNTRY(u32, Option<Box<str>>, Option<Box<str>>),
452    REGION(u32, Option<Box<str>>),
453    CITY(u32, Option<Box<str>>),
454    ISP(u32, Option<Box<str>>),
455    DOMAIN(u32, Option<Box<str>>),
456    // IP2Location
457    LATITUDE(f32),
458    LONGITUDE(f32),
459    ZIPCODE(u32, Option<Box<str>>),
460    TIMEZONE(u32, Option<Box<str>>),
461    NETSPEED(u32, Option<Box<str>>),
462    // IP2Proxy
463    PROXYTYPE(u32, Option<Box<str>>),
464    USAGETYPE(u32, Option<Box<str>>),
465    ASN(u32, Option<Box<str>>),
466    AS(u32, Option<Box<str>>),
467    LASTSEEN(u32, Option<Box<str>>),
468    THREAT(u32, Option<Box<str>>),
469    RESIDENTIAL(u32, Option<Box<str>>),
470    PROVIDER(u32, Option<Box<str>>),
471}
472
473#[derive(Debug, Clone)]
474pub struct RecordFieldContents(Vec<RecordFieldContent>);
475
476impl Deref for RecordFieldContents {
477    type Target = Vec<RecordFieldContent>;
478
479    fn deref(&self) -> &Self::Target {
480        &self.0
481    }
482}
483
484impl DerefMut for RecordFieldContents {
485    fn deref_mut(&mut self) -> &mut Self::Target {
486        &mut self.0
487    }
488}
489
490impl RecordFieldContents {
491    pub fn select(&mut self, record_fields: &[RecordField]) {
492        self.0.retain(|x| match x {
493            RecordFieldContent::COUNTRY(_, _, _) => record_fields.contains(&RecordField::COUNTRY),
494            RecordFieldContent::REGION(_, _) => record_fields.contains(&RecordField::REGION),
495            RecordFieldContent::CITY(_, _) => record_fields.contains(&RecordField::CITY),
496            RecordFieldContent::ISP(_, _) => record_fields.contains(&RecordField::ISP),
497            RecordFieldContent::DOMAIN(_, _) => record_fields.contains(&RecordField::DOMAIN),
498            //
499            RecordFieldContent::LATITUDE(_) => record_fields.contains(&RecordField::LATITUDE),
500            RecordFieldContent::LONGITUDE(_) => record_fields.contains(&RecordField::LONGITUDE),
501            RecordFieldContent::ZIPCODE(_, _) => record_fields.contains(&RecordField::ZIPCODE),
502            RecordFieldContent::TIMEZONE(_, _) => record_fields.contains(&RecordField::TIMEZONE),
503            RecordFieldContent::NETSPEED(_, _) => record_fields.contains(&RecordField::NETSPEED),
504            //
505            RecordFieldContent::PROXYTYPE(_, _) => record_fields.contains(&RecordField::PROXYTYPE),
506            RecordFieldContent::USAGETYPE(_, _) => record_fields.contains(&RecordField::USAGETYPE),
507            RecordFieldContent::ASN(_, _) => record_fields.contains(&RecordField::ASN),
508            RecordFieldContent::AS(_, _) => record_fields.contains(&RecordField::AS),
509            RecordFieldContent::LASTSEEN(_, _) => record_fields.contains(&RecordField::LASTSEEN),
510            RecordFieldContent::THREAT(_, _) => record_fields.contains(&RecordField::THREAT),
511            RecordFieldContent::RESIDENTIAL(_, _) => {
512                record_fields.contains(&RecordField::RESIDENTIAL)
513            }
514            RecordFieldContent::PROVIDER(_, _) => record_fields.contains(&RecordField::PROVIDER),
515        });
516    }
517}
518
519#[cfg(test)]
520mod tests {
521    use super::*;
522
523    #[test]
524    fn test_record_fields_prefix() {
525        for n in RECORD_FIELDS_DBN_LIST {
526            assert_eq!(
527                RecordFields::try_from((SchemaType::IP2Location, SchemaSubType(*n)))
528                    .unwrap()
529                    .0[0],
530                RecordField::IP
531            )
532        }
533
534        for n in RECORD_FIELDS_PXN_LIST {
535            assert_eq!(
536                RecordFields::try_from((SchemaType::IP2Proxy, SchemaSubType(*n)))
537                    .unwrap()
538                    .0[0],
539                RecordField::IP
540            )
541        }
542    }
543}