1use fancy_regex::Regex;
9use once_cell::sync::Lazy;
10use std::collections::BTreeMap;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum EdaType {
15 Ad, KiCad, }
18
19struct Rule {
22 logical_name: &'static str,
23 pattern: Regex,
24}
25
26fn rule(logical_name: &'static str, pattern_str: &'static str) -> Rule {
29 Rule {
30 logical_name,
31 pattern: Regex::new(pattern_str).expect("Invalid regex pattern"),
32 }
33}
34
35static AD_RULES: Lazy<Vec<Rule>> = Lazy::new(|| {
37 vec![
38 rule("Gerber_BoardOutlineLayer", "(?i)\\.GM(1|13)$"),
39 rule("Gerber_DocumentLayer", "(?i)\\.GM$"),
40 rule("Gerber_TopLayer", "(?i)\\.GTL$"),
41 rule("Gerber_TopSilkscreenLayer", "(?i)\\.GTO$"),
42 rule("Gerber_TopSolderMaskLayer", "(?i)\\.GTS$"),
43 rule("Gerber_TopPasteMaskLayer", "(?i)\\.GTP$"),
44 rule("Gerber_BottomLayer", "(?i)\\.GBL$"),
45 rule("Gerber_BottomSilkscreenLayer", "(?i)\\.GBO$"),
46 rule("Gerber_BottomSolderMaskLayer", "(?i)\\.GBS$"),
47 rule("Gerber_BottomPasteMaskLayer", "(?i)\\.GBP$"),
48 rule("Gerber_InnerLayer1", "(?i)\\.G1$"),
49 rule("Gerber_InnerLayer2", "(?i)\\.G2$"),
50 rule("Gerber_InnerLayer3", "(?i)\\.G3$"),
51 rule("Gerber_InnerLayer4", "(?i)\\.G4$"),
52 rule("Gerber_InnerLayer5", "(?i)\\.G5$"),
53 rule("Gerber_InnerLayer6", "(?i)\\.G6$"),
54 rule("Drill_NPTH_Through", "(?i).*slot\\s?h?oles.*\\.txt$"),
55 rule("Drill_PTH_Through", "(?i).*round\\s?h?oles.*\\.txt$"),
56 rule("Drill_PTH_Through_Via", "(?i)\\.REP$|.*via.*\\.txt$"),
57 rule("Drill_PTH_Through_GBR", "(?i)\\.GD1$"),
58 rule("Drill_PTH_Through_Via_GBR", "(?i)\\.GG1$"),
59 rule("Drill_Report", "(?i)\\.DRR$"),
60 rule("Gerber_Layer_Drawing_Parameters", "(?i)\\.LDP$"),
61 ]
62});
63
64static KICAD_RULES: Lazy<Vec<Rule>> = Lazy::new(|| {
66 vec![
67 rule("Gerber_BoardOutlineLayer", "(?i).*Edge_Cuts.*"),
68 rule("Gerber_DocumentLayer", "(?i).*GM.*"),
69 rule("Gerber_TopLayer", "(?i).*F_Cu.*"),
70 rule("Gerber_TopSilkscreenLayer", "(?i).*F_Silkscreen.*"),
71 rule("Gerber_TopSolderMaskLayer", "(?i).*F_Mask.*"),
72 rule("Gerber_TopPasteMaskLayer", "(?i).*F_Paste.*"),
73 rule("Gerber_BottomLayer", "(?i).*B_Cu.*"),
74 rule("Gerber_BottomSilkscreenLayer", "(?i).*B_Silkscreen.*"),
75 rule("Gerber_BottomSolderMaskLayer", "(?i).*B_Mask.*"),
76 rule("Gerber_BottomPasteMaskLayer", "(?i).*B_Paste.*"),
77 rule("Gerber_InnerLayer1", "(?i).*In1_Cu.*"),
78 rule("Gerber_InnerLayer2", "(?i).*In2_Cu.*"),
79 rule("Gerber_InnerLayer3", "(?i).*In3_Cu.*"),
80 rule("Gerber_InnerLayer4", "(?i).*In4_Cu.*"),
81 rule("Gerber_InnerLayer5", "(?i).*In5_Cu.*"),
82 rule("Gerber_InnerLayer6", "(?i).*In6_Cu.*"),
83 rule("Drill_PTH_Through_Via", "(?i)^.*\\bVIA\\b.*\\.DRL$"),
85 rule("Drill_NPTH_Through", "(?i)^.*\\bNPTH\\b.*\\.DRL$"),
86 rule("Drill_PTH_Through", "(?i)^(?!.*NPTH).*\\.DRL$"), rule("Drill_PTH_Through_Via_GBR", "(?i)^.*\\bVIA\\b.*\\.GBR$"),
88 rule("Drill_NPTH_Through_GBR", "(?i)^.*\\bNPTH\\b.*\\.GBR$"),
89 rule("Drill_PTH_Through_GBR", "(?i)^[^N]*PTH[^N]*\\.GBR$"),
90 rule("Drill_MAP_GBR", r"(?i).*[-_]drl_map(?:\.GBR)?$"),
92 rule("Gerber_GBR_JOB", "(?i)\\.gbrjob$"),
93 ]
94});
95
96fn get_final_filename(logical_name: &str) -> String {
98 match logical_name {
99 "Gerber_TopSolderMaskLayer" => "Gerber_TopSolderMaskLayer.GTS".to_string(),
100 "Gerber_TopSilkscreenLayer" => "Gerber_TopSilkscreenLayer.GTO".to_string(),
101 "Gerber_TopPasteMaskLayer" => "Gerber_TopPasteMaskLayer.GTP".to_string(),
102 "Gerber_TopLayer" => "Gerber_TopLayer.GTL".to_string(),
103 "Gerber_InnerLayer1" => "Gerber_InnerLayer1.G1".to_string(),
104 "Gerber_InnerLayer2" => "Gerber_InnerLayer2.G2".to_string(),
105 "Gerber_InnerLayer3" => "Gerber_InnerLayer3.G3".to_string(),
106 "Gerber_InnerLayer4" => "Gerber_InnerLayer4.G4".to_string(),
107 "Gerber_InnerLayer5" => "Gerber_InnerLayer5.G5".to_string(),
108 "Gerber_InnerLayer6" => "Gerber_InnerLayer6.G6".to_string(),
109 "Gerber_BottomSolderMaskLayer" => "Gerber_BottomSolderMaskLayer.GBS".to_string(),
110 "Gerber_BottomSilkscreenLayer" => "Gerber_BottomSilkscreenLayer.GBO".to_string(),
111 "Gerber_BottomPasteMaskLayer" => "Gerber_BottomPasteMaskLayer.GBP".to_string(),
112 "Gerber_BottomLayer" => "Gerber_BottomLayer.GBL".to_string(),
113 "Gerber_BoardOutlineLayer" => "Gerber_BoardOutlineLayer.GKO".to_string(),
114 "Drill_PTH_Through" => "Drill_PTH_Through.DRL".to_string(),
115 "Drill_PTH_Through_Via" => "Drill_PTH_Through_Via.DRL".to_string(),
116 "Drill_NPTH_Through" => "Drill_NPTH_Through.DRL".to_string(),
117 "Drill_MAP_GBR" => "Drill_MAP_GBR.GBR".to_string(),
118 "Gerber_GBR_JOB" => "Gerber_GBR_JOB.GBRJOB".to_string(),
119 "Drill_Report" => "Drill_MAP_GBR.DRR".to_string(),
120 "Gerber_Layer_Drawing_Parameters" => "Gerber_GBR_JOB.LDP".to_string(),
121
122 _ => format!("{}.GBR", logical_name),
124 }
125}
126
127pub fn map_filenames(files: &[String], eda_type: EdaType) -> BTreeMap<String, String> {
130 let rules = match eda_type {
131 EdaType::Ad => &AD_RULES,
132 EdaType::KiCad => &KICAD_RULES,
133 };
134
135 let mut rename_map = BTreeMap::new();
136
137 for file in files {
138 let mut new_name = file.clone(); let mut matched = false;
140
141 for rule in rules.iter() {
142 if let Ok(true) = rule.pattern.is_match(file) {
144 new_name = get_final_filename(rule.logical_name);
145 matched = true;
146 break; }
148 }
149 if !matched {
150 new_name = file.clone();
151 }
152
153 rename_map.insert(file.clone(), new_name);
154 }
155
156 rename_map
157}