1use core::ops::{Deref, DerefMut};
5
6use crate::header::schema::{SchemaSubType, SchemaType};
7
8pub const RECORD_FIELD_LEN_WITHOUT_IP: u32 = 4;
10
11pub const RECORD_FIELDS_DBN_LIST: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
14
15pub 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
160pub const RECORD_FIELDS_PXN_LIST: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
164
165pub 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
305pub enum RecordField {
306 IP,
307 COUNTRY,
309 REGION,
310 CITY,
311 ISP,
312 DOMAIN,
313 LATITUDE,
315 LONGITUDE,
316 ZIPCODE,
317 TIMEZONE,
318 NETSPEED,
319 PROXYTYPE,
321 USAGETYPE,
322 ASN,
323 AS,
324 LASTSEEN,
325 THREAT,
326 RESIDENTIAL,
327 PROVIDER,
328}
329
330#[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 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 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 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 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#[derive(Debug, Clone)]
449pub enum RecordFieldContent {
450 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 LATITUDE(f32),
458 LONGITUDE(f32),
459 ZIPCODE(u32, Option<Box<str>>),
460 TIMEZONE(u32, Option<Box<str>>),
461 NETSPEED(u32, Option<Box<str>>),
462 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 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 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}