1use nom::branch::alt;
2use nom::sequence::{delimited, terminated};
3
4use crate::primitives::{quote_string, ws};
5use crate::{parse_section, ws_separated};
6use nom::Err::Error;
7use nom::Parser;
8use nom::bytes::complete::{is_not, tag};
9use nom::character::complete::not_line_ending;
10use nom::error::ErrorKind;
11use nom::{IResult, error};
12
13#[derive(PartialEq, Debug, Clone, Default, PartialOrd)]
14pub struct LibraryHeader {
15 pub version: u32, pub system_id: String,
17 pub date: String, pub file_version: u32,
19}
20
21#[derive(Debug, PartialEq, Clone, Default, PartialOrd)]
22pub struct BoardPanelHeader {
23 pub file_type: String, pub version: u32, pub system_id: String,
26 pub date: String, pub file_version: u32,
28 pub board_name: String,
29 pub units: String,
30}
31
32fn header_metadata(input: &str) -> IResult<&str, (String, u32, String, String, u32)> {
34 let (remaining, (file_type, version, system_id, date, file_version)) = (
35 ws(alt((
36 tag("PANEL_FILE"),
37 tag("LIBRARY_FILE"),
38 tag("BOARD_FILE"),
39 ))), ws(terminated(tag("3"), tag(".0"))), ws(alt((quote_string, is_not(" ")))), ws(is_not(" ")), ws(not_line_ending), )
45 .parse(input)?;
46
47 Ok((
48 remaining,
49 (
50 file_type.to_string(),
51 version.parse::<u32>().unwrap(),
52 system_id.to_string(),
53 date.to_string(),
54 file_version.parse::<u32>().unwrap(),
55 ),
56 ))
57}
58
59pub fn parse_board_or_panel_header(input: &str) -> IResult<&str, BoardPanelHeader> {
75 let (remaining, (metadata, (board_name, units))) = parse_section!(
76 "HEADER",
77 (
78 header_metadata,
79 ws_separated!((is_not(" "), alt((tag("THOU"), tag("MM"))))),
80 )
81 )
82 .parse(input)?;
83
84 let (file_type, version, system_id, date, file_version) = metadata;
85
86 let header = BoardPanelHeader {
87 file_type,
88 version,
89 system_id,
90 date,
91 file_version,
92 board_name: board_name.to_string(),
93 units: units.to_string(),
94 };
95 Ok((remaining, header))
96}
97
98pub fn parse_library_header(input: &str) -> IResult<&str, LibraryHeader> {
114 let (remaining, (file_type, version, system_id, date, file_version)) =
115 parse_section!("HEADER", header_metadata).parse(input)?;
116
117 if file_type != "LIBRARY_FILE" {
118 return Err(Error(error::Error::new(input, ErrorKind::Tag)));
119 }
120
121 let header = LibraryHeader {
122 version,
123 system_id,
124 date,
125 file_version,
126 };
127 Ok((remaining, header))
128}
129
130#[cfg(test)]
131mod tests {
132 use super::*;
133 #[test]
134 fn test_parse_header_metadata() {
135 let input = "BOARD_FILE 3.0 \"Sample File Generator\" 10/22/96.16:02:44 1\n";
136 let (remaining, (file_type, version, system_id, date, file_version)) =
137 header_metadata(input).unwrap();
138 assert_eq!(remaining, "");
139 assert_eq!(file_type, "BOARD_FILE");
140 assert_eq!(version, 3);
141 assert_eq!(system_id, "Sample File Generator");
142 assert_eq!(date, "10/22/96.16:02:44");
143 assert_eq!(file_version, 1);
144 }
145
146 #[test]
147 fn test_parse_board_header() {
148 let input = ".HEADER
149BOARD_FILE 3.0 \"Sample File Generator\" 10/22/96.16:02:44 1
150sample_board THOU
151.END_HEADER\n other nonsense";
152
153 let (remaining, header) = parse_board_or_panel_header(input).unwrap();
154 assert_eq!(remaining, "other nonsense");
155 let example = BoardPanelHeader {
156 file_type: "BOARD_FILE".to_string(),
157 version: 3,
158 system_id: "Sample File Generator".to_string(),
159 date: "10/22/96.16:02:44".to_string(),
160 file_version: 1,
161 board_name: "sample_board".to_string(),
162 units: "THOU".to_string(),
163 };
164
165 assert_eq!(header.file_type, example.file_type);
166 }
167
168 #[test]
169 fn test_parse_board_header_isol() {
170 let input = ".HEADER
171BOARD_FILE 3.0 \"allegro 16.2\" 2010/04/27.15:29:26 1
172ISOL_mk.brd THOU
173.END_HEADER";
174
175 let (remaining, header) = parse_board_or_panel_header(input).unwrap();
176
177 let example = BoardPanelHeader {
178 file_type: "BOARD_FILE".to_string(),
179 version: 3,
180 system_id: "allegro 16.2".to_string(),
181 date: "2010/04/27.15:29:26".to_string(),
182 file_version: 1,
183 board_name: "ISOL_mk.brd".to_string(),
184 units: "THOU".to_string(),
185 };
186 assert_eq!(remaining, "");
187 assert_eq!(header, example);
188 }
189
190 #[test]
191 fn test_parse_board_header_beaglebone() {
192 let input = ".HEADER
193BOARD_FILE 3.0 allegro_16.5 2012/12/10.15:43:34 1
194BEAGLEBONE_REVC2.brd THOU
195.END_HEADER";
196
197 let (remaining, header) = parse_board_or_panel_header(input).unwrap();
198
199 let example = BoardPanelHeader {
200 file_type: "BOARD_FILE".to_string(),
201 version: 3,
202 system_id: "allegro_16.5".to_string(),
203 date: "2012/12/10.15:43:34".to_string(),
204 file_version: 1,
205 board_name: "BEAGLEBONE_REVC2.brd".to_string(),
206 units: "THOU".to_string(),
207 };
208 assert_eq!(remaining, "");
209 assert_eq!(header, example);
210 }
211 #[test]
212 fn test_parse_library_header() {
213 let input = ".HEADER
214LIBRARY_FILE 3.0 \"Sample File Generator\" 10/22/96.16:41:37 1
215.END_HEADER\n";
216
217 let (remaining, header) = parse_library_header(input).unwrap();
218 assert_eq!(remaining, "");
219 assert_eq!(header.version, 3);
220 assert_eq!(header.system_id, "Sample File Generator");
221 assert_eq!(header.date, "10/22/96.16:41:37");
222 assert_eq!(header.file_version, 1);
223 }
224
225 #[test]
226 fn test_library_header_isol() {
227 let input = ".HEADER
228LIBRARY_FILE 3.0 \"allegro 16.2\" 2010/04/27.15:29:26 1
229.END_HEADER";
230 let (remaining, header) = parse_library_header(input).unwrap();
231
232 let example = LibraryHeader {
233 version: 3,
234 system_id: "allegro 16.2".to_string(),
235 date: "2010/04/27.15:29:26".to_string(),
236 file_version: 1,
237 };
238 assert_eq!(remaining, "");
239 assert_eq!(header, example);
240 }
241
242 #[test]
243 fn test_library_header_beaglebone() {
244 let input = ".HEADER
245LIBRARY_FILE 3.0 allegro_16.5 2012/12/10.15:43:34 1
246.END_HEADER";
247 let (remaining, header) = parse_library_header(input).unwrap();
248
249 let example = LibraryHeader {
250 version: 3,
251 system_id: "allegro_16.5".to_string(),
252 date: "2012/12/10.15:43:34".to_string(),
253 file_version: 1,
254 };
255 assert_eq!(remaining, "");
256 assert_eq!(header, example);
257 }
258}