1use crate::components::{
2 ElectricalComponent, MechanicalComponent, electrical_component, mechanical_component,
3};
4use crate::headers::{LibraryHeader, parse_library_header};
5use nom::Parser;
6use nom::multi::many0;
7
8#[derive(Debug, PartialEq, Clone, Default)]
9pub struct Library {
10 pub header: LibraryHeader,
11 pub electrical_components: Vec<ElectricalComponent>,
12 pub mechanical_components: Vec<MechanicalComponent>,
13}
14
15pub fn parse_library(input: &str) -> Result<Library, nom::Err<nom::error::Error<&str>>> {
18 let (body, header) = parse_library_header.parse(input)?;
20
21 let (remaining, (electrical_components, mechanical_components)) =
23 if body.starts_with(".ELECTRICAL") {
24 let (remaining, (electrical_components, mechanical_components)) =
25 (many0(electrical_component), many0(mechanical_component)).parse(body)?;
26 (remaining, (electrical_components, mechanical_components))
27 } else if body.starts_with(".MECHANICAL") {
28 let (remaining, (mechanical_components, electrical_components)) =
29 (many0(mechanical_component), many0(electrical_component)).parse(body)?;
30 (remaining, (electrical_components, mechanical_components))
31 } else {
32 return Err(nom::Err::Error(nom::error::Error::new(
33 body,
34 nom::error::ErrorKind::Tag,
35 )));
36 };
37
38 let library = Library {
39 header,
40 electrical_components,
41 mechanical_components,
42 };
43
44 if !remaining.is_empty() {
46 Err(nom::Err::Error(nom::error::Error::new(
47 remaining,
48 nom::error::ErrorKind::Tag,
49 )))
50 } else {
51 Ok(library)
52 }
53}
54
55#[cfg(test)]
56mod tests {
57 use super::*;
58 use crate::point::Point;
59 use std::collections::HashMap;
60 #[test]
61 fn test_library() {
62 let input = ".HEADER
63LIBRARY_FILE 3.0 \"Sample File Generator\" 10/22/96.16:41:37 1
64.END_HEADER
65.ELECTRICAL
66cs13_a pn-cap THOU 150.0
670 -55.0 55.0 0.0
680 -55.0 55.0 0.0
69PROP CAPACITANCE 100.0
70PROP TOLERANCE 5.0
71.END_ELECTRICAL
72.ELECTRICAL
73cc1210 pn-cc1210 THOU 67.0
740 -40.0 56.0 0.0
75PROP CAPACITANCE 0.1
76PROP TOLERANCE 5.0
77.END_ELECTRICAL
78.ELECTRICAL
79conn_din24 connector THOU 435.0
800 -1400.0 -500.0 0.0
81.END_ELECTRICAL
82.ELECTRICAL
83dip_14w pn-hs346-dip THOU 200.0
840 350.0 50.0 0.0
85.END_ELECTRICAL
86.ELECTRICAL
87plcc_20 pn-pal16l8-plcc THOU 14.0
880 -200.0 240.0 0.0
890 -240.0 200.0 0.0
90.END_ELECTRICAL";
91 let library = parse_library(input).unwrap();
92 assert_eq!(library.electrical_components.len(), 5);
93
94 let header = LibraryHeader {
95 version: 3,
96 system_id: "Sample File Generator".to_string(),
97 date: "10/22/96.16:41:37".to_string(),
98 file_version: 1,
99 };
100
101 let electrical_components = vec![
102 ElectricalComponent {
103 geometry_name: "cs13_a".to_string(),
104 part_number: "pn-cap".to_string(),
105 units: "THOU".to_string(),
106 height: 150.0,
107 outline: vec![
108 Point {
109 loop_label: 0,
110 x: -55.0,
111 y: 55.0,
112 angle: 0.0,
113 },
114 Point {
115 loop_label: 0,
116 x: -55.0,
117 y: 55.0,
118 angle: 0.0,
119 },
120 ],
121 properties: {
122 let mut props = HashMap::new();
123 props.insert("CAPACITANCE".to_string(), 100.0);
124 props.insert("TOLERANCE".to_string(), 5.0);
125 props
126 },
127 },
128 ElectricalComponent {
129 geometry_name: "cc1210".to_string(),
130 part_number: "pn-cc1210".to_string(),
131 units: "THOU".to_string(),
132 height: 67.0,
133 outline: vec![Point {
134 loop_label: 0,
135 x: -40.0,
136 y: 56.0,
137 angle: 0.0,
138 }],
139 properties: {
140 let mut props = HashMap::new();
141 props.insert("CAPACITANCE".to_string(), 0.1);
142 props.insert("TOLERANCE".to_string(), 5.0);
143 props
144 },
145 },
146 ElectricalComponent {
147 geometry_name: "conn_din24".to_string(),
148 part_number: "connector".to_string(),
149 units: "THOU".to_string(),
150 height: 435.0,
151 outline: vec![Point {
152 loop_label: 0,
153 x: -1400.0,
154 y: -500.0,
155 angle: 0.0,
156 }],
157 properties: HashMap::new(),
158 },
159 ElectricalComponent {
160 geometry_name: "dip_14w".to_string(),
161 part_number: "pn-hs346-dip".to_string(),
162 units: "THOU".to_string(),
163 height: 200.0,
164 outline: vec![Point {
165 loop_label: 0,
166 x: 350.0,
167 y: 50.0,
168 angle: 0.0,
169 }],
170 properties: HashMap::new(),
171 },
172 ElectricalComponent {
173 geometry_name: "plcc_20".to_string(),
174 part_number: "pn-pal16l8-plcc".to_string(),
175 units: "THOU".to_string(),
176 height: 14.0,
177 outline: vec![
178 Point {
179 loop_label: 0,
180 x: -200.0,
181 y: 240.0,
182 angle: 0.0,
183 },
184 Point {
185 loop_label: 0,
186 x: -240.0,
187 y: 200.0,
188 angle: 0.0,
189 },
190 ],
191 properties: HashMap::new(),
192 },
193 ];
194
195 let expected_library = Library {
196 header,
197 electrical_components,
198 mechanical_components: vec![],
199 };
200
201 assert_eq!(library, expected_library);
202 }
203}