use crate::geo_ip_reader::Record;
use std::collections::HashMap;
use std::net::{Ipv4Addr, Ipv6Addr};
pub fn single_level(value: &'static str) -> HashMap<&'static str, &'static str> {
let mut map = HashMap::new();
map.insert("default", value);
map
}
pub fn multi_level(
entries: Vec<(&'static str, &'static str)>,
) -> HashMap<&'static str, &'static str> {
entries.into_iter().collect()
}
pub fn ip_to_number(ip: &str) -> u128 {
match ip.parse::<Ipv4Addr>() {
Ok(ipv4_addr) => {
let ipv4_u32: u32 = u32::from(ipv4_addr);
u128::from(ipv4_u32)
}
Err(_) => {
match ip.parse::<Ipv6Addr>() {
Ok(ipv6_addr) => {
let segments = ipv6_addr.segments();
(u128::from(segments[0]) << 112)
| (u128::from(segments[1]) << 96)
| (u128::from(segments[2]) << 64)
| u128::from(segments[3])
}
Err(_) => {
panic!("Invalid IP address: {}", ip);
}
}
}
}
}
pub fn read_data(buffer: &[u8], pos: usize) -> (usize, Option<Box<str>>) {
let mut cur = pos;
while buffer[cur] != 0 {
cur += 1;
}
let data = if cur > pos {
Some(
String::from_utf8_lossy(&buffer[pos..cur])
.to_string()
.into_boxed_str(),
)
} else {
None
};
(cur, data)
}
pub fn pretty_print_dict(record: Record) {
let data: Vec<(&str, Option<String>)> = vec![
("dma_code", record.dma.map(|d| d.dma_code().to_string())),
("area_code", record.dma.map(|d| d.area_code().to_string())),
("metro_code", record.dma.map(|c| c.to_string())),
(
"postal_code",
record.postal_code.as_ref().map(|d| d.to_string()),
),
(
"country_code",
Some(record.country.alphabetic_code_2().to_string()),
),
(
"country_code3",
Some(record.country.alphabetic_code_3().to_string()),
),
("country_name", Some(record.country.to_string())),
(
"continent",
record.country.continent().map(|c| c.to_string()),
),
("region_code", record.region_code.map(|d| d.to_string())),
("city", record.city.map(|d| d.to_string())),
("latitude", Some(record.latitude.to_string())),
("longitude", Some(record.longitude.to_string())),
("time_zone", Some(record.time_zone.to_string())),
];
let mut sorted_data = data.clone();
sorted_data.sort_by(|a, b| a.0.cmp(b.0));
println!("{{");
for (key, value) in sorted_data {
print!(" \"\u{1b}[1;32m{}\": ", key); match value {
Some(v) => print!("\u{1b}[1;37m\"{}\"\u{1b}[0m,", v), None => print!("\u{1b}[1;30mnull\u{1b}[0m,"), }
println!();
}
println!("}}");
}
#[cfg(test)]
mod tests {
use super::*;
use std::collections::HashMap;
#[test]
fn test_single_level() {
let map: HashMap<&'static str, &'static str> = single_level("example_value");
assert_eq!(map.get("default"), Some(&"example_value"));
assert_eq!(map.len(), 1);
}
#[test]
fn test_multi_level() {
let entries = vec![("key1", "value1"), ("key2", "value2")];
let map: HashMap<&'static str, &'static str> = multi_level(entries);
assert_eq!(map.get("key1"), Some(&"value1"));
assert_eq!(map.get("key2"), Some(&"value2"));
assert_eq!(map.len(), 2);
}
#[test]
fn test_ip_to_number_ipv4() {
let ipv4_address = "192.168.1.1";
let result = ip_to_number(ipv4_address);
assert_eq!(result, 3232235777);
}
#[test]
fn test_ip_to_number_ipv6() {
let ipv6_address = "2001:0db8:85a3:0000:0000:8a2e:0370:7334";
let result = ip_to_number(ipv6_address);
assert_eq!(result, 42540766411283223938465490629124161536);
}
#[test]
#[should_panic(expected = "Invalid IP address")]
fn test_ip_to_number_invalid() {
let invalid_address = "invalid_ip";
ip_to_number(invalid_address);
}
#[test]
fn test_read_data_with_valid_string() {
let buffer = b"Hello\0World";
let pos = 0;
let (new_pos, data) = read_data(buffer, pos);
assert_eq!(new_pos, 5);
assert_eq!(data, Some("Hello".into()));
}
#[test]
fn test_read_data_with_empty_string() {
let buffer = b"\0World";
let pos = 0;
let (new_pos, data) = read_data(buffer, pos);
assert_eq!(new_pos, 0);
assert_eq!(data, None);
}
#[test]
#[should_panic(expected = "index out of bounds: the len is 10 but the index is 10")]
fn test_read_data_with_no_null_terminator() {
let buffer = b"HelloWorld";
let pos = 0;
let (new_pos, data) = read_data(buffer, pos);
assert_eq!(new_pos, buffer.len());
assert_eq!(data, None);
}
}
#[macro_export]
macro_rules! codegen {
($name: expr) => {
include!(concat!(env!("OUT_DIR"), "/", $name))
};
(statement; $name: expr) => {
include!(concat!(env!("OUT_DIR"), "/", $name));
};
}