From 6f77ef9d7d6529504ef1914cfeef0550112a518c Mon Sep 17 00:00:00 2001 From: Dominic Clifton Date: Mon, 30 Jun 2025 09:23:07 +0200 Subject: [PATCH] Make Coordinates optional for D01, D02, D03. Since `Operation` specifies an `Option` it is inconsistent to allow both of these states: a) `Operation::Interpolate { _, Some(CoordinateOffset { x: None, y: None })}` b) `Operation::Interpolate { _, None }, * If a viewer encounters the first state, it should generate a warning. * A parser should never generate the first state (a) to begin with and generate (b) instead. To be consistent, it's now invalid for both Coordinate and CoordinateOffset to have neither X nor Y. Instead, `None` should be used for the `Coordinate` or `CoordinateOffset` instance itself. * this answers the long-standing 'should we catch this' question, the answer is YES. --- examples/polarities-apertures.rs | 155 ++++++++++++++++++------------- examples/two-boxes.rs | 25 ++--- src/coordinates.rs | 144 ++++++++++++++++++++++++---- src/errors.rs | 3 + src/function_codes.rs | 9 +- src/lib.rs | 13 ++- 6 files changed, 252 insertions(+), 97 deletions(-) diff --git a/examples/polarities-apertures.rs b/examples/polarities-apertures.rs index ccb77756..0c88da43 100644 --- a/examples/polarities-apertures.rs +++ b/examples/polarities-apertures.rs @@ -121,106 +121,117 @@ fn main() { .into(), FunctionCode::GCode(GCode::Comment("Start image generation".to_string())).into(), FunctionCode::DCode(DCode::SelectAperture(10)).into(), - FunctionCode::DCode(DCode::Operation(Operation::Move(Coordinates::new( + FunctionCode::DCode(DCode::Operation(Operation::Move(Some(Coordinates::new( 0, CoordinateNumber::try_from(0.25).unwrap(), cf, - )))) + ))))) .into(), FunctionCode::GCode(GCode::InterpolationMode(InterpolationMode::Linear)).into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::new(0, 0, cf), + Some(Coordinates::new(0, 0, cf)), None, ))) .into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::new(CoordinateNumber::try_from(0.25).unwrap(), 0, cf), + Some(Coordinates::new( + CoordinateNumber::try_from(0.25).unwrap(), + 0, + cf, + )), None, ))) .into(), - FunctionCode::DCode(DCode::Operation(Operation::Move(Coordinates::new( + FunctionCode::DCode(DCode::Operation(Operation::Move(Some(Coordinates::new( 1, 1, cf, - )))) + ))))) .into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::at_x(CoordinateNumber::try_from(1.5).unwrap(), cf), + Some(Coordinates::at_x( + CoordinateNumber::try_from(1.5).unwrap(), + cf, + )), None, ))) .into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::new(2, CoordinateNumber::try_from(1.5).unwrap(), cf), + Some(Coordinates::new( + 2, + CoordinateNumber::try_from(1.5).unwrap(), + cf, + )), None, ))) .into(), - FunctionCode::DCode(DCode::Operation(Operation::Move(Coordinates::at_x( + FunctionCode::DCode(DCode::Operation(Operation::Move(Some(Coordinates::at_x( CoordinateNumber::try_from(2.5).unwrap(), cf, - )))) + ))))) .into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::at_y(1, cf), + Some(Coordinates::at_y(1, cf)), None, ))) .into(), FunctionCode::DCode(DCode::SelectAperture(11)).into(), - FunctionCode::DCode(DCode::Operation(Operation::Flash(Coordinates::new( + FunctionCode::DCode(DCode::Operation(Operation::Flash(Some(Coordinates::new( 1, 1, cf, - )))) + ))))) .into(), - FunctionCode::DCode(DCode::Operation(Operation::Flash(Coordinates::new( + FunctionCode::DCode(DCode::Operation(Operation::Flash(Some(Coordinates::new( 2, 1, cf, - )))) + ))))) .into(), - FunctionCode::DCode(DCode::Operation(Operation::Flash(Coordinates::new( + FunctionCode::DCode(DCode::Operation(Operation::Flash(Some(Coordinates::new( CoordinateNumber::try_from(2.5).unwrap(), 1, cf, - )))) + ))))) .into(), - FunctionCode::DCode(DCode::Operation(Operation::Flash(Coordinates::new( + FunctionCode::DCode(DCode::Operation(Operation::Flash(Some(Coordinates::new( CoordinateNumber::try_from(2.5).unwrap(), CoordinateNumber::try_from(1.5).unwrap(), cf, - )))) + ))))) .into(), - FunctionCode::DCode(DCode::Operation(Operation::Flash(Coordinates::new( + FunctionCode::DCode(DCode::Operation(Operation::Flash(Some(Coordinates::new( 2, CoordinateNumber::try_from(1.5).unwrap(), cf, - )))) + ))))) .into(), FunctionCode::DCode(DCode::SelectAperture(12)).into(), - FunctionCode::DCode(DCode::Operation(Operation::Flash(Coordinates::new( + FunctionCode::DCode(DCode::Operation(Operation::Flash(Some(Coordinates::new( 1, CoordinateNumber::try_from(1.5).unwrap(), cf, - )))) + ))))) .into(), FunctionCode::DCode(DCode::SelectAperture(13)).into(), - FunctionCode::DCode(DCode::Operation(Operation::Flash(Coordinates::new( + FunctionCode::DCode(DCode::Operation(Operation::Flash(Some(Coordinates::new( 3, CoordinateNumber::try_from(1.5).unwrap(), cf, - )))) + ))))) .into(), FunctionCode::DCode(DCode::SelectAperture(14)).into(), - FunctionCode::DCode(DCode::Operation(Operation::Flash(Coordinates::new( + FunctionCode::DCode(DCode::Operation(Operation::Flash(Some(Coordinates::new( 3, CoordinateNumber::try_from(1.25).unwrap(), cf, - )))) + ))))) .into(), FunctionCode::DCode(DCode::SelectAperture(15)).into(), - FunctionCode::DCode(DCode::Operation(Operation::Flash(Coordinates::new( + FunctionCode::DCode(DCode::Operation(Operation::Flash(Some(Coordinates::new( 3, 1, cf, - )))) + ))))) .into(), FunctionCode::DCode(DCode::SelectAperture(10)).into(), - FunctionCode::DCode(DCode::Operation(Operation::Move(Coordinates::new( + FunctionCode::DCode(DCode::Operation(Operation::Move(Some(Coordinates::new( CoordinateNumber::try_from(3.75).unwrap(), 1, cf, - )))) + ))))) .into(), FunctionCode::GCode(GCode::QuadrantMode(QuadrantMode::Multi)).into(), FunctionCode::GCode(GCode::InterpolationMode( @@ -228,7 +239,11 @@ fn main() { )) .into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::new(CoordinateNumber::try_from(3.75).unwrap(), 1, cf), + Some(Coordinates::new( + CoordinateNumber::try_from(3.75).unwrap(), + 1, + cf, + )), Some(CoordinateOffset::new( CoordinateNumber::try_from(0.25).unwrap(), 0, @@ -237,71 +252,80 @@ fn main() { ))) .into(), FunctionCode::DCode(DCode::SelectAperture(16)).into(), - FunctionCode::DCode(DCode::Operation(Operation::Flash(Coordinates::new( + FunctionCode::DCode(DCode::Operation(Operation::Flash(Some(Coordinates::new( CoordinateNumber::try_from(3.4).unwrap(), 1, cf, - )))) + ))))) .into(), - FunctionCode::DCode(DCode::Operation(Operation::Flash(Coordinates::new( + FunctionCode::DCode(DCode::Operation(Operation::Flash(Some(Coordinates::new( CoordinateNumber::try_from(3.5).unwrap(), CoordinateNumber::try_from(0.9).unwrap(), cf, - )))) + ))))) .into(), FunctionCode::DCode(DCode::SelectAperture(10)).into(), FunctionCode::GCode(GCode::RegionMode(true)).into(), - FunctionCode::DCode(DCode::Operation(Operation::Move(Coordinates::new( + FunctionCode::DCode(DCode::Operation(Operation::Move(Some(Coordinates::new( CoordinateNumber::try_from(0.5).unwrap(), 2, cf, - )))) + ))))) .into(), FunctionCode::GCode(GCode::InterpolationMode(InterpolationMode::Linear)).into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::at_y(CoordinateNumber::try_from(3.75).unwrap(), cf), + Some(Coordinates::at_y( + CoordinateNumber::try_from(3.75).unwrap(), + cf, + )), None, ))) .into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::at_x(CoordinateNumber::try_from(3.75).unwrap(), cf), + Some(Coordinates::at_x( + CoordinateNumber::try_from(3.75).unwrap(), + cf, + )), None, ))) .into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::at_y(2, cf), + Some(Coordinates::at_y(2, cf)), None, ))) .into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::at_x(CoordinateNumber::try_from(0.5).unwrap(), cf), + Some(Coordinates::at_x( + CoordinateNumber::try_from(0.5).unwrap(), + cf, + )), None, ))) .into(), FunctionCode::GCode(GCode::RegionMode(false)).into(), FunctionCode::DCode(DCode::SelectAperture(18)).into(), - FunctionCode::DCode(DCode::Operation(Operation::Flash(Coordinates::new( + FunctionCode::DCode(DCode::Operation(Operation::Flash(Some(Coordinates::new( 0, CoordinateNumber::try_from(3.875).unwrap(), cf, - )))) + ))))) .into(), - FunctionCode::DCode(DCode::Operation(Operation::Flash(Coordinates::new( + FunctionCode::DCode(DCode::Operation(Operation::Flash(Some(Coordinates::new( CoordinateNumber::try_from(3.875).unwrap(), CoordinateNumber::try_from(3.875).unwrap(), cf, - )))) + ))))) .into(), ExtendedCode::LoadPolarity(Polarity::Clear).into(), FunctionCode::GCode(GCode::RegionMode(true)).into(), - FunctionCode::DCode(DCode::Operation(Operation::Move(Coordinates::new( + FunctionCode::DCode(DCode::Operation(Operation::Move(Some(Coordinates::new( 1, CoordinateNumber::try_from(2.5).unwrap(), cf, - )))) + ))))) .into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::at_y(3, cf), + Some(Coordinates::at_y(3, cf)), None, ))) .into(), @@ -311,11 +335,11 @@ fn main() { )) .into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::new( + Some(Coordinates::new( CoordinateNumber::try_from(1.25).unwrap(), CoordinateNumber::try_from(3.25).unwrap(), cf, - ), + )), Some(CoordinateOffset::new( CoordinateNumber::try_from(0.25).unwrap(), 0, @@ -325,7 +349,7 @@ fn main() { .into(), FunctionCode::GCode(GCode::InterpolationMode(InterpolationMode::Linear)).into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::at_x(3, cf), + Some(Coordinates::at_x(3, cf)), None, ))) .into(), @@ -335,7 +359,11 @@ fn main() { )) .into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::new(3, CoordinateNumber::try_from(2.5).unwrap(), cf), + Some(Coordinates::new( + 3, + CoordinateNumber::try_from(2.5).unwrap(), + cf, + )), Some(CoordinateOffset::new( 0, CoordinateNumber::try_from(0.375).unwrap(), @@ -345,38 +373,41 @@ fn main() { .into(), FunctionCode::GCode(GCode::InterpolationMode(InterpolationMode::Linear)).into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::at_x(1, cf), + Some(Coordinates::at_x(1, cf)), None, ))) .into(), FunctionCode::GCode(GCode::RegionMode(false)).into(), ExtendedCode::LoadPolarity(Polarity::Dark).into(), FunctionCode::DCode(DCode::SelectAperture(10)).into(), - FunctionCode::DCode(DCode::Operation(Operation::Move(Coordinates::new( + FunctionCode::DCode(DCode::Operation(Operation::Move(Some(Coordinates::new( CoordinateNumber::try_from(1.5).unwrap(), CoordinateNumber::try_from(2.875).unwrap(), cf, - )))) + ))))) .into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::at_x(2, cf), + Some(Coordinates::at_x(2, cf)), None, ))) .into(), FunctionCode::DCode(DCode::SelectAperture(11)).into(), - FunctionCode::DCode(DCode::Operation(Operation::Flash(Coordinates::new( + FunctionCode::DCode(DCode::Operation(Operation::Flash(Some(Coordinates::new( CoordinateNumber::try_from(1.5).unwrap(), CoordinateNumber::try_from(2.875).unwrap(), cf, - )))) + ))))) + .into(), + FunctionCode::DCode(DCode::Operation(Operation::Flash(Some(Coordinates::at_x( + 2, cf, + ))))) .into(), - FunctionCode::DCode(DCode::Operation(Operation::Flash(Coordinates::at_x(2, cf)))).into(), FunctionCode::DCode(DCode::SelectAperture(19)).into(), - FunctionCode::DCode(DCode::Operation(Operation::Flash(Coordinates::new( + FunctionCode::DCode(DCode::Operation(Operation::Flash(Some(Coordinates::new( CoordinateNumber::try_from(2.875).unwrap(), CoordinateNumber::try_from(2.875).unwrap(), cf, - )))) + ))))) .into(), ExtendedCode::FileAttribute(FileAttribute::Md5( "6ab9e892830469cdff7e3e346331d404".to_string(), diff --git a/examples/two-boxes.rs b/examples/two-boxes.rs index 3026e2d1..66001b7b 100644 --- a/examples/two-boxes.rs +++ b/examples/two-boxes.rs @@ -34,49 +34,52 @@ fn main() { }) .into(), FunctionCode::DCode(DCode::SelectAperture(10)).into(), - FunctionCode::DCode(DCode::Operation(Operation::Move(Coordinates::new( + FunctionCode::DCode(DCode::Operation(Operation::Move(Some(Coordinates::new( 0, 0, cf, - )))) + ))))) .into(), FunctionCode::GCode(GCode::InterpolationMode(InterpolationMode::Linear)).into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::new(5, 0, cf), + Some(Coordinates::new(5, 0, cf)), None, ))) .into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::at_y(5, cf), + Some(Coordinates::at_y(5, cf)), None, ))) .into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::at_x(0, cf), + Some(Coordinates::at_x(0, cf)), None, ))) .into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::at_y(0, cf), + Some(Coordinates::at_y(0, cf)), None, ))) .into(), - FunctionCode::DCode(DCode::Operation(Operation::Move(Coordinates::at_x(6, cf)))).into(), + FunctionCode::DCode(DCode::Operation(Operation::Move(Some(Coordinates::at_x( + 6, cf, + ))))) + .into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::at_x(11, cf), + Some(Coordinates::at_x(11, cf)), None, ))) .into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::at_y(5, cf), + Some(Coordinates::at_y(5, cf)), None, ))) .into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::at_x(6, cf), + Some(Coordinates::at_x(6, cf)), None, ))) .into(), FunctionCode::DCode(DCode::Operation(Operation::Interpolate( - Coordinates::at_y(0, cf), + Some(Coordinates::at_y(0, cf)), None, ))) .into(), diff --git a/src/coordinates.rs b/src/coordinates.rs index b1cdb943..a0e1e0f8 100644 --- a/src/coordinates.rs +++ b/src/coordinates.rs @@ -201,6 +201,8 @@ impl CoordinateNumber { /// /// Coordinates are modal. If an X is omitted, the X coordinate of the /// current point is used. Similar for Y. +/// +/// It is NOT valid for both X and Y to be omitted, instead the Coordinates itself should be contained in an `Option` #[derive(Debug, Clone, PartialEq, Eq)] pub struct Coordinates { pub x: Option, @@ -221,6 +223,18 @@ impl Coordinates { } } + pub fn validate(self) -> Result { + match (self.x, self.y) { + (None, None) => Err(GerberError::EmptyCoordinates), + (Some(x), Some(y)) => { + x.validate(&self.format)?; + y.validate(&self.format)?; + Ok(self) + } + _ => Ok(self), + } + } + pub fn at_x(x: T, format: CoordinateFormat) -> Self where T: IntoOptionalCoordinate, @@ -248,6 +262,8 @@ impl_xy_partial_gerbercode!(Coordinates, "X", "Y"); /// Coordinate offsets can be used for interpolate operations in circular /// interpolation mode. +/// +/// It is NOT valid for both X and Y to be omitted, instead the CoordinateOffset itself should be contained in an `Option` #[derive(Debug, Clone, PartialEq, Eq)] pub struct CoordinateOffset { pub x: Option, @@ -268,6 +284,18 @@ impl CoordinateOffset { } } + pub fn validate(self) -> Result { + match (self.x, self.y) { + (None, None) => Err(GerberError::EmptyCoordinates), + (Some(x), Some(y)) => { + x.validate(&self.format)?; + y.validate(&self.format)?; + Ok(self) + } + _ => Ok(self), + } + } + pub fn at_x(x: T, format: CoordinateFormat) -> Self where T: IntoOptionalCoordinate, @@ -523,19 +551,12 @@ mod test { macro_rules! assert_coords { ($coords:expr, $result:expr) => {{ assert_partial_code!($coords, $result); + assert!($coords.validate().is_ok()); }}; } let cf44 = CoordinateFormat::new(4, 4); let cf46 = CoordinateFormat::new(4, 6); assert_coords!(Coordinates::new(10, 20, cf44), "X100000Y200000"); - assert_coords!( - Coordinates { - x: None, - y: None, - format: cf44 - }, - "" - ); // TODO should we catch this? assert_coords!(Coordinates::at_x(10, cf44), "X100000"); assert_coords!(Coordinates::at_x(Some(10), cf44), "X100000"); assert_coords!(Coordinates::at_y(20, cf46), "Y20000000"); @@ -544,25 +565,67 @@ mod test { assert_coords!(Coordinates::new(Some(0), Some(-400), cf44), "X0Y-4000000"); } + #[test] + fn invalid_coordinates() { + let cf44 = CoordinateFormat::new(4, 4); + let coordinates = Coordinates { + x: None, + y: None, + format: cf44, + }; + + assert!(matches!( + coordinates.validate(), + Err(GerberError::EmptyCoordinates) + )); + + let cf23 = CoordinateFormat::new(2, 3); + let bad = CoordinateNumber::try_from(100.001).unwrap(); + let good = CoordinateNumber::try_from(99.999).unwrap(); + + assert!(bad.validate(&cf23).is_err()); + + let coordinates = Coordinates { + x: Some(bad), + y: Some(good), + format: cf23, + }; + assert!(matches!( + coordinates.validate(), + Err(GerberError::CoordinateFormatError(_)) + )); + let coordinates = Coordinates { + x: Some(good), + y: Some(bad), + format: cf23, + }; + assert!(matches!( + coordinates.validate(), + Err(GerberError::CoordinateFormatError(_)) + )); + let coordinates = Coordinates { + x: Some(bad), + y: Some(bad), + format: cf23, + }; + assert!(matches!( + coordinates.validate(), + Err(GerberError::CoordinateFormatError(_)) + )); + } + #[test] fn test_offset() { macro_rules! assert_coords { ($coords:expr, $result:expr) => {{ assert_partial_code!($coords, $result); + assert!($coords.validate().is_ok()); }}; } let cf44 = CoordinateFormat::new(4, 4); let cf55 = CoordinateFormat::new(5, 5); let cf66 = CoordinateFormat::new(6, 6); assert_coords!(CoordinateOffset::new(10, 20, cf44), "I100000J200000"); - assert_coords!( - CoordinateOffset { - x: None, - y: None, - format: cf44 - }, - "" - ); // TODO should we catch this? assert_coords!(CoordinateOffset::at_x(Some(10), cf66), "I10000000"); assert_coords!(CoordinateOffset::at_x(10, cf66), "I10000000"); assert_coords!(CoordinateOffset::at_y(Some(20), cf55), "J2000000"); @@ -574,6 +637,55 @@ mod test { ); } + #[test] + fn invalid_offset() { + let cf44 = CoordinateFormat::new(4, 4); + let coordinates = CoordinateOffset { + x: None, + y: None, + format: cf44, + }; + + assert!(matches!( + coordinates.validate(), + Err(GerberError::EmptyCoordinates) + )); + + let cf23 = CoordinateFormat::new(2, 3); + let bad = CoordinateNumber::try_from(100.001).unwrap(); + let good = CoordinateNumber::try_from(99.999).unwrap(); + + assert!(bad.validate(&cf23).is_err()); + + let coordinates = CoordinateOffset { + x: Some(bad), + y: Some(good), + format: cf23, + }; + assert!(matches!( + coordinates.validate(), + Err(GerberError::CoordinateFormatError(_)) + )); + let coordinates = CoordinateOffset { + x: Some(good), + y: Some(bad), + format: cf23, + }; + assert!(matches!( + coordinates.validate(), + Err(GerberError::CoordinateFormatError(_)) + )); + let coordinates = CoordinateOffset { + x: Some(bad), + y: Some(bad), + format: cf23, + }; + assert!(matches!( + coordinates.validate(), + Err(GerberError::CoordinateFormatError(_)) + )); + } + #[test] fn test_validate_too_large_for_format() { // %FSLAX23Y23*% diff --git a/src/errors.rs b/src/errors.rs index 15f41fbe..c39ecfc4 100644 --- a/src/errors.rs +++ b/src/errors.rs @@ -20,6 +20,9 @@ pub enum GerberError { #[error("I/O error during code generation")] IoError(#[from] IoError), + + #[error("Empty coordinates")] + EmptyCoordinates, } pub type GerberResult = Result; diff --git a/src/function_codes.rs b/src/function_codes.rs index b18411fe..bb387171 100644 --- a/src/function_codes.rs +++ b/src/function_codes.rs @@ -73,11 +73,14 @@ impl GerberCode for MCode { #[derive(Debug, Clone, PartialEq, Eq)] pub enum Operation { /// D01 Command - Interpolate(Coordinates, Option), + /// `D01 = ['X' integer] ['Y' integer] ['I' integer 'J' integer] 'D01*';` + Interpolate(Option, Option), /// D02 Command - Move(Coordinates), + /// `['X' integer] ['Y' integer] 'D02*';` + Move(Option), /// D03 Command - Flash(Coordinates), + /// `['X' integer] ['Y' integer] 'D03*';` + Flash(Option), } impl GerberCode for Operation { diff --git a/src/lib.rs b/src/lib.rs index 4d38420d..5bc9afa2 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -115,15 +115,18 @@ mod serialization_tests { fn test_operation_interpolate() { let cf = CoordinateFormat::new(2, 5); let c1 = Operation::Interpolate( - Coordinates::new(1, 2, cf), + Some(Coordinates::new(1, 2, cf)), Some(CoordinateOffset::new(5, 10, cf)), ); assert_code!(c1, "X100000Y200000I500000J1000000D01*\n"); - let c2 = Operation::Interpolate(Coordinates::at_y(-2, CoordinateFormat::new(4, 4)), None); + let c2 = Operation::Interpolate( + Some(Coordinates::at_y(-2, CoordinateFormat::new(4, 4))), + None, + ); assert_code!(c2, "Y-20000D01*\n"); let cf = CoordinateFormat::new(4, 4); let c3 = Operation::Interpolate( - Coordinates::at_x(1, cf), + Some(Coordinates::at_x(1, cf)), Some(CoordinateOffset::at_y(2, cf)), ); assert_code!(c3, "X10000J20000D01*\n"); @@ -131,13 +134,13 @@ mod serialization_tests { #[test] fn test_operation_move() { - let c = Operation::Move(Coordinates::new(23, 42, CoordinateFormat::new(6, 4))); + let c = Operation::Move(Some(Coordinates::new(23, 42, CoordinateFormat::new(6, 4)))); assert_code!(c, "X230000Y420000D02*\n"); } #[test] fn test_operation_flash() { - let c = Operation::Flash(Coordinates::new(23, 42, CoordinateFormat::new(4, 4))); + let c = Operation::Flash(Some(Coordinates::new(23, 42, CoordinateFormat::new(4, 4)))); assert_code!(c, "X230000Y420000D03*\n"); }