gerber_types/
types.rs

1//! Types for Gerber code generation.
2//!
3//! All types are stateless, meaning that they contain all information in order
4//! to render themselves. This means for example that each `Coordinates`
5//! instance contains a reference to the coordinate format to be used.
6
7use crate::attributes;
8use crate::coordinates;
9use crate::extended_codes;
10use crate::function_codes;
11use crate::macros;
12use chrono::{DateTime, FixedOffset};
13use std::convert::From;
14
15// Helper macros
16
17macro_rules! impl_from {
18    ($from:ty, $target:ty, $variant:expr) => {
19        impl From<$from> for $target {
20            fn from(val: $from) -> Self {
21                $variant(val)
22            }
23        }
24    };
25}
26
27// Root type
28
29#[derive(Debug, Clone, PartialEq)]
30pub enum Command {
31    FunctionCode(FunctionCode),
32    ExtendedCode(ExtendedCode),
33}
34
35impl_from!(FunctionCode, Command, Command::FunctionCode);
36impl_from!(ExtendedCode, Command, Command::ExtendedCode);
37
38macro_rules! impl_command_fromfrom {
39    ($from:ty, $inner:path) => {
40        impl From<$from> for Command {
41            fn from(val: $from) -> Self {
42                Command::from($inner(val))
43            }
44        }
45    };
46}
47
48// Main categories
49
50#[derive(Debug, Clone, PartialEq)]
51pub enum FunctionCode {
52    DCode(function_codes::DCode),
53    GCode(function_codes::GCode),
54    MCode(function_codes::MCode),
55}
56
57impl_from!(function_codes::DCode, FunctionCode, FunctionCode::DCode);
58impl_from!(function_codes::GCode, FunctionCode, FunctionCode::GCode);
59impl_from!(function_codes::MCode, FunctionCode, FunctionCode::MCode);
60
61impl_command_fromfrom!(function_codes::DCode, FunctionCode::from);
62impl_command_fromfrom!(function_codes::GCode, FunctionCode::from);
63impl_command_fromfrom!(function_codes::MCode, FunctionCode::from);
64
65#[derive(Debug, Clone, PartialEq)]
66pub enum ExtendedCode {
67    /// FS
68    CoordinateFormat(coordinates::CoordinateFormat),
69    /// MO
70    Unit(extended_codes::Unit),
71    /// AD
72    ApertureDefinition(extended_codes::ApertureDefinition),
73    /// AM
74    ApertureMacro(macros::ApertureMacro),
75    /// LP
76    LoadPolarity(extended_codes::Polarity),
77    /// LM
78    LoadMirroring(extended_codes::Mirroring),
79    /// LR
80    LoadRotation(extended_codes::Rotation),
81    /// LS
82    LoadScaling(extended_codes::Scaling),
83    /// SR
84    StepAndRepeat(extended_codes::StepAndRepeat),
85    /// AB
86    ApertureBlock(extended_codes::ApertureBlock),
87    /// TF
88    FileAttribute(attributes::FileAttribute),
89    /// TO
90    ObjectAttribute(attributes::ObjectAttribute),
91    /// TA
92    ApertureAttribute(attributes::ApertureAttribute),
93    /// TD
94    DeleteAttribute(attributes::AttributeDeletionCriterion),
95    /// MI (deprecated in Gerber spec since December 2012)
96    MirrorImage(extended_codes::ImageMirroring),
97    /// OF (deprecated in Gerber spec since December 2012)
98    OffsetImage(extended_codes::ImageOffset),
99    /// SF (deprecated in Gerber spec since December 2012)
100    ScaleImage(extended_codes::ImageScaling),
101    /// IR (deprecated in Gerber spec since December 2012)
102    RotateImage(extended_codes::ImageRotation),
103    /// IP (deprecated in gerber spec since December 2012)
104    ImagePolarity(extended_codes::ImagePolarity),
105    /// AS (deprecated in gerber spec since December 2012)
106    AxisSelect(extended_codes::AxisSelect),
107    /// IN (deprecated in gerber spec since October 2013)
108    ImageName(extended_codes::ImageName),
109}
110
111impl_from!(
112    coordinates::CoordinateFormat,
113    ExtendedCode,
114    ExtendedCode::CoordinateFormat
115);
116impl_from!(extended_codes::Unit, ExtendedCode, ExtendedCode::Unit);
117impl_from!(
118    extended_codes::ApertureDefinition,
119    ExtendedCode,
120    ExtendedCode::ApertureDefinition
121);
122impl_from!(
123    macros::ApertureMacro,
124    ExtendedCode,
125    ExtendedCode::ApertureMacro
126);
127impl_from!(
128    extended_codes::Polarity,
129    ExtendedCode,
130    ExtendedCode::LoadPolarity
131);
132impl_from!(
133    extended_codes::Mirroring,
134    ExtendedCode,
135    ExtendedCode::LoadMirroring
136);
137impl_from!(
138    extended_codes::Rotation,
139    ExtendedCode,
140    ExtendedCode::LoadRotation
141);
142impl_from!(
143    extended_codes::Scaling,
144    ExtendedCode,
145    ExtendedCode::LoadScaling
146);
147impl_from!(
148    extended_codes::StepAndRepeat,
149    ExtendedCode,
150    ExtendedCode::StepAndRepeat
151);
152impl_from!(
153    extended_codes::ApertureBlock,
154    ExtendedCode,
155    ExtendedCode::ApertureBlock
156);
157impl_from!(
158    attributes::FileAttribute,
159    ExtendedCode,
160    ExtendedCode::FileAttribute
161);
162impl_from!(
163    attributes::ApertureAttribute,
164    ExtendedCode,
165    ExtendedCode::ApertureAttribute
166);
167
168impl_command_fromfrom!(coordinates::CoordinateFormat, ExtendedCode::from);
169impl_command_fromfrom!(extended_codes::Unit, ExtendedCode::from);
170impl_command_fromfrom!(extended_codes::ApertureDefinition, ExtendedCode::from);
171impl_command_fromfrom!(macros::ApertureMacro, ExtendedCode::from);
172impl_command_fromfrom!(extended_codes::Polarity, ExtendedCode::from);
173impl_command_fromfrom!(extended_codes::Scaling, ExtendedCode::from);
174impl_command_fromfrom!(extended_codes::Mirroring, ExtendedCode::from);
175impl_command_fromfrom!(extended_codes::Rotation, ExtendedCode::from);
176impl_command_fromfrom!(extended_codes::StepAndRepeat, ExtendedCode::from);
177impl_command_fromfrom!(extended_codes::ApertureBlock, ExtendedCode::from);
178impl_command_fromfrom!(attributes::FileAttribute, ExtendedCode::from);
179impl_command_fromfrom!(attributes::ApertureAttribute, ExtendedCode::from);
180
181#[cfg(test)]
182mod test {
183    use super::*;
184
185    use std::io::BufWriter;
186
187    use crate::extended_codes::Polarity;
188    use crate::function_codes::GCode;
189    use crate::traits::GerberCode;
190    use crate::{
191        ApertureBlock, AttributeDeletionCriterion, CommentContent, Mirroring, Rotation, Scaling,
192        StepAndRepeat,
193    };
194
195    #[test]
196    fn test_debug() {
197        //! The debug representation should work properly.
198        let c = Command::FunctionCode(FunctionCode::GCode(GCode::Comment(CommentContent::String(
199            "test".to_string(),
200        ))));
201        let debug = format!("{:?}", c);
202        assert_eq!(debug, "FunctionCode(GCode(Comment(String(\"test\"))))");
203    }
204
205    #[test]
206    fn test_function_code_serialize() {
207        //! A `FunctionCode` should implement `GerberCode`
208        let c = FunctionCode::GCode(GCode::Comment(CommentContent::String(
209            "comment".to_string(),
210        )));
211        assert_code!(c, "G04 comment*\n");
212    }
213
214    #[test]
215    fn test_function_code_from_gcode() {
216        let comment = GCode::Comment(CommentContent::String("hello".into()));
217        let f1: FunctionCode = FunctionCode::GCode(comment.clone());
218        let f2: FunctionCode = comment.into();
219        assert_eq!(f1, f2);
220    }
221
222    #[test]
223    fn test_command_from_function_code() {
224        let comment = FunctionCode::GCode(GCode::Comment(CommentContent::String("hello".into())));
225        let c1: Command = Command::FunctionCode(comment.clone());
226        let c2: Command = comment.into();
227        assert_eq!(c1, c2);
228    }
229
230    #[test]
231    fn test_command_from_extended_code() {
232        let delete_attr = ExtendedCode::DeleteAttribute(
233            AttributeDeletionCriterion::SingleApertureAttribute("test".to_string()),
234        );
235        let c1: Command = Command::ExtendedCode(delete_attr.clone());
236        let c2: Command = delete_attr.into();
237        assert_eq!(c1, c2);
238    }
239
240    #[test]
241    fn test_extended_code_from_step_and_repeat() {
242        let e1: ExtendedCode = ExtendedCode::StepAndRepeat(StepAndRepeat::Close);
243        let e2: ExtendedCode = StepAndRepeat::Close.into();
244        assert_eq!(e1, e2);
245    }
246
247    #[test]
248    fn test_extended_code_from_aperture_block() {
249        let e1: ExtendedCode = ExtendedCode::ApertureBlock(ApertureBlock::Open { code: 102 });
250        let e2: ExtendedCode = ApertureBlock::Open { code: 102 }.into();
251        assert_eq!(e1, e2);
252    }
253    #[test]
254    fn test_extended_code_from_polarity() {
255        let e1: ExtendedCode = ExtendedCode::LoadPolarity(Polarity::Dark);
256        let e2: ExtendedCode = Polarity::Dark.into();
257        assert_eq!(e1, e2);
258    }
259
260    #[test]
261    fn test_extended_code_from_mirroring() {
262        let e1: ExtendedCode = ExtendedCode::LoadMirroring(Mirroring::XY);
263        let e2: ExtendedCode = Mirroring::XY.into();
264        assert_eq!(e1, e2);
265    }
266
267    #[test]
268    fn test_extended_code_from_scaling() {
269        let e1: ExtendedCode = ExtendedCode::LoadScaling(Scaling { scale: 50.0 });
270        let e2: ExtendedCode = Scaling { scale: 50.0 }.into();
271        assert_eq!(e1, e2);
272    }
273
274    #[test]
275    fn test_extended_code_from_rotation() {
276        let e1: ExtendedCode = ExtendedCode::LoadRotation(Rotation { rotation: 90.0 });
277        let e2: ExtendedCode = Rotation { rotation: 90.0 }.into();
278        assert_eq!(e1, e2);
279    }
280}
281
282// Date/Time
283pub type GerberDate = DateTime<FixedOffset>;