1use std::io::Write;
4use strum_macros::{IntoStaticStr, VariantArray, VariantNames};
5use uuid::Uuid;
6
7use crate::errors::GerberResult;
8use crate::traits::PartialGerberCode;
9use crate::GerberDate;
10
11#[derive(Debug, Clone, PartialEq, Eq, Hash)]
12pub enum Ident {
13 Uuid(Uuid),
15 Name(String),
16}
17
18impl<W: Write> PartialGerberCode<W> for Ident {
19 fn serialize_partial(&self, writer: &mut W) -> GerberResult<()> {
20 match self {
21 Ident::Uuid(guid) => {
22 write!(writer, "{}", guid)?;
23 }
24 Ident::Name(value) => {
25 write!(writer, "{}", value)?;
26 }
27 }
28
29 Ok(())
30 }
31}
32
33#[derive(Debug, Clone, PartialEq, Eq, Hash)]
36pub enum FileAttribute {
37 Part(Part),
39 FileFunction(FileFunction),
41 FilePolarity(FilePolarity),
43 SameCoordinates(Option<Ident>),
45 CreationDate(GerberDate),
47 GenerationSoftware(GenerationSoftware),
49 ProjectId {
51 id: String,
52 uuid: Uuid,
53 revision: String,
54 },
55 Md5(String),
57 UserDefined {
58 name: String,
59 values: Vec<String>,
60 },
61}
62
63impl<W: Write> PartialGerberCode<W> for FileAttribute {
64 fn serialize_partial(&self, writer: &mut W) -> GerberResult<()> {
65 match self {
66 FileAttribute::Part(ref part) => {
67 write!(writer, ".Part,")?;
68 part.serialize_partial(writer)?;
69 }
70 FileAttribute::FileFunction(ref function) => {
71 write!(writer, ".FileFunction,")?;
72 match function {
73 FileFunction::Copper {
74 ref layer,
75 ref pos,
76 ref copper_type,
77 } => {
78 write!(writer, "Copper,L{},", layer)?;
79 pos.serialize_partial(writer)?;
80 if let Some(ref t) = *copper_type {
81 write!(writer, ",")?;
82 t.serialize_partial(writer)?;
83 }
84 }
85 FileFunction::Plated {
86 from_layer,
87 to_layer,
88 drill,
89 label,
90 } => {
91 write!(writer, "Plated,{},{},", from_layer, to_layer)?;
92 drill.serialize_partial(writer)?;
93 if let Some(ref l) = label {
94 write!(writer, ",")?;
95 l.serialize_partial(writer)?;
96 }
97 }
98 FileFunction::NonPlated {
99 from_layer,
100 to_layer,
101 drill,
102 label,
103 } => {
104 write!(writer, "NonPlated,{},{},", from_layer, to_layer)?;
105 drill.serialize_partial(writer)?;
106 if let Some(ref l) = label {
107 write!(writer, ",")?;
108 l.serialize_partial(writer)?;
109 }
110 }
111 FileFunction::Profile(ref plating) => {
112 write!(writer, "Profile")?;
113 if let Some(ref plating) = plating {
114 write!(writer, ",")?;
115 plating.serialize_partial(writer)?;
116 }
117 }
118 FileFunction::KeepOut(ref pos) => {
119 write!(writer, "Keepout,")?;
120 pos.serialize_partial(writer)?;
121 }
122 FileFunction::SolderMask { ref pos, ref index } => {
123 write!(writer, "Soldermask,")?;
124 pos.serialize_partial(writer)?;
125 if let Some(ref i) = index {
126 write!(writer, ",{}", *i)?;
127 }
128 }
129 FileFunction::Legend { ref pos, ref index } => {
130 write!(writer, "Legend,")?;
131 pos.serialize_partial(writer)?;
132 if let Some(ref i) = index {
133 write!(writer, ",{}", *i)?;
134 }
135 }
136 FileFunction::Component { layer, pos } => {
137 write!(writer, "Component,L{},", layer)?;
138 pos.serialize_partial(writer)?;
139 }
140 FileFunction::Paste(pos) => {
141 write!(writer, "Paste,")?;
142 pos.serialize_partial(writer)?;
143 }
144 FileFunction::Glue(pos) => {
145 write!(writer, "Glue,")?;
146 pos.serialize_partial(writer)?;
147 }
148 FileFunction::CarbonMask { pos, index } => {
149 write!(writer, "Carbonmask,")?;
150 pos.serialize_partial(writer)?;
151 if let Some(ref i) = index {
152 write!(writer, ",{}", *i)?;
153 }
154 }
155 FileFunction::GoldMask { pos, index } => {
156 write!(writer, "Goldmask,")?;
157 pos.serialize_partial(writer)?;
158 if let Some(ref i) = index {
159 write!(writer, ",{}", *i)?;
160 }
161 }
162 FileFunction::HeatsinkMask { pos, index } => {
163 write!(writer, "Heatsinkmask,")?;
164 pos.serialize_partial(writer)?;
165 if let Some(ref i) = index {
166 write!(writer, ",{}", *i)?;
167 }
168 }
169 FileFunction::PeelableMask { pos, index } => {
170 write!(writer, "Peelablemask,")?;
171 pos.serialize_partial(writer)?;
172 if let Some(ref i) = index {
173 write!(writer, ",{}", *i)?;
174 }
175 }
176 FileFunction::SilverMask { pos, index } => {
177 write!(writer, "Silvermask,")?;
178 pos.serialize_partial(writer)?;
179 if let Some(ref i) = index {
180 write!(writer, ",{}", *i)?;
181 }
182 }
183 FileFunction::TinMask { pos, index } => {
184 write!(writer, "Tinmask,")?;
185 pos.serialize_partial(writer)?;
186 if let Some(ref i) = index {
187 write!(writer, ",{}", *i)?;
188 }
189 }
190 FileFunction::DepthRoute(pos) => {
191 write!(writer, "Depthrout,")?;
192 pos.serialize_partial(writer)?;
193 }
194 FileFunction::VCut(pos) => {
195 write!(writer, "Vcut")?;
196 if let Some(pos) = pos {
197 write!(writer, ",")?;
198 pos.serialize_partial(writer)?;
199 }
200 }
201 FileFunction::ViaFill => {
202 write!(writer, "Viafill")?;
203 }
204 FileFunction::Pads(pos) => {
205 write!(writer, "Pads,")?;
206 pos.serialize_partial(writer)?;
207 }
208 FileFunction::Other(value) => {
209 write!(writer, "Other,{}", value)?;
210 }
211
212 FileFunction::DrillMap => {
214 write!(writer, "Drillmap")?;
215 }
216 FileFunction::FabricationDrawing => {
217 write!(writer, "FabricationDrawing")?;
218 }
219 FileFunction::VCutMap => {
220 write!(writer, "Vcutmap")?;
221 }
222 FileFunction::AssemblyDrawing(pos) => {
223 write!(writer, "AssemblyDrawing,")?;
224 pos.serialize_partial(writer)?;
225 }
226 FileFunction::ArrayDrawing => {
227 write!(writer, "ArrayDrawing")?;
228 }
229 FileFunction::OtherDrawing(value) => {
230 write!(writer, "OtherDrawing,{}", value)?;
231 }
232 }
233 }
234 FileAttribute::FilePolarity(ref p) => {
235 write!(writer, ".FilePolarity,")?;
236 p.serialize_partial(writer)?;
237 }
238 FileAttribute::SameCoordinates(ident) => {
239 write!(writer, ".SameCoordinates")?;
240 if let Some(ident) = ident {
241 write!(writer, ",")?;
242 ident.serialize_partial(writer)?;
243 }
244 }
245 FileAttribute::CreationDate(date) => {
246 write!(writer, ".CreationDate,{}", date.to_rfc3339())?;
247 }
248 FileAttribute::GenerationSoftware(ref gs) => {
249 write!(writer, ".GenerationSoftware,")?;
250 gs.serialize_partial(writer)?;
251 }
252 FileAttribute::ProjectId { id, uuid, revision } => {
253 write!(writer, ".ProjectId,{},{},{}", id, uuid, revision)?;
254 }
255 FileAttribute::Md5(ref hash) => write!(writer, ".MD5,{}", hash)?,
256 FileAttribute::UserDefined { name, values } => {
257 write!(writer, "{}", name)?;
258 for value in values {
259 write!(writer, ",{}", value)?;
260 }
261 }
262 };
263 Ok(())
264 }
265}
266
267#[derive(Debug, Copy, Clone, PartialEq, Hash, IntoStaticStr, VariantNames, VariantArray)]
269#[strum(serialize_all = "UPPERCASE")]
270pub enum TextMode {
271 #[strum(serialize = "B")]
272 BarCode,
273 #[strum(serialize = "C")]
274 Characters,
275}
276
277impl_partial_gerber_code_via_strum!(TextMode);
278
279#[derive(Debug, Copy, Clone, PartialEq, Hash, IntoStaticStr, VariantNames, VariantArray)]
281#[strum(serialize_all = "UPPERCASE")]
282pub enum TextMirroring {
283 #[strum(serialize = "R")]
284 Readable,
285 #[strum(serialize = "M")]
286 Mirrored,
287}
288
289impl_partial_gerber_code_via_strum!(TextMirroring);
290
291#[derive(Debug, Clone, PartialEq)]
294pub enum ApertureAttribute {
295 ApertureFunction(ApertureFunction),
296 DrillTolerance {
297 plus: f64,
298 minus: f64,
299 },
300 FlashText {
301 text: String,
302 mode: TextMode,
303 mirroring: Option<TextMirroring>,
304 font: Option<String>,
305 size: Option<i32>,
306 comment: Option<String>,
307 },
308 UserDefined {
309 name: String,
310 values: Vec<String>,
311 },
312}
313
314impl<W: Write> PartialGerberCode<W> for ApertureAttribute {
315 fn serialize_partial(&self, writer: &mut W) -> GerberResult<()> {
316 match self {
317 ApertureAttribute::ApertureFunction(ref af) => {
318 write!(writer, ".AperFunction,")?;
319 match af {
320 ApertureFunction::ViaDrill(ref value) => {
322 write!(writer, "ViaDrill")?;
323 if let Some(value) = value {
324 write!(writer, ",")?;
325 value.serialize_partial(writer)?;
326 }
327 }
328 ApertureFunction::BackDrill => {
329 write!(writer, "BackDrill")?;
330 }
331 ApertureFunction::ComponentDrill { ref function } => {
332 write!(writer, "ComponentDrill")?;
333 if let Some(function) = function {
334 write!(writer, ",")?;
335 function.serialize_partial(writer)?;
336 }
337 }
338 ApertureFunction::MechanicalDrill { function } => {
339 write!(writer, "MechanicalDrill")?;
340 if let Some(ref function) = function {
341 write!(writer, ",")?;
342 function.serialize_partial(writer)?;
343 }
344 }
345 ApertureFunction::CastellatedDrill => {
346 write!(writer, "CastellatedDrill")?;
347 }
348 ApertureFunction::OtherDrill(ref value) => {
349 write!(writer, "OtherDrill,{}", value)?;
350 }
351
352 ApertureFunction::ComponentPad => {
354 write!(writer, "ComponentPad")?;
355 }
356 ApertureFunction::SmdPad(ref value) => {
357 write!(writer, "SMDPad,")?;
358 value.serialize_partial(writer)?;
359 }
360 ApertureFunction::BgaPad(ref value) => {
361 write!(writer, "BGAPad,")?;
362 value.serialize_partial(writer)?;
363 }
364 ApertureFunction::ConnectorPad => {
365 write!(writer, "ConnectorPad")?;
366 }
367 ApertureFunction::HeatsinkPad => {
368 write!(writer, "HeatsinkPad")?;
369 }
370 ApertureFunction::ViaPad => {
371 write!(writer, "ViaPad")?;
372 }
373 ApertureFunction::TestPad => {
374 write!(writer, "TestPad")?;
375 }
376 ApertureFunction::CastellatedPad => {
377 write!(writer, "CastellatedPad")?;
378 }
379 ApertureFunction::FiducialPad(ref value) => {
380 write!(writer, "FiducialPad,")?;
381 value.serialize_partial(writer)?;
382 }
383 ApertureFunction::ThermalReliefPad => {
384 write!(writer, "ThermalReliefPad")?;
385 }
386 ApertureFunction::WasherPad => {
387 write!(writer, "WasherPad")?;
388 }
389 ApertureFunction::AntiPad => {
390 write!(writer, "AntiPad")?;
391 }
392 ApertureFunction::OtherPad(ref value) => {
393 write!(writer, "OtherPad,{}", value)?;
394 }
395 ApertureFunction::Conductor => {
396 write!(writer, "Conductor")?;
397 }
398 ApertureFunction::EtchedComponent => {
399 write!(writer, "EtchedComponent")?;
400 }
401 ApertureFunction::NonConductor => {
402 write!(writer, "NonConductor")?;
403 }
404 ApertureFunction::CopperBalancing => {
405 write!(writer, "CopperBalancing")?;
406 }
407 ApertureFunction::Border => {
408 write!(writer, "Border")?;
409 }
410 ApertureFunction::OtherCopper(ref value) => {
411 write!(writer, "OtherCopper,{}", value)?;
412 }
413
414 ApertureFunction::ComponentMain => {
416 write!(writer, "ComponentMain")?;
417 }
418 ApertureFunction::ComponentOutline(ref value) => {
419 write!(writer, "ComponentOutline,")?;
420 value.serialize_partial(writer)?;
421 }
422 ApertureFunction::ComponentPin => {
423 write!(writer, "ComponentPin")?;
424 }
425
426 ApertureFunction::Profile => {
428 write!(writer, "Profile")?;
429 }
430 ApertureFunction::NonMaterial => {
431 write!(writer, "NonMaterial")?;
432 }
433 ApertureFunction::Material => {
434 write!(writer, "Material")?;
435 }
436 ApertureFunction::Other(value) => {
437 write!(writer, "Other,{}", value)?;
438 }
439
440 ApertureFunction::Slot => {
442 write!(writer, "Slot")?;
443 }
444 ApertureFunction::Cavity => {
445 write!(writer, "Cavity")?;
446 }
447 ApertureFunction::CutOut => {
448 write!(writer, "CutOut")?;
449 }
450 ApertureFunction::Drawing => {
451 write!(writer, "Drawing")?;
452 }
453 }
454 }
455 ApertureAttribute::DrillTolerance { plus, minus } => {
456 write!(writer, ".DrillTolerance,{},{}", plus, minus)?;
457 }
458 ApertureAttribute::FlashText {
459 text,
460 mode,
461 mirroring,
462 font,
463 size,
464 comment,
465 } => {
466 write!(writer, ".FlashText,{},", text)?;
467 mode.serialize_partial(writer)?;
468 write!(writer, ",")?;
469 mirroring.serialize_partial(writer)?;
470 write!(writer, ",")?;
471 if let Some(font) = font {
472 write!(writer, "{}", font)?;
473 }
474 write!(writer, ",")?;
475 if let Some(size) = size {
476 write!(writer, "{}", size)?;
477 }
478 write!(writer, ",")?;
479 if let Some(comment) = comment {
480 write!(writer, "{}", comment)?;
481 }
482 }
483 ApertureAttribute::UserDefined { name, values } => {
484 write!(writer, "{}", name)?;
485 for value in values {
486 write!(writer, ",{}", value)?;
487 }
488 }
489 }
490 Ok(())
491 }
492}
493
494#[derive(Debug, Clone, PartialEq, Eq, Hash)]
497pub enum Part {
498 Single,
500 Array,
502 FabricationPanel,
504 Coupon,
506 Other(String),
508}
509
510impl<W: Write> PartialGerberCode<W> for Part {
511 fn serialize_partial(&self, writer: &mut W) -> GerberResult<()> {
512 match *self {
513 Part::Single => write!(writer, "Single")?,
514 Part::Array => write!(writer, "Array")?,
515 Part::FabricationPanel => write!(writer, "FabricationPanel")?,
516 Part::Coupon => write!(writer, "Coupon")?,
517 Part::Other(ref description) => write!(writer, "Other,{}", description)?,
518 };
519 Ok(())
520 }
521}
522
523#[derive(
526 Debug,
527 Copy,
528 Clone,
529 PartialEq,
530 Eq,
531 Hash,
532 strum_macros::Display,
533 IntoStaticStr,
534 VariantNames,
535 VariantArray,
536)]
537#[strum(serialize_all = "PascalCase")]
538pub enum Position {
539 Top,
540 #[strum(serialize = "Bot")]
541 Bottom,
542}
543
544impl_partial_gerber_code_via_strum!(Position);
545
546#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, IntoStaticStr, VariantNames, VariantArray)]
549#[strum(serialize_all = "PascalCase")]
550pub enum ExtendedPosition {
551 Top,
552 #[strum(serialize = "Inr")]
553 Inner,
554 #[strum(serialize = "Bot")]
555 Bottom,
556}
557
558impl_partial_gerber_code_via_strum!(ExtendedPosition);
559
560#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, IntoStaticStr, VariantNames, VariantArray)]
563#[strum(serialize_all = "PascalCase")]
564pub enum CopperType {
565 Plane,
566 Signal,
567 Mixed,
568 Hatched,
569}
570
571impl_partial_gerber_code_via_strum!(CopperType);
572
573#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, IntoStaticStr, VariantNames, VariantArray)]
576#[strum(serialize_all = "PascalCase")]
577pub enum PlatedDrill {
578 #[strum(serialize = "PTH")]
579 PlatedThroughHole,
580 Blind,
581 Buried,
582}
583
584impl_partial_gerber_code_via_strum!(PlatedDrill);
585
586#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, IntoStaticStr, VariantNames, VariantArray)]
589#[strum(serialize_all = "PascalCase")]
590pub enum NonPlatedDrill {
591 #[strum(serialize = "NPTH")]
592 NonPlatedThroughHole,
593 Blind,
594 Buried,
595}
596
597impl_partial_gerber_code_via_strum!(NonPlatedDrill);
598
599#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, IntoStaticStr, VariantNames, VariantArray)]
602#[strum(serialize_all = "PascalCase")]
603pub enum DrillRouteType {
604 Drill,
605 #[strum(serialize = "Rout")]
606 Route,
607 Mixed,
608}
609
610impl_partial_gerber_code_via_strum!(DrillRouteType);
611
612#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, IntoStaticStr, VariantNames, VariantArray)]
615pub enum Profile {
616 #[strum(serialize = "P")]
617 Plated,
618 #[strum(serialize = "NP")]
619 NonPlated,
620}
621
622impl_partial_gerber_code_via_strum!(Profile);
623
624#[derive(Debug, Clone, PartialEq, Eq, Hash)]
627pub enum FileFunction {
628 Copper {
632 layer: i32,
633 pos: ExtendedPosition,
634 copper_type: Option<CopperType>,
635 },
636 Plated {
637 from_layer: i32,
638 to_layer: i32,
639 drill: PlatedDrill,
640 label: Option<DrillRouteType>,
641 },
642 NonPlated {
643 from_layer: i32,
644 to_layer: i32,
645 drill: NonPlatedDrill,
646 label: Option<DrillRouteType>,
647 },
648 Profile(Option<Profile>),
652 KeepOut(Position),
653 SolderMask {
654 pos: Position,
655 index: Option<i32>,
656 },
657 Legend {
658 pos: Position,
659 index: Option<i32>,
660 },
661 Component {
662 layer: i32,
663 pos: Position,
664 },
665 Paste(Position),
666 Glue(Position),
667 CarbonMask {
668 pos: Position,
669 index: Option<i32>,
670 },
671 GoldMask {
672 pos: Position,
673 index: Option<i32>,
674 },
675 HeatsinkMask {
676 pos: Position,
677 index: Option<i32>,
678 },
679 PeelableMask {
680 pos: Position,
681 index: Option<i32>,
682 },
683 SilverMask {
684 pos: Position,
685 index: Option<i32>,
686 },
687 TinMask {
688 pos: Position,
689 index: Option<i32>,
690 },
691 DepthRoute(Position),
692 VCut(Option<Position>),
693 ViaFill,
695 Pads(Position),
696 Other(String),
697
698 DrillMap,
700 FabricationDrawing,
701 VCutMap,
702 AssemblyDrawing(Position),
703 ArrayDrawing,
704 OtherDrawing(String),
705}
706
707#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, IntoStaticStr, VariantNames, VariantArray)]
710#[strum(serialize_all = "PascalCase")]
711pub enum FilePolarity {
712 Positive,
713 Negative,
714}
715
716impl_partial_gerber_code_via_strum!(FilePolarity);
717
718#[derive(Debug, Clone, PartialEq, Eq, Hash)]
721pub struct GenerationSoftware {
722 pub vendor: String,
723 pub application: String,
724 pub version: Option<String>,
725}
726
727impl GenerationSoftware {
728 pub fn new<S: Into<String>>(vendor: S, application: S, version: Option<S>) -> Self {
729 GenerationSoftware {
730 vendor: vendor.into(),
731 application: application.into(),
732 version: version.map(|s| s.into()),
733 }
734 }
735}
736
737impl<W: Write> PartialGerberCode<W> for GenerationSoftware {
738 fn serialize_partial(&self, writer: &mut W) -> GerberResult<()> {
739 match self.version {
740 Some(ref v) => write!(writer, "{},{},{}", self.vendor, self.application, v)?,
741 None => write!(writer, "{},{}", self.vendor, self.application)?,
742 };
743 Ok(())
744 }
745}
746
747#[derive(Debug, Clone, PartialEq, Eq, Hash)]
751pub enum ApertureFunction {
752 ViaDrill(Option<IPC4761ViaProtection>),
754 BackDrill,
755 ComponentDrill { function: Option<ComponentDrill> },
756 MechanicalDrill { function: Option<DrillFunction> },
757 CastellatedDrill,
758 OtherDrill(String),
759
760 ComponentPad,
762 SmdPad(SmdPadType),
763 BgaPad(SmdPadType),
764 ConnectorPad,
765 HeatsinkPad,
766 ViaPad,
767 TestPad,
768 CastellatedPad,
769 FiducialPad(FiducialScope),
770 ThermalReliefPad,
771 WasherPad,
772 AntiPad,
773 OtherPad(String),
774 Conductor,
775 EtchedComponent,
776 NonConductor,
777 CopperBalancing,
778 Border,
779 OtherCopper(String),
780
781 Profile,
783 Material,
784 NonMaterial,
785 Other(String),
786
787 ComponentMain,
789 ComponentOutline(ComponentOutline),
790 ComponentPin,
791
792 Slot,
794 CutOut,
795 Cavity,
796 Drawing,
797}
798
799#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, IntoStaticStr, VariantNames, VariantArray)]
800#[strum(serialize_all = "PascalCase")]
801pub enum IPC4761ViaProtection {
802 Ia,
803 Ib,
804 IIa,
805 IIb,
806 #[strum(serialize = "IIIa")]
807 IIIa,
808 #[strum(serialize = "IIIb")]
809 IIIb,
810 IVa,
811 IVb,
812 V,
813 #[strum(serialize = "VI")]
814 VI,
815 #[strum(serialize = "VII")]
816 VII,
817 None,
818}
819
820impl_partial_gerber_code_via_strum!(IPC4761ViaProtection);
821
822#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, IntoStaticStr, VariantNames, VariantArray)]
823#[strum(serialize_all = "PascalCase")]
824pub enum ComponentOutline {
825 Body,
826 Lead2Lead,
827 Footprint,
828 Courtyard,
829}
830
831impl_partial_gerber_code_via_strum!(ComponentOutline);
832
833#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, IntoStaticStr, VariantNames, VariantArray)]
836#[strum(serialize_all = "PascalCase")]
837pub enum DrillFunction {
838 #[strum(serialize = "Breakout")]
839 BreakOut,
840 Tooling,
841 Other,
842}
843
844impl_partial_gerber_code_via_strum!(DrillFunction);
845
846#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, IntoStaticStr, VariantNames, VariantArray)]
850pub enum ComponentDrill {
851 #[strum(serialize = "PressFit")]
852 PressFit,
853}
854
855impl_partial_gerber_code_via_strum!(ComponentDrill);
856
857#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, IntoStaticStr, VariantNames, VariantArray)]
860#[strum(serialize_all = "PascalCase")]
861pub enum SmdPadType {
862 #[strum(serialize = "CuDef")]
863 CopperDefined,
864 #[strum(serialize = "SMDef")]
865 SoldermaskDefined,
866}
867
868impl_partial_gerber_code_via_strum!(SmdPadType);
869
870#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, IntoStaticStr, VariantNames, VariantArray)]
873#[strum(serialize_all = "PascalCase")]
874pub enum FiducialScope {
875 Local,
876 Global,
877 Panel,
878}
879
880impl_partial_gerber_code_via_strum!(FiducialScope);
881
882#[derive(Debug, Clone, PartialEq)]
884pub enum ObjectAttribute {
885 Net(Net),
886 Pin(Pin),
887 Component(String),
889 ComponentCharacteristics(ComponentCharacteristics),
890 UserDefined {
891 name: String,
892 values: Vec<String>,
893 },
894}
895
896impl<W: Write> PartialGerberCode<W> for ObjectAttribute {
897 fn serialize_partial(&self, writer: &mut W) -> GerberResult<()> {
898 match self {
899 ObjectAttribute::Net(net) => {
900 net.serialize_partial(writer)?;
901 }
902 ObjectAttribute::Pin(pin) => {
903 pin.serialize_partial(writer)?;
904 }
905 ObjectAttribute::Component(ref_des) => {
906 write!(writer, ".C,{}", ref_des)?;
907 }
908 ObjectAttribute::ComponentCharacteristics(cc) => {
909 cc.serialize_partial(writer)?;
910 }
911 ObjectAttribute::UserDefined { name, values } => {
912 write!(writer, "{}", name)?;
913 for value in values {
914 write!(writer, ",{}", value)?;
915 }
916 }
917 };
918 Ok(())
919 }
920}
921
922#[derive(Debug, Clone, PartialEq)]
925pub enum ComponentCharacteristics {
926 Rotation(f64),
928 Manufacturer(String),
930 MPN(String),
932 Value(String),
934 Mount(ComponentMounting),
936 Footprint(String),
938 PackageName(String),
940 PackageDescription(String),
942 Height(f64),
944 LibraryName(String),
946 LibraryDescription(String),
948 Supplier(Vec<SupplierPart>),
951}
952
953impl<W: Write> PartialGerberCode<W> for ComponentCharacteristics {
954 fn serialize_partial(&self, writer: &mut W) -> GerberResult<()> {
955 match self {
956 ComponentCharacteristics::Rotation(rotation) => {
957 write!(writer, ".CRot,{}", rotation)?;
958 }
959 ComponentCharacteristics::Manufacturer(manufacturer) => {
960 write!(writer, ".CMfr,{}", manufacturer)?;
961 }
962 ComponentCharacteristics::MPN(mpn) => {
963 write!(writer, ".CMPN,{}", mpn)?;
964 }
965 ComponentCharacteristics::Value(value) => {
966 write!(writer, ".CVal,{}", value)?;
967 }
968 ComponentCharacteristics::Mount(mount) => {
969 write!(writer, ".CMnt,")?;
970 mount.serialize_partial(writer)?;
971 }
972 ComponentCharacteristics::Footprint(footprint) => {
973 write!(writer, ".CFtp,{}", footprint)?;
974 }
975 ComponentCharacteristics::PackageName(package_name) => {
976 write!(writer, ".CPgN,{}", package_name)?;
977 }
978 ComponentCharacteristics::PackageDescription(package_description) => {
979 write!(writer, ".CPgD,{}", package_description)?;
980 }
981 ComponentCharacteristics::Height(height) => {
982 write!(writer, ".CHgt,{}", height)?;
983 }
984 ComponentCharacteristics::LibraryName(library_name) => {
985 write!(writer, ".CLbN,{}", library_name)?;
986 }
987 ComponentCharacteristics::LibraryDescription(library_description) => {
988 write!(writer, ".CLbD,{}", library_description)?;
989 }
990 ComponentCharacteristics::Supplier(values) => {
991 write!(writer, ".CSup")?;
992 for value in values {
993 write!(writer, ",")?;
994 value.serialize_partial(writer)?;
995 }
996 }
997 }
998 Ok(())
999 }
1000}
1001
1002#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, IntoStaticStr, VariantNames, VariantArray)]
1004pub enum ComponentMounting {
1005 #[strum(serialize = "TH")]
1006 ThroughHole,
1007 #[strum(serialize = "SMD")]
1009 SMD,
1010 #[strum(serialize = "Pressfit")]
1011 PressFit,
1012 #[strum(serialize = "Other")]
1013 Other,
1014}
1015
1016impl_partial_gerber_code_via_strum!(ComponentMounting);
1017
1018#[derive(Debug, Clone, PartialEq, Eq, Hash)]
1019pub struct SupplierPart {
1020 pub supplier_name: String,
1022 pub supplier_part_reference: String,
1024}
1025
1026impl<W: Write> PartialGerberCode<W> for SupplierPart {
1027 fn serialize_partial(&self, writer: &mut W) -> GerberResult<()> {
1028 write!(
1029 writer,
1030 "{},{}",
1031 self.supplier_name, self.supplier_part_reference
1032 )?;
1033 Ok(())
1034 }
1035}
1036
1037#[derive(Debug, Clone, PartialEq, Eq)]
1038pub enum Net {
1039 None,
1040 NotConnected,
1041 Connected(Vec<String>),
1042}
1043
1044impl<W: Write> PartialGerberCode<W> for Net {
1045 fn serialize_partial(&self, writer: &mut W) -> GerberResult<()> {
1046 write!(writer, ".N,")?;
1047 match self {
1048 Net::None => {}
1049 Net::NotConnected => {
1050 write!(writer, "N/C")?;
1051 }
1052 Net::Connected(nets) => {
1053 write!(writer, "{}", nets.join(","))?;
1054 }
1055 }
1056 Ok(())
1057 }
1058}
1059
1060#[derive(Debug, Clone, PartialEq, Eq)]
1061pub struct Pin {
1062 pub refdes: String,
1063 pub name: String,
1065 pub function: Option<String>,
1066}
1067
1068impl<W: Write> PartialGerberCode<W> for Pin {
1069 fn serialize_partial(&self, writer: &mut W) -> GerberResult<()> {
1070 write!(writer, ".P,{},{}", self.refdes, self.name)?;
1071 if let Some(function) = &self.function {
1072 write!(writer, ",{}", function)?;
1073 }
1074 Ok(())
1075 }
1076}
1077
1078#[derive(Debug, Clone, PartialEq)]
1088pub enum AttributeDeletionCriterion {
1089 AllApertureAndObjectAttributes,
1090 SingleObjectAttribute(String),
1091 SingleApertureAttribute(String),
1092}
1093
1094impl<W: Write> PartialGerberCode<W> for AttributeDeletionCriterion {
1095 fn serialize_partial(&self, writer: &mut W) -> GerberResult<()> {
1096 match self {
1097 AttributeDeletionCriterion::AllApertureAndObjectAttributes => {}
1098 AttributeDeletionCriterion::SingleObjectAttribute(name) => {
1099 write!(writer, "{}", name)?;
1100 }
1101 AttributeDeletionCriterion::SingleApertureAttribute(name) => {
1102 write!(writer, "{}", name)?;
1103 }
1104 }
1105 Ok(())
1106 }
1107}