use core::ops::{Deref, DerefMut};
use crate::header::schema::{SchemaSubType, SchemaType};
pub const RECORD_FIELD_LEN_WITHOUT_IP: u32 = 4;
pub const RECORD_FIELDS_DBN_LIST: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14];
pub const RECORD_FIELDS_DB1: &[RecordField] = &[RecordField::IP, RecordField::COUNTRY];
pub const RECORD_FIELDS_DB2: &[RecordField] =
&[RecordField::IP, RecordField::COUNTRY, RecordField::ISP];
pub const RECORD_FIELDS_DB3: &[RecordField] = &[
RecordField::IP,
RecordField::COUNTRY,
RecordField::REGION,
RecordField::CITY,
];
pub const RECORD_FIELDS_DB4: &[RecordField] = &[
RecordField::IP,
RecordField::COUNTRY,
RecordField::REGION,
RecordField::CITY,
RecordField::ISP,
];
pub const RECORD_FIELDS_DB5: &[RecordField] = &[
RecordField::IP,
RecordField::COUNTRY,
RecordField::REGION,
RecordField::CITY,
RecordField::LATITUDE,
RecordField::LONGITUDE,
];
pub const RECORD_FIELDS_DB6: &[RecordField] = &[
RecordField::IP,
RecordField::COUNTRY,
RecordField::REGION,
RecordField::CITY,
RecordField::LATITUDE,
RecordField::LONGITUDE,
RecordField::ISP,
];
pub const RECORD_FIELDS_DB7: &[RecordField] = &[
RecordField::IP,
RecordField::COUNTRY,
RecordField::REGION,
RecordField::CITY,
RecordField::ISP,
RecordField::DOMAIN,
];
pub const RECORD_FIELDS_DB8: &[RecordField] = &[
RecordField::IP,
RecordField::COUNTRY,
RecordField::REGION,
RecordField::CITY,
RecordField::LATITUDE,
RecordField::LONGITUDE,
RecordField::ISP,
RecordField::DOMAIN,
];
pub const RECORD_FIELDS_DB9: &[RecordField] = &[
RecordField::IP,
RecordField::COUNTRY,
RecordField::REGION,
RecordField::CITY,
RecordField::LATITUDE,
RecordField::LONGITUDE,
RecordField::ZIPCODE,
];
pub const RECORD_FIELDS_DB10: &[RecordField] = &[
RecordField::IP,
RecordField::COUNTRY,
RecordField::REGION,
RecordField::CITY,
RecordField::LATITUDE,
RecordField::LONGITUDE,
RecordField::ZIPCODE,
RecordField::ISP,
RecordField::DOMAIN,
];
pub const RECORD_FIELDS_DB11: &[RecordField] = &[
RecordField::IP,
RecordField::COUNTRY,
RecordField::REGION,
RecordField::CITY,
RecordField::LATITUDE,
RecordField::LONGITUDE,
RecordField::ZIPCODE,
RecordField::TIMEZONE,
];
pub const RECORD_FIELDS_DB12: &[RecordField] = &[
RecordField::IP,
RecordField::COUNTRY,
RecordField::REGION,
RecordField::CITY,
RecordField::LATITUDE,
RecordField::LONGITUDE,
RecordField::ZIPCODE,
RecordField::TIMEZONE,
RecordField::ISP,
RecordField::DOMAIN,
];
pub const RECORD_FIELDS_DB13: &[RecordField] = &[
RecordField::IP,
RecordField::COUNTRY,
RecordField::REGION,
RecordField::CITY,
RecordField::LATITUDE,
RecordField::LONGITUDE,
RecordField::TIMEZONE,
RecordField::NETSPEED,
];
pub const RECORD_FIELDS_DB14: &[RecordField] = &[
RecordField::IP,
RecordField::COUNTRY,
RecordField::REGION,
RecordField::CITY,
RecordField::LATITUDE,
RecordField::LONGITUDE,
RecordField::ZIPCODE,
RecordField::TIMEZONE,
RecordField::ISP,
RecordField::DOMAIN,
RecordField::NETSPEED,
];
pub const RECORD_FIELDS_PXN_LIST: &[u8] = &[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11];
pub const RECORD_FIELDS_PX1: &[RecordField] = &[RecordField::IP, RecordField::COUNTRY];
pub const RECORD_FIELDS_PX2: &[RecordField] = &[
RecordField::IP,
RecordField::PROXYTYPE,
RecordField::COUNTRY,
];
pub const RECORD_FIELDS_PX3: &[RecordField] = &[
RecordField::IP,
RecordField::PROXYTYPE,
RecordField::COUNTRY,
RecordField::REGION,
RecordField::CITY,
];
pub const RECORD_FIELDS_PX4: &[RecordField] = &[
RecordField::IP,
RecordField::PROXYTYPE,
RecordField::COUNTRY,
RecordField::REGION,
RecordField::CITY,
RecordField::ISP,
];
pub const RECORD_FIELDS_PX5: &[RecordField] = &[
RecordField::IP,
RecordField::PROXYTYPE,
RecordField::COUNTRY,
RecordField::REGION,
RecordField::CITY,
RecordField::ISP,
RecordField::DOMAIN,
];
pub const RECORD_FIELDS_PX6: &[RecordField] = &[
RecordField::IP,
RecordField::PROXYTYPE,
RecordField::COUNTRY,
RecordField::REGION,
RecordField::CITY,
RecordField::ISP,
RecordField::DOMAIN,
RecordField::USAGETYPE,
];
pub const RECORD_FIELDS_PX7: &[RecordField] = &[
RecordField::IP,
RecordField::PROXYTYPE,
RecordField::COUNTRY,
RecordField::REGION,
RecordField::CITY,
RecordField::ISP,
RecordField::DOMAIN,
RecordField::USAGETYPE,
RecordField::ASN,
RecordField::AS,
];
pub const RECORD_FIELDS_PX8: &[RecordField] = &[
RecordField::IP,
RecordField::PROXYTYPE,
RecordField::COUNTRY,
RecordField::REGION,
RecordField::CITY,
RecordField::ISP,
RecordField::DOMAIN,
RecordField::USAGETYPE,
RecordField::ASN,
RecordField::AS,
RecordField::LASTSEEN,
];
pub const RECORD_FIELDS_PX9: &[RecordField] = &[
RecordField::IP,
RecordField::PROXYTYPE,
RecordField::COUNTRY,
RecordField::REGION,
RecordField::CITY,
RecordField::ISP,
RecordField::DOMAIN,
RecordField::USAGETYPE,
RecordField::ASN,
RecordField::AS,
RecordField::LASTSEEN,
RecordField::THREAT,
];
pub const RECORD_FIELDS_PX10: &[RecordField] = &[
RecordField::IP,
RecordField::PROXYTYPE,
RecordField::COUNTRY,
RecordField::REGION,
RecordField::CITY,
RecordField::ISP,
RecordField::DOMAIN,
RecordField::USAGETYPE,
RecordField::ASN,
RecordField::AS,
RecordField::LASTSEEN,
RecordField::THREAT,
];
pub const RECORD_FIELDS_PX11: &[RecordField] = &[
RecordField::IP,
RecordField::PROXYTYPE,
RecordField::COUNTRY,
RecordField::REGION,
RecordField::CITY,
RecordField::ISP,
RecordField::DOMAIN,
RecordField::USAGETYPE,
RecordField::ASN,
RecordField::AS,
RecordField::LASTSEEN,
RecordField::THREAT,
RecordField::PROVIDER,
];
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum RecordField {
IP,
COUNTRY,
REGION,
CITY,
ISP,
DOMAIN,
LATITUDE,
LONGITUDE,
ZIPCODE,
TIMEZONE,
NETSPEED,
PROXYTYPE,
USAGETYPE,
ASN,
AS,
LASTSEEN,
THREAT,
RESIDENTIAL,
PROVIDER,
}
#[derive(Debug, Clone)]
pub struct RecordFields(Vec<RecordField>);
impl RecordFields {
pub fn record_bytes_len_for_ipv4(&self) -> u32 {
self.0.len() as u32 * RECORD_FIELD_LEN_WITHOUT_IP
}
pub fn record_bytes_len_for_ipv4_with_double_ip(&self) -> u32 {
self.record_bytes_len_for_ipv4() + 4
}
pub fn records_bytes_len_for_ipv4(&self, n: u32) -> u32 {
self.record_bytes_len_for_ipv4() * n
}
pub fn record_bytes_len_for_ipv6(&self) -> u32 {
self.0.len() as u32 * RECORD_FIELD_LEN_WITHOUT_IP + 12
}
pub fn record_bytes_len_for_ipv6_with_double_ip(&self) -> u32 {
self.record_bytes_len_for_ipv6() + 16
}
pub fn records_bytes_len_for_ipv6(&self, n: u32) -> u32 {
self.record_bytes_len_for_ipv6() * n
}
pub fn to_contents(&self) -> RecordFieldContents {
assert_eq!(self.0[0], RecordField::IP);
let inner = self.0[1..]
.iter()
.map(|x| match x {
RecordField::IP => {
unreachable!()
}
RecordField::COUNTRY => {
RecordFieldContent::COUNTRY(0, Default::default(), Default::default())
}
RecordField::REGION => RecordFieldContent::REGION(0, Default::default()),
RecordField::CITY => RecordFieldContent::CITY(0, Default::default()),
RecordField::ISP => RecordFieldContent::ISP(0, Default::default()),
RecordField::DOMAIN => RecordFieldContent::DOMAIN(0, Default::default()),
RecordField::LATITUDE => RecordFieldContent::LATITUDE(0.0),
RecordField::LONGITUDE => RecordFieldContent::LONGITUDE(0.0),
RecordField::ZIPCODE => RecordFieldContent::ZIPCODE(0, Default::default()),
RecordField::TIMEZONE => RecordFieldContent::TIMEZONE(0, Default::default()),
RecordField::NETSPEED => RecordFieldContent::NETSPEED(0, Default::default()),
RecordField::PROXYTYPE => RecordFieldContent::PROXYTYPE(0, Default::default()),
RecordField::USAGETYPE => RecordFieldContent::USAGETYPE(0, Default::default()),
RecordField::ASN => RecordFieldContent::ASN(0, Default::default()),
RecordField::AS => RecordFieldContent::AS(0, Default::default()),
RecordField::LASTSEEN => RecordFieldContent::LASTSEEN(0, Default::default()),
RecordField::THREAT => RecordFieldContent::THREAT(0, Default::default()),
RecordField::RESIDENTIAL => RecordFieldContent::RESIDENTIAL(0, Default::default()),
RecordField::PROVIDER => RecordFieldContent::PROVIDER(0, Default::default()),
})
.collect::<Vec<_>>();
RecordFieldContents(inner)
}
}
impl Deref for RecordFields {
type Target = Vec<RecordField>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl TryFrom<(SchemaType, SchemaSubType)> for RecordFields {
type Error = SchemaSubType;
fn try_from((r#type, sub_type): (SchemaType, SchemaSubType)) -> Result<Self, Self::Error> {
match r#type {
SchemaType::IP2Location | SchemaType::None => match sub_type.0 {
1 => Ok(Self(RECORD_FIELDS_DB1.to_owned())),
2 => Ok(Self(RECORD_FIELDS_DB2.to_owned())),
3 => Ok(Self(RECORD_FIELDS_DB3.to_owned())),
4 => Ok(Self(RECORD_FIELDS_DB4.to_owned())),
5 => Ok(Self(RECORD_FIELDS_DB5.to_owned())),
6 => Ok(Self(RECORD_FIELDS_DB6.to_owned())),
7 => Ok(Self(RECORD_FIELDS_DB7.to_owned())),
8 => Ok(Self(RECORD_FIELDS_DB8.to_owned())),
9 => Ok(Self(RECORD_FIELDS_DB9.to_owned())),
10 => Ok(Self(RECORD_FIELDS_DB10.to_owned())),
11 => Ok(Self(RECORD_FIELDS_DB11.to_owned())),
12 => Ok(Self(RECORD_FIELDS_DB12.to_owned())),
13 => Ok(Self(RECORD_FIELDS_DB13.to_owned())),
14 => Ok(Self(RECORD_FIELDS_DB14.to_owned())),
_ => Err(sub_type),
},
SchemaType::IP2Proxy => match sub_type.0 {
1 => Ok(Self(RECORD_FIELDS_PX1.to_owned())),
2 => Ok(Self(RECORD_FIELDS_PX2.to_owned())),
3 => Ok(Self(RECORD_FIELDS_PX3.to_owned())),
4 => Ok(Self(RECORD_FIELDS_PX4.to_owned())),
5 => Ok(Self(RECORD_FIELDS_PX5.to_owned())),
6 => Ok(Self(RECORD_FIELDS_PX6.to_owned())),
7 => Ok(Self(RECORD_FIELDS_PX7.to_owned())),
8 => Ok(Self(RECORD_FIELDS_PX8.to_owned())),
9 => Ok(Self(RECORD_FIELDS_PX9.to_owned())),
10 => Ok(Self(RECORD_FIELDS_PX10.to_owned())),
11 => Ok(Self(RECORD_FIELDS_PX11.to_owned())),
_ => Err(sub_type),
},
}
}
}
#[derive(Debug, Clone)]
pub enum RecordFieldContent {
COUNTRY(u32, Option<Box<str>>, Option<Box<str>>),
REGION(u32, Option<Box<str>>),
CITY(u32, Option<Box<str>>),
ISP(u32, Option<Box<str>>),
DOMAIN(u32, Option<Box<str>>),
LATITUDE(f32),
LONGITUDE(f32),
ZIPCODE(u32, Option<Box<str>>),
TIMEZONE(u32, Option<Box<str>>),
NETSPEED(u32, Option<Box<str>>),
PROXYTYPE(u32, Option<Box<str>>),
USAGETYPE(u32, Option<Box<str>>),
ASN(u32, Option<Box<str>>),
AS(u32, Option<Box<str>>),
LASTSEEN(u32, Option<Box<str>>),
THREAT(u32, Option<Box<str>>),
RESIDENTIAL(u32, Option<Box<str>>),
PROVIDER(u32, Option<Box<str>>),
}
#[derive(Debug, Clone)]
pub struct RecordFieldContents(Vec<RecordFieldContent>);
impl Deref for RecordFieldContents {
type Target = Vec<RecordFieldContent>;
fn deref(&self) -> &Self::Target {
&self.0
}
}
impl DerefMut for RecordFieldContents {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.0
}
}
impl RecordFieldContents {
pub fn select(&mut self, record_fields: &[RecordField]) {
self.0.retain(|x| match x {
RecordFieldContent::COUNTRY(_, _, _) => record_fields.contains(&RecordField::COUNTRY),
RecordFieldContent::REGION(_, _) => record_fields.contains(&RecordField::REGION),
RecordFieldContent::CITY(_, _) => record_fields.contains(&RecordField::CITY),
RecordFieldContent::ISP(_, _) => record_fields.contains(&RecordField::ISP),
RecordFieldContent::DOMAIN(_, _) => record_fields.contains(&RecordField::DOMAIN),
RecordFieldContent::LATITUDE(_) => record_fields.contains(&RecordField::LATITUDE),
RecordFieldContent::LONGITUDE(_) => record_fields.contains(&RecordField::LONGITUDE),
RecordFieldContent::ZIPCODE(_, _) => record_fields.contains(&RecordField::ZIPCODE),
RecordFieldContent::TIMEZONE(_, _) => record_fields.contains(&RecordField::TIMEZONE),
RecordFieldContent::NETSPEED(_, _) => record_fields.contains(&RecordField::NETSPEED),
RecordFieldContent::PROXYTYPE(_, _) => record_fields.contains(&RecordField::PROXYTYPE),
RecordFieldContent::USAGETYPE(_, _) => record_fields.contains(&RecordField::USAGETYPE),
RecordFieldContent::ASN(_, _) => record_fields.contains(&RecordField::ASN),
RecordFieldContent::AS(_, _) => record_fields.contains(&RecordField::AS),
RecordFieldContent::LASTSEEN(_, _) => record_fields.contains(&RecordField::LASTSEEN),
RecordFieldContent::THREAT(_, _) => record_fields.contains(&RecordField::THREAT),
RecordFieldContent::RESIDENTIAL(_, _) => {
record_fields.contains(&RecordField::RESIDENTIAL)
}
RecordFieldContent::PROVIDER(_, _) => record_fields.contains(&RecordField::PROVIDER),
});
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_record_fields_prefix() {
for n in RECORD_FIELDS_DBN_LIST {
assert_eq!(
RecordFields::try_from((SchemaType::IP2Location, SchemaSubType(*n)))
.unwrap()
.0[0],
RecordField::IP
)
}
for n in RECORD_FIELDS_PXN_LIST {
assert_eq!(
RecordFields::try_from((SchemaType::IP2Proxy, SchemaSubType(*n)))
.unwrap()
.0[0],
RecordField::IP
)
}
}
}