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 std::convert::From;
8
9use crate::attributes;
10use crate::coordinates;
11use crate::extended_codes;
12use crate::function_codes;
13use crate::macros;
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, Eq)]
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    /// SR
78    StepAndRepeat(extended_codes::StepAndRepeat),
79    /// TF
80    FileAttribute(attributes::FileAttribute),
81    /// TA
82    ApertureAttribute(attributes::ApertureAttribute),
83    /// TD
84    DeleteAttribute(String),
85}
86
87impl_from!(
88    coordinates::CoordinateFormat,
89    ExtendedCode,
90    ExtendedCode::CoordinateFormat
91);
92impl_from!(extended_codes::Unit, ExtendedCode, ExtendedCode::Unit);
93impl_from!(
94    extended_codes::ApertureDefinition,
95    ExtendedCode,
96    ExtendedCode::ApertureDefinition
97);
98impl_from!(
99    macros::ApertureMacro,
100    ExtendedCode,
101    ExtendedCode::ApertureMacro
102);
103impl_from!(
104    extended_codes::Polarity,
105    ExtendedCode,
106    ExtendedCode::LoadPolarity
107);
108impl_from!(
109    extended_codes::StepAndRepeat,
110    ExtendedCode,
111    ExtendedCode::StepAndRepeat
112);
113impl_from!(
114    attributes::FileAttribute,
115    ExtendedCode,
116    ExtendedCode::FileAttribute
117);
118impl_from!(
119    attributes::ApertureAttribute,
120    ExtendedCode,
121    ExtendedCode::ApertureAttribute
122);
123
124impl_command_fromfrom!(coordinates::CoordinateFormat, ExtendedCode::from);
125impl_command_fromfrom!(extended_codes::Unit, ExtendedCode::from);
126impl_command_fromfrom!(extended_codes::ApertureDefinition, ExtendedCode::from);
127impl_command_fromfrom!(macros::ApertureMacro, ExtendedCode::from);
128impl_command_fromfrom!(extended_codes::Polarity, ExtendedCode::from);
129impl_command_fromfrom!(extended_codes::StepAndRepeat, ExtendedCode::from);
130impl_command_fromfrom!(attributes::FileAttribute, ExtendedCode::from);
131impl_command_fromfrom!(attributes::ApertureAttribute, ExtendedCode::from);
132
133#[cfg(test)]
134mod test {
135    use super::*;
136
137    use std::io::BufWriter;
138
139    use crate::extended_codes::Polarity;
140    use crate::function_codes::GCode;
141    use crate::traits::GerberCode;
142
143    #[test]
144    fn test_debug() {
145        //! The debug representation should work properly.
146        let c = Command::FunctionCode(FunctionCode::GCode(GCode::Comment("test".to_string())));
147        let debug = format!("{:?}", c);
148        assert_eq!(debug, "FunctionCode(GCode(Comment(\"test\")))");
149    }
150
151    #[test]
152    fn test_function_code_serialize() {
153        //! A `FunctionCode` should implement `GerberCode`
154        let c = FunctionCode::GCode(GCode::Comment("comment".to_string()));
155        assert_code!(c, "G04 comment*\n");
156    }
157
158    #[test]
159    fn test_function_code_from_gcode() {
160        let comment = GCode::Comment("hello".into());
161        let f1: FunctionCode = FunctionCode::GCode(comment.clone());
162        let f2: FunctionCode = comment.into();
163        assert_eq!(f1, f2);
164    }
165
166    #[test]
167    fn test_command_from_function_code() {
168        let comment = FunctionCode::GCode(GCode::Comment("hello".into()));
169        let c1: Command = Command::FunctionCode(comment.clone());
170        let c2: Command = comment.into();
171        assert_eq!(c1, c2);
172    }
173
174    #[test]
175    fn test_command_from_extended_code() {
176        let delete_attr = ExtendedCode::DeleteAttribute("hello".into());
177        let c1: Command = Command::ExtendedCode(delete_attr.clone());
178        let c2: Command = delete_attr.into();
179        assert_eq!(c1, c2);
180    }
181
182    #[test]
183    fn test_extended_code_from_polarity() {
184        let e1: ExtendedCode = ExtendedCode::LoadPolarity(Polarity::Dark);
185        let e2: ExtendedCode = Polarity::Dark.into();
186        assert_eq!(e1, e2);
187    }
188}