ipcap_codegen/
lib.rs

1use crate::names::name_to_enum_name;
2use std::fs;
3
4mod names;
5
6const NAMES_DATA: &str = include_str!("../countries-names.txt");
7const CODES_2_DATA: &str = include_str!("../countries-two.txt");
8const CODES_3_DATA: &str = include_str!("../countries-three.txt");
9const COUNTRIES_TO_CONTINENTS: &str = include_str!("../countries-to-continents.txt");
10const DMA: &str = include_str!("../dma.txt");
11
12trait PushMut<T> {
13    fn add(self, item: T) -> Self;
14}
15
16impl<T> PushMut<T> for Vec<T> {
17    fn add(self, item: T) -> Self {
18        let mut new = self;
19        new.push(item);
20        new
21    }
22}
23
24macro_rules! codes {
25    ($data: expr, $enum_names: expr) => {
26        &$data
27            .split('\n')
28            .enumerate()
29            .map(|(i, code)| format!("Country::{} => \"{}\"", $enum_names[i], code))
30            .collect::<Vec<String>>()
31            .join(",\n")
32    };
33}
34
35macro_rules! codes_reverse {
36    ($data: expr, $enum_names: expr) => {{
37        $data
38            .split('\n')
39            .enumerate()
40            .map(|(i, code)| format!("\"{}\" => Some(Country::{})", code, $enum_names[i]))
41            .collect::<Vec<String>>()
42            .add("_ => None".to_string())
43            .join(",\n")
44    }};
45}
46
47macro_rules! _save_content {
48    ($data: expr, $file_name: expr) => {
49        let out_dir = std::env::var("OUT_DIR").unwrap();
50        fs::write(
51            format!("{out_dir}/{}", $file_name),
52            $data
53        )
54        .unwrap();
55    };
56}
57
58macro_rules! save_content {
59    (result $data: expr, $value: expr, $file_name: expr) => {
60        _save_content!(
61            format!(
62                r#"Ok(match {} {{
63                    {}
64                }}?)"#,
65                $value,
66                $data
67            ),
68            $file_name
69        )
70    };
71
72    ($data: expr, $value: expr, $file_name: expr) => {
73        _save_content!(
74            format!(
75                r#"match {} {{
76                    {}
77                }}"#,
78                $value,
79                $data
80            ),
81            $file_name
82        )
83    };
84}
85
86macro_rules! codes_with_fs_write {
87    (reverse $data: expr, $enum_names: expr, $file_name: expr) => {
88        save_content!(codes_reverse!($data, $enum_names), "value", $file_name);
89    };
90
91    ($data: expr, $enum_names: expr, $file_name: expr) => {
92        save_content!(codes!($data, $enum_names), "self", $file_name);
93    };
94}
95
96pub fn run() {
97    const OFFSET: u8 = 1;
98    let names_by_line = NAMES_DATA.split("\n");
99    let enum_names = names_by_line
100        .clone()
101        .map(name_to_enum_name)
102        .collect::<Vec<String>>();
103
104    let out_dir = std::env::var("OUT_DIR").unwrap();
105
106    let enum_content = &*enum_names.join(", \n\t");
107    fs::write(
108        format!("{out_dir}/countries-enum-values"),
109        format!(
110            r#"
111            #[derive(Debug, Clone, Copy, PartialEq, PartialOrd)]
112            pub enum Country {{
113                {enum_content}
114            }}"#
115        ),
116    )
117    .unwrap();
118
119    codes_with_fs_write!(CODES_2_DATA, enum_names, "countries-codes-2");
120    codes_with_fs_write!(CODES_3_DATA, enum_names, "countries-codes-3");
121    codes_with_fs_write!(reverse CODES_2_DATA, enum_names, "countries-codes-2-reverse");
122    codes_with_fs_write!(reverse CODES_3_DATA, enum_names, "countries-codes-3-reverse");
123
124    let match_pattern = names_by_line
125        .clone()
126        .enumerate()
127        .map(|(i, name)| format!("Country::{} => f.write_str(\"{name}\")", enum_names[i]))
128        .collect::<Vec<String>>()
129        .join(",\n");
130    save_content!(result match_pattern, "self", "countries-to-names");
131
132    let match_pattern = enum_names
133        .iter()
134        .enumerate()
135        .map(|(i, name)| format!("{} => Some(Country::{name})", i as u8 + OFFSET))
136        .collect::<Vec<String>>()
137        .add("_ => None".to_string())
138        .join(",\n");
139    save_content!(match_pattern, "value", "countries-from-buffer");
140
141    let match_pattern = COUNTRIES_TO_CONTINENTS
142        .split('\n')
143        .enumerate()
144        .map(|(i, continent)| {
145            if continent.is_empty() {
146                format!("Country::{} => None", enum_names[i])
147            } else {
148                format!("Country::{} => Some(Continent::{continent})", enum_names[i])
149            }
150        })
151        .collect::<Vec<String>>()
152        .join(",\n");
153    save_content!(match_pattern, "value", "country-to-continent");
154
155    let match_pattern = DMA.split('\n')
156        .map(|dma| {
157            let data: Vec<&str> = dma.split("; ").collect();
158            format!("{} => f.write_str(\"{}\")", data[0], data[1])
159        })
160        .collect::<Vec<String>>()
161        .add("_ => f.write_str(\"Unknown DMA\")".to_string())
162        .join(",\n");
163    save_content!(match_pattern, "value", "dma-code-to-name");
164}