ip2location-iso3166-2 0.1.0

IP2Location™ ISO 3166-2 Subdivision Code
Documentation
use core::{fmt, ops::Deref};
use std::io::Read;

use csv::{Error as CsvError, Reader as CsvReader};
use serde::Deserialize;

//
#[cfg(feature = "once_cell")]
pub static DATA: once_cell::sync::Lazy<Data> = once_cell::sync::Lazy::new(|| {
    let csv = include_str!("../data/IP2LOCATION-ISO3166-2.CSV");
    Data::from_csv(csv.as_bytes()).unwrap()
});

#[cfg(feature = "once_cell")]
pub static DATA_MAP: once_cell::sync::Lazy<std::collections::HashMap<Box<str>, Row>> =
    once_cell::sync::Lazy::new(|| {
        DATA.iter()
            .cloned()
            .map(|x| (x.code.to_owned(), x))
            .collect()
    });

//
#[derive(Debug, Clone)]
pub struct Data(pub Vec<Row>);

impl Deref for Data {
    type Target = Vec<Row>;

    fn deref(&self) -> &Self::Target {
        &self.0
    }
}

//
#[derive(Deserialize, Debug, Clone)]
pub struct Row {
    pub country_code: Box<str>,
    pub subdivision_name: Box<str>,
    pub code: Box<str>,
}

//
impl Data {
    pub fn from_csv<R: Read>(rdr: R) -> Result<Self, DataFromCsvError> {
        let mut rdr = CsvReader::from_reader(rdr);
        let iter = rdr.records();

        let mut inner = vec![];

        for record in iter {
            let record = record.map_err(DataFromCsvError::CsvParseFailed)?;
            let row: Row = record
                .deserialize(None)
                .map_err(DataFromCsvError::RowDeFailed)?;
            inner.push(row);
        }

        Ok(Self(inner))
    }
}

//
#[derive(Debug)]
pub enum DataFromCsvError {
    CsvParseFailed(CsvError),
    RowDeFailed(CsvError),
}

impl fmt::Display for DataFromCsvError {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        write!(f, "{:?}", self)
    }
}

impl std::error::Error for DataFromCsvError {}