1mod arc;
6mod bezier;
7mod bus;
8mod bus_entry;
9mod common;
10mod component;
11mod designator;
12mod ellipse;
13mod image;
14mod implementation;
15mod junction;
16mod label;
17mod line;
18mod netlabel;
19mod no_erc;
20mod parameter;
21mod pie;
22mod pin;
23mod pin_new; mod polygon;
25mod polyline;
26mod port;
27mod power;
28mod primitive;
29mod rectangle;
30mod sheet;
31mod symbol;
32mod text_frame;
33mod warning_sign;
34mod wire;
35
36pub use arc::{SchArc, SchEllipticalArc};
37pub use bezier::*;
38pub use bus::*;
39pub use bus_entry::*;
40pub use common::*;
41pub use component::*;
42pub use designator::*;
43pub use ellipse::*;
44pub use image::*;
45pub use implementation::*;
46pub use junction::*;
47pub use label::*;
48pub use line::*;
49pub use netlabel::*;
50pub use no_erc::*;
51pub use parameter::*;
52pub use pie::*;
53pub use pin::*;
54pub use polygon::*;
55pub use polyline::*;
56pub use port::*;
57pub use power::*;
58pub use primitive::*;
59pub use rectangle::*;
60pub use sheet::*;
61pub use symbol::*;
62pub use text_frame::*;
63pub use warning_sign::*;
64pub use wire::*;
65
66#[cfg(test)]
67mod tests;
68
69use crate::dump::{DumpTree, TreeBuilder, fmt_angle, fmt_bool, fmt_coord, fmt_point};
71
72impl DumpTree for SchComponent {
73 fn dump(&self, tree: &mut TreeBuilder) {
74 let mut props = vec![("lib_reference", self.lib_reference.clone())];
75 if !self.component_description.is_empty() {
76 props.push(("description", self.component_description.clone()));
77 }
78 props.push((
79 "location",
80 fmt_point(self.graphical.location_x, self.graphical.location_y),
81 ));
82 props.push(("parts", format!("{}", self.part_count)));
83 tree.add_leaf("Component", &props);
84 }
85}
86
87impl DumpTree for SchPin {
88 fn dump(&self, tree: &mut TreeBuilder) {
89 let mut props = vec![];
90 if !self.designator.is_empty() {
91 props.push(("designator", self.designator.clone()));
92 }
93 if !self.name.is_empty() {
94 props.push(("name", self.name.clone()));
95 }
96 props.push((
97 "location",
98 fmt_point(self.graphical.location_x, self.graphical.location_y),
99 ));
100 props.push(("length", fmt_coord(self.pin_length)));
101 props.push(("electrical", format!("{:?}", self.electrical)));
102 if self.is_hidden() {
103 props.push(("hidden", "yes".to_string()));
104 }
105 tree.add_leaf("Pin", &props);
106 }
107}
108
109impl DumpTree for SchSymbol {
110 fn dump(&self, tree: &mut TreeBuilder) {
111 let mut props = vec![(
112 "location",
113 fmt_point(self.graphical.location_x, self.graphical.location_y),
114 )];
115 if self.scale_factor != 1.0 {
116 props.push(("scale", format!("{:.2}", self.scale_factor)));
117 }
118 if self.is_mirrored {
119 props.push(("mirrored", "yes".to_string()));
120 }
121 tree.add_leaf("Symbol", &props);
122 }
123}
124
125impl DumpTree for SchLabel {
126 fn dump(&self, tree: &mut TreeBuilder) {
127 let mut props = vec![
128 ("text", format!("\"{}\"", self.text)),
129 (
130 "location",
131 fmt_point(self.graphical.location_x, self.graphical.location_y),
132 ),
133 ];
134 if self.is_hidden {
135 props.push(("hidden", "yes".to_string()));
136 }
137 tree.add_leaf("Label", &props);
138 }
139}
140
141impl DumpTree for SchBezier {
142 fn dump(&self, tree: &mut TreeBuilder) {
143 tree.add_leaf(
144 "Bezier",
145 &[("control_points", format!("{}", self.vertices.len()))],
146 );
147 }
148}
149
150impl DumpTree for SchPolyline {
151 fn dump(&self, tree: &mut TreeBuilder) {
152 tree.add_leaf(
153 "Polyline",
154 &[
155 ("vertices", format!("{}", self.vertices.len())),
156 ("style", format!("{:?}", self.line_style)),
157 ],
158 );
159 }
160}
161
162impl DumpTree for SchPolygon {
163 fn dump(&self, tree: &mut TreeBuilder) {
164 let mut props = vec![("vertices", format!("{}", self.vertices.len()))];
165 if self.is_solid {
166 props.push(("filled", "yes".to_string()));
167 }
168 tree.add_leaf("Polygon", &props);
169 }
170}
171
172impl DumpTree for SchEllipse {
173 fn dump(&self, tree: &mut TreeBuilder) {
174 let mut props = vec![
175 (
176 "center",
177 fmt_point(self.graphical.location_x, self.graphical.location_y),
178 ),
179 (
180 "radius",
181 format!(
182 "{} × {}",
183 fmt_coord(self.radius_x),
184 fmt_coord(self.radius_y)
185 ),
186 ),
187 ];
188 if self.is_solid {
189 props.push(("filled", "yes".to_string()));
190 }
191 tree.add_leaf("Ellipse", &props);
192 }
193}
194
195impl DumpTree for SchPie {
196 fn dump(&self, tree: &mut TreeBuilder) {
197 let mut props = vec![
198 (
199 "center",
200 fmt_point(self.graphical.location_x, self.graphical.location_y),
201 ),
202 (
203 "radii",
204 format!(
205 "{} × {}",
206 fmt_coord(self.radius),
207 fmt_coord(if self.secondary_radius == 0 {
208 self.radius
209 } else {
210 self.secondary_radius
211 })
212 ),
213 ),
214 (
215 "angles",
216 format!(
217 "{} → {}",
218 fmt_angle(self.start_angle),
219 fmt_angle(self.end_angle)
220 ),
221 ),
222 ];
223 if self.is_solid {
224 props.push(("filled", "yes".to_string()));
225 }
226 tree.add_leaf("Pie", &props);
227 }
228}
229
230impl DumpTree for SchEllipticalArc {
231 fn dump(&self, tree: &mut TreeBuilder) {
232 tree.add_leaf(
233 "EllipticalArc",
234 &[
235 (
236 "center",
237 fmt_point(self.graphical.location_x, self.graphical.location_y),
238 ),
239 (
240 "radii",
241 format!(
242 "{} × {}",
243 fmt_coord(self.radius),
244 fmt_coord(self.secondary_radius)
245 ),
246 ),
247 (
248 "angles",
249 format!(
250 "{} → {}",
251 fmt_angle(self.start_angle),
252 fmt_angle(self.end_angle)
253 ),
254 ),
255 ],
256 );
257 }
258}
259
260impl DumpTree for SchArc {
261 fn dump(&self, tree: &mut TreeBuilder) {
262 tree.add_leaf(
263 "Arc",
264 &[
265 (
266 "center",
267 fmt_point(self.graphical.location_x, self.graphical.location_y),
268 ),
269 ("radius", fmt_coord(self.radius)),
270 (
271 "angles",
272 format!(
273 "{} → {}",
274 fmt_angle(self.start_angle),
275 fmt_angle(self.end_angle)
276 ),
277 ),
278 ],
279 );
280 }
281}
282
283impl DumpTree for SchLine {
284 fn dump(&self, tree: &mut TreeBuilder) {
285 tree.add_leaf(
286 "Line",
287 &[
288 (
289 "start",
290 fmt_point(self.graphical.location_x, self.graphical.location_y),
291 ),
292 ("end", fmt_point(self.corner_x, self.corner_y)),
293 ],
294 );
295 }
296}
297
298impl DumpTree for SchRectangle {
299 fn dump(&self, tree: &mut TreeBuilder) {
300 let mut props = vec![
301 (
302 "corner1",
303 fmt_point(self.graphical.location_x, self.graphical.location_y),
304 ),
305 ("corner2", fmt_point(self.corner_x, self.corner_y)),
306 ];
307 if self.is_solid {
308 props.push(("filled", "yes".to_string()));
309 }
310 tree.add_leaf("Rectangle", &props);
311 }
312}
313
314impl DumpTree for SchPowerObject {
315 fn dump(&self, tree: &mut TreeBuilder) {
316 tree.add_leaf(
317 "PowerObject",
318 &[
319 ("net", format!("\"{}\"", self.text)),
320 ("style", format!("{:?}", self.style)),
321 (
322 "location",
323 fmt_point(self.graphical.location_x, self.graphical.location_y),
324 ),
325 ],
326 );
327 }
328}
329
330impl DumpTree for SchPort {
331 fn dump(&self, tree: &mut TreeBuilder) {
332 let mut props = vec![
333 ("name", format!("\"{}\"", self.name)),
334 (
335 "location",
336 fmt_point(self.graphical.location_x, self.graphical.location_y),
337 ),
338 ];
339 props.push(("io_type", format!("{:?}", self.io_type)));
340 props.push(("style", format!("{:?}", self.style)));
341 if self.width > 0 || self.height > 0 {
342 props.push(("size", format!("{}x{}", self.width, self.height)));
343 }
344 if !self.harness_type.is_empty() {
345 props.push(("harness", self.harness_type.clone()));
346 }
347 tree.add_leaf("Port", &props);
348 }
349}
350
351impl DumpTree for SchNetLabel {
352 fn dump(&self, tree: &mut TreeBuilder) {
353 tree.add_leaf(
354 "NetLabel",
355 &[
356 ("net", format!("\"{}\"", self.label.text)),
357 (
358 "location",
359 fmt_point(
360 self.label.graphical.location_x,
361 self.label.graphical.location_y,
362 ),
363 ),
364 ],
365 );
366 }
367}
368
369impl DumpTree for SchWire {
370 fn dump(&self, tree: &mut TreeBuilder) {
371 let vertices = &self.vertices;
372 if vertices.len() == 2 {
373 tree.add_leaf(
374 "Wire",
375 &[
376 ("start", fmt_point(vertices[0].0, vertices[0].1)),
377 ("end", fmt_point(vertices[1].0, vertices[1].1)),
378 ],
379 );
380 } else {
381 tree.add_leaf(
382 "Wire",
383 &[("segments", format!("{}", vertices.len().saturating_sub(1)))],
384 );
385 }
386 }
387}
388
389impl DumpTree for SchTextFrame {
390 fn dump(&self, tree: &mut TreeBuilder) {
391 tree.add_leaf(
392 "TextFrame",
393 &[
394 ("text", format!("\"{}\"", self.text)),
395 (
396 "corner1",
397 fmt_point(self.graphical.location_x, self.graphical.location_y),
398 ),
399 ("corner2", fmt_point(self.corner_x, self.corner_y)),
400 ],
401 );
402 }
403}
404
405impl DumpTree for SchTextFrameVariant {
406 fn dump(&self, tree: &mut TreeBuilder) {
407 tree.add_leaf(
408 "TextFrameVariant",
409 &[
410 ("text", format!("\"{}\"", self.text)),
411 (
412 "corner1",
413 fmt_point(self.graphical.location_x, self.graphical.location_y),
414 ),
415 ("corner2", fmt_point(self.corner_x, self.corner_y)),
416 ],
417 );
418 }
419}
420
421impl DumpTree for SchJunction {
422 fn dump(&self, tree: &mut TreeBuilder) {
423 tree.add_leaf(
424 "Junction",
425 &[(
426 "location",
427 fmt_point(self.graphical.location_x, self.graphical.location_y),
428 )],
429 );
430 }
431}
432
433impl DumpTree for SchImage {
434 fn dump(&self, tree: &mut TreeBuilder) {
435 let mut props = vec![
436 (
437 "corner1",
438 fmt_point(self.graphical.location_x, self.graphical.location_y),
439 ),
440 ("corner2", fmt_point(self.corner_x, self.corner_y)),
441 ];
442 if !self.filename.is_empty() {
443 props.push(("file", self.filename.clone()));
444 }
445 props.push(("embedded", fmt_bool(self.embed_image)));
446 tree.add_leaf("Image", &props);
447 }
448}
449
450impl DumpTree for SchSheetHeader {
451 fn dump(&self, tree: &mut TreeBuilder) {
452 tree.add_leaf(
453 "SheetHeader",
454 &[
455 ("fonts", format!("{}", self.font_id_count)),
456 ("sheet_size", format!("{}", self.sheet_size)),
457 ],
458 );
459 }
460}
461
462impl DumpTree for SchParameter {
463 fn dump(&self, tree: &mut TreeBuilder) {
464 tree.add_leaf(
465 "Parameter",
466 &[
467 ("name", self.name.clone()),
468 ("value", format!("\"{}\"", self.label.text)),
469 (
470 "location",
471 fmt_point(
472 self.label.graphical.location_x,
473 self.label.graphical.location_y,
474 ),
475 ),
476 ],
477 );
478 }
479}
480
481impl DumpTree for SchWarningSign {
482 fn dump(&self, tree: &mut TreeBuilder) {
483 let mut props = vec![(
484 "location",
485 fmt_point(self.graphical.location_x, self.graphical.location_y),
486 )];
487 if !self.name.is_empty() {
488 props.push(("name", self.name.clone()));
489 }
490 tree.add_leaf("WarningSign", &props);
491 }
492}
493
494impl DumpTree for SchDesignator {
495 fn dump(&self, tree: &mut TreeBuilder) {
496 tree.add_leaf(
497 "Designator",
498 &[
499 ("name", self.param.name.clone()),
500 ("value", format!("\"{}\"", self.param.label.text)),
501 (
502 "location",
503 fmt_point(
504 self.param.label.graphical.location_x,
505 self.param.label.graphical.location_y,
506 ),
507 ),
508 ],
509 );
510 }
511}
512
513impl DumpTree for SchImplementationList {
514 fn dump(&self, tree: &mut TreeBuilder) {
515 tree.add_leaf(
516 "ImplementationList",
517 &[("owner_index", format!("{}", self.base.owner_index))],
518 );
519 }
520}
521
522impl DumpTree for SchImplementation {
523 fn dump(&self, tree: &mut TreeBuilder) {
524 let mut props = vec![
525 ("model_name", self.model_name.clone()),
526 ("model_type", self.model_type.clone()),
527 ];
528 if self.is_current {
529 props.push(("current", "yes".to_string()));
530 }
531 tree.add_leaf("Implementation", &props);
532 }
533}
534
535impl DumpTree for SchMapDefinerList {
536 fn dump(&self, tree: &mut TreeBuilder) {
537 tree.add_leaf(
538 "MapDefinerList",
539 &[("owner_index", format!("{}", self.base.owner_index))],
540 );
541 }
542}
543
544impl DumpTree for SchMapDefiner {
545 fn dump(&self, tree: &mut TreeBuilder) {
546 tree.add_leaf(
547 "MapDefiner",
548 &[
549 ("interface", self.designator_interface.clone()),
550 (
551 "impl_count",
552 format!("{}", self.designator_implementation.len()),
553 ),
554 ],
555 );
556 }
557}
558
559impl DumpTree for SchImplementationParameters {
560 fn dump(&self, tree: &mut TreeBuilder) {
561 tree.add_leaf(
562 "ImplementationParameters",
563 &[("owner_index", format!("{}", self.base.owner_index))],
564 );
565 }
566}
567
568impl DumpTree for SchBus {
569 fn dump(&self, tree: &mut TreeBuilder) {
570 let vertices = &self.vertices;
571 if vertices.len() == 2 {
572 tree.add_leaf(
573 "Bus",
574 &[
575 ("start", fmt_point(vertices[0].0, vertices[0].1)),
576 ("end", fmt_point(vertices[1].0, vertices[1].1)),
577 ],
578 );
579 } else {
580 tree.add_leaf(
581 "Bus",
582 &[("segments", format!("{}", vertices.len().saturating_sub(1)))],
583 );
584 }
585 }
586}
587
588impl DumpTree for SchBusEntry {
589 fn dump(&self, tree: &mut TreeBuilder) {
590 let (bus_x, bus_y) = self.bus_point();
591 let (wire_x, wire_y) = self.wire_point();
592 tree.add_leaf(
593 "BusEntry",
594 &[
595 ("bus_point", fmt_point(bus_x, bus_y)),
596 ("wire_point", fmt_point(wire_x, wire_y)),
597 ],
598 );
599 }
600}
601
602impl DumpTree for SchNoErc {
603 fn dump(&self, tree: &mut TreeBuilder) {
604 let mut props = vec![(
605 "location",
606 fmt_point(self.graphical.location_x, self.graphical.location_y),
607 )];
608 if self.is_active {
609 props.push(("active", "yes".to_string()));
610 }
611 tree.add_leaf("NoERC", &props);
612 }
613}
614
615impl DumpTree for SchRecord {
616 fn dump(&self, tree: &mut TreeBuilder) {
617 match self {
618 SchRecord::Component(r) => r.dump(tree),
619 SchRecord::Pin(r) => r.dump(tree),
620 SchRecord::Symbol(r) => r.dump(tree),
621 SchRecord::Label(r) => r.dump(tree),
622 SchRecord::Bezier(r) => r.dump(tree),
623 SchRecord::Polyline(r) => r.dump(tree),
624 SchRecord::Polygon(r) => r.dump(tree),
625 SchRecord::Ellipse(r) => r.dump(tree),
626 SchRecord::Pie(r) => r.dump(tree),
627 SchRecord::EllipticalArc(r) => r.dump(tree),
628 SchRecord::Arc(r) => r.dump(tree),
629 SchRecord::Line(r) => r.dump(tree),
630 SchRecord::Rectangle(r) => r.dump(tree),
631 SchRecord::PowerObject(r) => r.dump(tree),
632 SchRecord::Port(r) => r.dump(tree),
633 SchRecord::NoErc(r) => r.dump(tree),
634 SchRecord::NetLabel(r) => r.dump(tree),
635 SchRecord::Bus(r) => r.dump(tree),
636 SchRecord::Wire(r) => r.dump(tree),
637 SchRecord::TextFrame(r) => r.dump(tree),
638 SchRecord::TextFrameVariant(r) => r.dump(tree),
639 SchRecord::Junction(r) => r.dump(tree),
640 SchRecord::Image(r) => r.dump(tree),
641 SchRecord::SheetHeader(r) => r.dump(tree),
642 SchRecord::Designator(r) => r.dump(tree),
643 SchRecord::BusEntry(r) => r.dump(tree),
644 SchRecord::Parameter(r) => r.dump(tree),
645 SchRecord::WarningSign(r) => r.dump(tree),
646 SchRecord::ImplementationList(r) => r.dump(tree),
647 SchRecord::Implementation(r) => r.dump(tree),
648 SchRecord::MapDefinerList(r) => r.dump(tree),
649 SchRecord::MapDefiner(r) => r.dump(tree),
650 SchRecord::ImplementationParameters(r) => r.dump(tree),
651 SchRecord::Unknown { record_id, params } => {
652 tree.add_leaf(
653 "Unknown",
654 &[
655 ("record_id", format!("{}", record_id)),
656 ("params", format!("{} fields", params.len())),
657 ],
658 );
659 }
660 }
661 }
662}