ip2location_iso3166_2/
csv_format.rs1use core::ops::Deref;
2use std::io::Read;
3
4use csv::{Error as CsvError, Reader, StringRecord};
5
6use crate::record::Record;
7
8#[cfg(feature = "once_cell")]
10pub static RECORDS: once_cell::sync::Lazy<Records> = once_cell::sync::Lazy::new(|| {
11 let csv = include_str!("../data/IP2LOCATION-ISO3166-2.CSV");
12 Records::from_csv(csv.as_bytes()).unwrap()
13});
14
15#[cfg(feature = "once_cell")]
16pub static RECORDS_CODE_MAP: once_cell::sync::Lazy<
17 std::collections::HashMap<country_code::iso3166_2::SubdivisionCode, Record>,
18> = once_cell::sync::Lazy::new(|| {
19 RECORDS
20 .iter()
21 .cloned()
22 .map(|x| (x.code.to_owned(), x))
23 .collect()
24});
25
26#[derive(Debug, Clone)]
28pub struct Records(pub Vec<Record>);
29
30impl Deref for Records {
31 type Target = Vec<Record>;
32
33 fn deref(&self) -> &Self::Target {
34 &self.0
35 }
36}
37
38impl Records {
40 pub fn from_csv<R: Read>(rdr: R) -> Result<Self, RecordsFromCsvError> {
41 let mut rdr = Reader::from_reader(rdr);
42
43 let mut inner = vec![];
44
45 for record in rdr.records() {
46 let record = record.map_err(RecordsFromCsvError::CsvParseFailed)?;
47
48 let record = if record.get(2) == Some("-") {
52 StringRecord::from(vec![
53 &record[0],
54 &record[1],
55 format!("{}-", &record[0]).as_str(),
56 ])
57 } else {
58 record
59 };
60
61 let row: Record = record
62 .deserialize(None)
63 .map_err(RecordsFromCsvError::RecordDeFailed)?;
64 inner.push(row);
65 }
66
67 Ok(Self(inner))
68 }
69}
70
71#[derive(Debug)]
73pub enum RecordsFromCsvError {
74 CsvParseFailed(CsvError),
75 RecordDeFailed(CsvError),
76}
77
78impl core::fmt::Display for RecordsFromCsvError {
79 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
80 write!(f, "{self:?}")
81 }
82}
83
84impl std::error::Error for RecordsFromCsvError {}