Browse Source

Initial diff

Kevin Lee 4 months ago
parent
commit
65fc461f66

+ 23 - 0
Cargo.lock

@@ -163,6 +163,28 @@ version = "1.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7"
 
+[[package]]
+name = "diff-struct"
+version = "0.5.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "79aac083112b31f7cb768b24b893dc0c34c296a4b06b250c407bfd495e42075c"
+dependencies = [
+ "diff_derive",
+ "num",
+ "serde",
+]
+
+[[package]]
+name = "diff_derive"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "fe165e7ead196bbbf44c7ce11a7a21157b5c002ce46d7098ff9c556784a4912d"
+dependencies = [
+ "proc-macro2",
+ "quote",
+ "syn 1.0.109",
+]
+
 [[package]]
 name = "either"
 version = "1.9.0"
@@ -205,6 +227,7 @@ dependencies = [
  "binrw",
  "clap",
  "clap-verbosity-flag",
+ "diff-struct",
  "env_logger",
  "log",
  "modular-bitfield",

+ 1 - 0
Cargo.toml

@@ -17,6 +17,7 @@ path = "src/main.rs"
 binrw = "0.13.3"
 clap = { version = "4.4.11", features = ["derive"] }
 clap-verbosity-flag = "2.1.1"
+diff-struct = "0.5.3"
 env_logger = "0.10.1"
 log = "0.4.20"
 modular-bitfield = "0.11.2"

+ 7 - 7
README.md

@@ -23,8 +23,8 @@ Three operations are supported for patching pen settings:
 1. Setting values of specific fields for a given pen:
 
 ``` yaml
-Pens: 
-  - !Patch
+Ops: 
+  - !PatchPen
     Pen: 0                  # Required - target pen
     Color: [127, 127, 127]  # Optional - target pen RGB color
     Enabled: true           # Optional - target pen enable flag
@@ -37,8 +37,8 @@ Pens:
 2. Cloning one pen to another (and optionally override settings):
 
 ``` yaml
-Pens: 
-  - !Clone
+Ops: 
+  - !ClonePen
     From: 0                 # Required - source pen
     To: 1                   # Required - target pen
     # Color: [64, 64, 64]   # Optional - target pen RGB color
@@ -49,11 +49,11 @@ Pens:
     # Frequency: 10000      # Optional - target pen frequency
 ```
 
-3. Incrementing a specific field across a sequence of pens:
+3. Incrementing a specific field by some value across a sequence of pens:
 
 ``` yaml
-Pens: 
-  - !Pattern
+Ops: 
+  - !PatternPen
     From: 1                 # Required - starting pen to copy settings from
     To: 5                   # Required - ending pen to stop at (inclusive)
     # Field: !Loops 1         # Choose one

+ 44 - 35
src/ezcad/array_of.rs

@@ -1,4 +1,5 @@
 use binrw::{binrw, BinRead, BinWrite};
+use diff::Diff;
 use num::Num;
 use std::{
     fmt::{Debug, Display},
@@ -6,25 +7,20 @@ use std::{
     ops::{Deref, DerefMut},
 };
 
-/// Supertrait to simplify constraints
-pub trait BinReadWrite:
-    for<'a> BinRead<Args<'a> = ()> + for<'a> BinWrite<Args<'a> = ()> + 'static
-{
-}
-impl<T> BinReadWrite for T where
-    T: for<'a> BinRead<Args<'a> = ()> + for<'a> BinWrite<Args<'a> = ()> + 'static
-{
-}
-
 /// Wrapper to prefix array of primitives (u8/u32/etc)
 #[binrw]
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 pub struct ArrayOfPrimitive<T, S = u32>
 where
     // Static bounds due to https://github.com/jam1garner/binrw/issues/199
-    T: BinReadWrite + Num,
-    S: BinReadWrite,
-    S: TryFrom<usize> + Display + Debug + Copy + Clone,
+    T: for<'a> BinRead<Args<'a> = ()> + for<'a> BinWrite<Args<'a> = ()>,
+    T: Debug + Diff + PartialEq + Num + 'static,
+    <T as Diff>::Repr: Debug + PartialEq,
+    S: for<'a> BinRead<Args<'a> = ()> + for<'a> BinWrite<Args<'a> = ()>,
+    S: TryFrom<usize> + Copy + Clone + Debug + Display + Diff + PartialEq + 'static,
     <S as TryFrom<usize>>::Error: Display + Debug + Send + Sync,
     usize: TryFrom<S>,
 {
@@ -41,10 +37,11 @@ where
 
 impl<T, S> Debug for ArrayOfPrimitive<T, S>
 where
-    T: BinReadWrite + Num,
-    S: BinReadWrite,
-    T: Debug,
-    S: TryFrom<usize> + Display + Debug + Copy + Clone,
+    T: for<'a> BinRead<Args<'a> = ()> + for<'a> BinWrite<Args<'a> = ()>,
+    T: Debug + Diff + PartialEq + Num + 'static,
+    <T as Diff>::Repr: Debug + PartialEq,
+    S: for<'a> BinRead<Args<'a> = ()> + for<'a> BinWrite<Args<'a> = ()>,
+    S: TryFrom<usize> + Copy + Clone + Debug + Display + Diff + PartialEq + 'static,
     <S as TryFrom<usize>>::Error: Display + Debug + Send + Sync,
     usize: TryFrom<S>,
 {
@@ -55,13 +52,18 @@ where
 
 /// Wrapper to prefix array of single non-primitive type
 #[binrw]
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 pub struct ArrayOf<T, S = u32>
 where
     // Static bounds due to https://github.com/jam1garner/binrw/issues/199
-    T: BinReadWrite,
-    S: BinReadWrite,
-    S: TryFrom<usize> + Display + Debug + Copy + Clone,
+    T: for<'a> BinRead<Args<'a> = ()> + for<'a> BinWrite<Args<'a> = ()>,
+    T: Debug + Diff + PartialEq + 'static,
+    <T as Diff>::Repr: Debug + PartialEq,
+    S: for<'a> BinRead<Args<'a> = ()> + for<'a> BinWrite<Args<'a> = ()>,
+    S: TryFrom<usize> + Copy + Clone + Debug + Display + Diff + PartialEq + 'static,
     <S as TryFrom<usize>>::Error: Display + Debug + Send + Sync,
     usize: TryFrom<S>,
 {
@@ -78,10 +80,11 @@ where
 
 impl<T, S> Debug for ArrayOf<T, S>
 where
-    T: BinReadWrite,
-    S: BinReadWrite,
-    T: Debug,
-    S: TryFrom<usize> + Display + Debug + Copy + Clone,
+    T: for<'a> BinRead<Args<'a> = ()> + for<'a> BinWrite<Args<'a> = ()>,
+    T: Debug + Diff + PartialEq + 'static,
+    <T as Diff>::Repr: Debug + PartialEq,
+    S: for<'a> BinRead<Args<'a> = ()> + for<'a> BinWrite<Args<'a> = ()>,
+    S: TryFrom<usize> + Copy + Clone + Debug + Display + Diff + PartialEq + 'static,
     <S as TryFrom<usize>>::Error: Display + Debug + Send + Sync,
     usize: TryFrom<S>,
 {
@@ -92,9 +95,11 @@ where
 
 impl<T, S> Deref for ArrayOf<T, S>
 where
-    T: BinReadWrite,
-    S: BinReadWrite,
-    S: TryFrom<usize> + Display + Debug + Copy + Clone,
+    T: for<'a> BinRead<Args<'a> = ()> + for<'a> BinWrite<Args<'a> = ()>,
+    T: Debug + Diff + PartialEq + 'static,
+    <T as Diff>::Repr: Debug + PartialEq,
+    S: for<'a> BinRead<Args<'a> = ()> + for<'a> BinWrite<Args<'a> = ()>,
+    S: TryFrom<usize> + Copy + Clone + Debug + Display + Diff + PartialEq + 'static,
     <S as TryFrom<usize>>::Error: Display + Debug + Send + Sync,
     usize: TryFrom<S>,
 {
@@ -107,9 +112,11 @@ where
 
 impl<T, S> DerefMut for ArrayOf<T, S>
 where
-    T: BinReadWrite,
-    S: BinReadWrite,
-    S: TryFrom<usize> + Display + Debug + Copy + Clone,
+    T: for<'a> BinRead<Args<'a> = ()> + for<'a> BinWrite<Args<'a> = ()>,
+    T: Debug + Diff + PartialEq + 'static,
+    <T as Diff>::Repr: Debug + PartialEq,
+    S: for<'a> BinRead<Args<'a> = ()> + for<'a> BinWrite<Args<'a> = ()>,
+    S: TryFrom<usize> + Copy + Clone + Debug + Display + Diff + PartialEq + 'static,
     <S as TryFrom<usize>>::Error: Display + Debug + Send + Sync,
     usize: TryFrom<S>,
 {
@@ -120,9 +127,11 @@ where
 
 impl<T, S> From<Vec<T>> for ArrayOf<T, S>
 where
-    T: BinReadWrite,
-    S: BinReadWrite,
-    S: TryFrom<usize> + Display + Debug + Copy + Clone,
+    T: for<'a> BinRead<Args<'a> = ()> + for<'a> BinWrite<Args<'a> = ()>,
+    T: Debug + Diff + PartialEq + 'static,
+    <T as Diff>::Repr: Debug + PartialEq,
+    S: for<'a> BinRead<Args<'a> = ()> + for<'a> BinWrite<Args<'a> = ()>,
+    S: TryFrom<usize> + Copy + Clone + Debug + Display + Diff + PartialEq + 'static,
     <S as TryFrom<usize>>::Error: Display + Debug + Send + Sync,
     usize: TryFrom<S>,
 {

+ 17 - 3
src/ezcad/field_of.rs

@@ -1,4 +1,5 @@
 use binrw::{binrw, BinRead, BinWrite};
+use diff::Diff;
 use std::{
     fmt::{Debug, Display},
     mem::size_of,
@@ -7,11 +8,16 @@ use std::{
 
 /// Wrapper to prefix arbitrary types with size of type as u32
 #[binrw]
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 pub struct FieldOf<T>
 where
     T: for<'a> BinRead<Args<'a> = ()>,
     T: for<'a> BinWrite<Args<'a> = ()>,
+    T: Diff,
+    <T as Diff>::Repr: Debug + PartialEq,
 {
     // Temporary variable that must match size of value
     #[br(temp, assert(size == size_of::<T>().try_into().unwrap()))]
@@ -25,6 +31,8 @@ impl<T> Deref for FieldOf<T>
 where
     T: for<'a> BinRead<Args<'a> = ()>,
     T: for<'a> BinWrite<Args<'a> = ()>,
+    T: Diff,
+    <T as Diff>::Repr: Debug + PartialEq,
 {
     type Target = T;
 
@@ -37,6 +45,8 @@ impl<T> DerefMut for FieldOf<T>
 where
     T: for<'a> BinRead<Args<'a> = ()>,
     T: for<'a> BinWrite<Args<'a> = ()>,
+    T: Diff,
+    <T as Diff>::Repr: Debug + PartialEq,
 {
     fn deref_mut(&mut self) -> &mut Self::Target {
         &mut self.value
@@ -47,7 +57,8 @@ impl<T> Debug for FieldOf<T>
 where
     T: for<'a> BinRead<Args<'a> = ()>,
     T: for<'a> BinWrite<Args<'a> = ()>,
-    T: Debug,
+    T: Diff + Debug,
+    <T as Diff>::Repr: Debug + PartialEq,
 {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(f, "{:?}", self.value)
@@ -58,7 +69,8 @@ impl<T> Display for FieldOf<T>
 where
     T: for<'a> BinRead<Args<'a> = ()>,
     T: for<'a> BinWrite<Args<'a> = ()>,
-    T: Display,
+    T: Diff + Display,
+    <T as Diff>::Repr: Debug + PartialEq,
 {
     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
         write!(f, "{}", self.value)
@@ -69,6 +81,8 @@ impl<T> From<T> for FieldOf<T>
 where
     T: for<'a> BinRead<Args<'a> = ()>,
     T: for<'a> BinWrite<Args<'a> = ()>,
+    T: Diff,
+    <T as Diff>::Repr: Debug + PartialEq,
 {
     fn from(value: T) -> Self {
         Self { value }

+ 13 - 3
src/ezcad/layer.rs

@@ -1,4 +1,5 @@
 use binrw::{BinRead, BinWrite};
+use diff::Diff;
 
 use crate::{
     array_of::ArrayOf,
@@ -6,7 +7,10 @@ use crate::{
     types::{Field, WString, F64, U16, U32},
 };
 
-#[derive(BinRead, BinWrite, Debug)]
+#[derive(BinRead, BinWrite, Debug, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 #[brw(magic(17u32))] // Number of fields within this struct
 pub struct LayerSettings1 {
     _unknown_1: [Field; 3],
@@ -18,7 +22,10 @@ pub struct LayerSettings1 {
     _unknown_3: [Field; 9],
 }
 
-#[derive(BinRead, BinWrite, Debug)]
+#[derive(BinRead, BinWrite, Debug, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 #[brw(magic(151u32))] // Number of fields within this struct
 pub struct LayerSettings2 {
     _unknown_4: [Field; 54],
@@ -39,7 +46,10 @@ pub struct LayerSettings2 {
     footer: u32,
 }
 
-#[derive(BinRead, BinWrite, Debug)]
+#[derive(BinRead, BinWrite, Debug, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 pub struct Layer {
     pub pre: LayerSettings1,
     pub objects: ArrayOf<Object>,

+ 5 - 1
src/ezcad/objects/circle.rs

@@ -1,6 +1,7 @@
 use std::fmt::Debug;
 
 use binrw::{BinRead, BinWrite};
+use diff::Diff;
 
 use crate::{
     field_of::FieldOf,
@@ -9,7 +10,10 @@ use crate::{
 
 use super::ObjectCore;
 
-#[derive(BinRead, BinWrite)]
+#[derive(BinRead, BinWrite, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 pub struct Circle {
     pub core: ObjectCore,
     #[brw(magic(6u32))] // Number of following fields in struct

+ 5 - 1
src/ezcad/objects/ellipse.rs

@@ -1,6 +1,7 @@
 use std::fmt::Debug;
 
 use binrw::{BinRead, BinWrite};
+use diff::Diff;
 
 use crate::{
     field_of::FieldOf,
@@ -9,7 +10,10 @@ use crate::{
 
 use super::ObjectCore;
 
-#[derive(BinRead, BinWrite)]
+#[derive(BinRead, BinWrite, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 pub struct Ellipse {
     pub core: ObjectCore,
     #[brw(magic(8u32))] // Number of following fields in struct

+ 21 - 5
src/ezcad/objects/hatch.rs

@@ -1,6 +1,7 @@
 use std::fmt::Debug;
 
 use binrw::{BinRead, BinWrite};
+use diff::Diff;
 use modular_bitfield::{
     bitfield,
     specifiers::{B1, B2, B21, B4},
@@ -15,7 +16,10 @@ use crate::{
 use super::{line::Lines, Object, ObjectCore};
 
 #[bitfield(bits = 32)]
-#[derive(BinRead, BinWrite, Debug, Copy, Clone)]
+#[derive(BinRead, BinWrite, Copy, Clone, Debug, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 #[br(map = Self::from_bytes)]
 #[bw(map = |&x| Self::into_bytes(x))]
 pub struct ObjectFlags {
@@ -33,12 +37,18 @@ pub struct ObjectFlags {
     __: B21,
 }
 
-#[derive(BinRead, BinWrite, Debug)]
+#[derive(BinRead, BinWrite, Debug, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 pub struct HatchLine {
     lines: ArrayOf<Lines>,
 }
 
-#[derive(BinRead, BinWrite)]
+#[derive(BinRead, BinWrite, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 #[brw(magic(46u32))] // Number of fields in this struct
 pub struct HatchSettings1 {
     pub mark_contour: U32,
@@ -86,7 +96,10 @@ impl Debug for HatchSettings1 {
     }
 }
 
-#[derive(BinRead, BinWrite)]
+#[derive(BinRead, BinWrite, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 #[brw(magic(15u32))] // Number of fields in this struct
 pub struct HatchSettings2 {
     pub count: U32,
@@ -125,7 +138,10 @@ impl Debug for HatchSettings2 {
     }
 }
 
-#[derive(BinRead, BinWrite)]
+#[derive(BinRead, BinWrite, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 pub struct Hatch {
     pub core: ObjectCore,
     pub outline: ArrayOf<Object>,

+ 9 - 2
src/ezcad/objects/line.rs

@@ -1,10 +1,14 @@
 use binrw::{BinRead, BinWrite};
+use diff::Diff;
 
 use crate::{array_of::ArrayOf, types::Point};
 
 use super::ObjectCore;
 
-#[derive(BinRead, BinWrite, Debug)]
+#[derive(BinRead, BinWrite, Debug, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 pub enum LineType {
     #[brw(magic = 0x0001u16)]
     Point { _zero: u32, point: Point },
@@ -14,7 +18,10 @@ pub enum LineType {
     Bezier { _zero: u32, points: ArrayOf<Point> },
 }
 
-#[derive(BinRead, BinWrite, Debug)]
+#[derive(BinRead, BinWrite, Debug, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 pub struct Lines {
     pub core: ObjectCore,
     pub lines: ArrayOf<LineType, u64>,

+ 13 - 3
src/ezcad/objects/mod.rs

@@ -1,6 +1,7 @@
 use std::fmt::Debug;
 
 use binrw::{BinRead, BinWrite};
+use diff::Diff;
 use modular_bitfield::{
     bitfield,
     specifiers::{B1, B14},
@@ -24,7 +25,10 @@ pub mod polygon;
 pub mod rectangle;
 
 #[bitfield(bits = 16)]
-#[derive(BinRead, BinWrite, Debug, Copy, Clone)]
+#[derive(BinRead, BinWrite, Copy, Clone, Debug, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 #[br(map = Self::from_bytes)]
 #[bw(map = |&x| Self::into_bytes(x))]
 pub struct ObjectFlags {
@@ -35,7 +39,10 @@ pub struct ObjectFlags {
 }
 
 /// Core properties defined for all object types
-#[derive(BinRead, BinWrite)]
+#[derive(BinRead, BinWrite, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 #[brw(magic(17u32))]
 pub struct ObjectCore {
     pub pen: U32,
@@ -71,7 +78,10 @@ impl Debug for ObjectCore {
     }
 }
 
-#[derive(BinRead, BinWrite, Debug)]
+#[derive(BinRead, BinWrite, Debug, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 pub enum Object {
     #[brw(magic = 1u32)]
     Curve(Lines),

+ 5 - 1
src/ezcad/objects/polygon.rs

@@ -1,6 +1,7 @@
 use std::fmt::Debug;
 
 use binrw::{BinRead, BinWrite};
+use diff::Diff;
 
 use crate::{
     field_of::FieldOf,
@@ -9,7 +10,10 @@ use crate::{
 
 use super::ObjectCore;
 
-#[derive(BinRead, BinWrite)]
+#[derive(BinRead, BinWrite, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 pub struct Polygon {
     pub core: ObjectCore,
     #[brw(magic(10u32))] // Number of following fields in struct

+ 5 - 1
src/ezcad/objects/rectangle.rs

@@ -1,6 +1,7 @@
 use std::fmt::Debug;
 
 use binrw::{BinRead, BinWrite};
+use diff::Diff;
 
 use crate::{
     field_of::FieldOf,
@@ -9,7 +10,10 @@ use crate::{
 
 use super::ObjectCore;
 
-#[derive(BinRead, BinWrite)]
+#[derive(BinRead, BinWrite, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 pub struct Rectangle {
     pub core: ObjectCore,
     #[brw(magic(8u32))] // Number of following fields in struct

+ 9 - 2
src/ezcad/pen.rs

@@ -1,6 +1,7 @@
 use std::fmt::Debug;
 
 use binrw::{BinRead, BinWrite, FilePtr64};
+use diff::Diff;
 
 use crate::{
     field_of::FieldOf,
@@ -40,14 +41,20 @@ impl BinWrite for PenHeader {
     }
 }
 
-#[derive(BinRead, BinWrite, Debug)]
+#[derive(BinRead, BinWrite, Debug, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 #[br(import {pen_count: u32})]
 pub struct Pens {
     #[br(count = pen_count)]
     pub pens: Vec<Pen>,
 }
 
-#[derive(BinRead, BinWrite, Clone)]
+#[derive(BinRead, BinWrite, Clone, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 #[brw(magic(236u32))] // Number of fields within this struct
 pub struct Pen {
     pub color: FieldOf<Rgba>,

+ 21 - 5
src/ezcad/types.rs

@@ -1,6 +1,7 @@
 use std::fmt::{Debug, Display};
 
 use binrw::{binrw, BinRead, BinWrite};
+use diff::Diff;
 
 use crate::{array_of::ArrayOfPrimitive, field_of::FieldOf};
 
@@ -12,7 +13,10 @@ pub type U16 = FieldOf<u16>;
 pub type F64 = FieldOf<f64>;
 
 #[binrw]
-#[derive(Clone, PartialEq)]
+#[derive(Clone, Diff, PartialEq)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 pub struct WString {
     // Temporary variable that holds number of elements
     #[br(temp)]
@@ -48,7 +52,10 @@ impl Display for WString {
     }
 }
 
-#[derive(Clone, Debug, PartialEq, BinRead, BinWrite)]
+#[derive(Clone, Debug, Diff, PartialEq, BinRead, BinWrite)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 pub struct Rgba {
     pub red: u8,
     pub green: u8,
@@ -67,13 +74,19 @@ impl From<(u8, u8, u8)> for Rgba {
     }
 }
 
-#[derive(Clone, Debug, PartialEq, BinRead, BinWrite)]
+#[derive(Clone, Debug, Diff, PartialEq, BinRead, BinWrite)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 pub struct Point {
     pub x: f64,
     pub y: f64,
 }
 
-#[derive(Clone, Debug, PartialEq, BinRead, BinWrite, strum::Display)]
+#[derive(Clone, Debug, Diff, PartialEq, BinRead, BinWrite, strum::Display)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 #[brw(repr(u32))]
 #[repr(u32)]
 pub enum WobbleType {
@@ -84,7 +97,10 @@ pub enum WobbleType {
     Hori8 = 4,
 }
 
-#[derive(Clone, Debug, PartialEq, BinRead, BinWrite, strum::Display)]
+#[derive(Clone, Debug, Diff, PartialEq, BinRead, BinWrite, strum::Display)]
+#[diff(attr(
+    #[derive(Debug, PartialEq)]
+))]
 #[brw(repr(u16))]
 #[repr(u16)]
 pub enum ObjectType {

+ 6 - 0
src/main.rs

@@ -3,6 +3,7 @@ use std::{fs::File, path::PathBuf, time::Instant};
 use binrw::{BinRead, BinWriterExt};
 use clap::Parser;
 use clap_verbosity_flag::{InfoLevel, Verbosity};
+use diff::Diff;
 use ezcad::file::EzCadHeader;
 use log::{info, trace};
 
@@ -44,6 +45,11 @@ fn main() {
         EzCadHeader::read_le(&mut input).expect("Failed to parse input file as EZCAD format");
     info!("Input decode time: {:?}", time.elapsed());
 
+    let pen_0 = file.pens_offset.data.pens.get(0).unwrap();
+    let pen_1 = file.pens_offset.data.pens.get(1).unwrap();
+    info!("{:#?}", pen_0.diff(pen_1));
+    // info!("{:?}", diff.color.value.);
+
     // Print info on pens with non-default settings
     for pen in file
         .pens_offset

+ 5 - 1
tests/array_of.rs

@@ -1,6 +1,7 @@
 use std::io::Cursor;
 
 use binrw::{BinRead, BinWrite};
+use diff::Diff;
 use ezcad::array_of::ArrayOf;
 
 #[test]
@@ -33,7 +34,10 @@ fn array_of_le() {
 
 #[test]
 fn array_of_struct() {
-    #[derive(BinRead, BinWrite, Debug, PartialEq, Default)]
+    #[derive(BinRead, BinWrite, Debug, PartialEq, Default, Diff)]
+    #[diff(attr(
+        #[derive(Debug, PartialEq)]
+    ))]
     struct Test {
         a: u16,
         b: u16,

+ 63 - 56
tests/field_of.rs

@@ -1,56 +1,63 @@
-use std::io::Cursor;
-
-use binrw::{BinRead, BinWrite};
-use ezcad::field_of::FieldOf;
-
-#[test]
-fn field_of_be() {
-    #[derive(BinRead, BinWrite, Debug, PartialEq, Default)]
-    struct Test {
-        a: u32,
-        b: u32,
-    }
-
-    let decoded: FieldOf<Test> = FieldOf {
-        value: Test {
-            a: 0x0A0B0C0D,
-            b: 0x01020304,
-        },
-    };
-    let encoded: Vec<u8> = vec![
-        0x00, 0x00, 0x00, 0x08, 0x0A, 0x0B, 0x0C, 0x0D, 0x01, 0x02, 0x03, 0x04,
-    ];
-
-    let mut stream: Cursor<Vec<u8>> = Cursor::new(encoded.clone());
-    assert_eq!(FieldOf::<Test>::read_be(&mut stream).unwrap(), decoded);
-
-    let mut buffer: Cursor<Vec<u8>> = Cursor::new(vec![]);
-    decoded.write_be(&mut buffer).unwrap();
-    assert_eq!(buffer.into_inner(), encoded);
-}
-
-#[test]
-fn field_of_le() {
-    #[derive(BinRead, BinWrite, Debug, PartialEq, Default)]
-    struct Test {
-        a: u32,
-        b: u32,
-    }
-
-    let decoded: FieldOf<Test> = FieldOf {
-        value: Test {
-            a: 0x0A0B0C0D,
-            b: 0x01020304,
-        },
-    };
-    let encoded: Vec<u8> = vec![
-        0x08, 0x00, 0x00, 0x00, 0x0D, 0x0C, 0x0B, 0x0A, 0x04, 0x03, 0x02, 0x01,
-    ];
-
-    let mut stream: Cursor<Vec<u8>> = Cursor::new(encoded.clone());
-    assert_eq!(FieldOf::<Test>::read_le(&mut stream).unwrap(), decoded);
-
-    let mut buffer: Cursor<Vec<u8>> = Cursor::new(vec![]);
-    decoded.write_le(&mut buffer).unwrap();
-    assert_eq!(buffer.into_inner(), encoded);
-}
+use std::io::Cursor;
+
+use binrw::{BinRead, BinWrite};
+use diff::Diff;
+use ezcad::field_of::FieldOf;
+
+#[test]
+fn field_of_be() {
+    #[derive(BinRead, BinWrite, Debug, PartialEq, Default, Diff)]
+    #[diff(attr(
+        #[derive(Debug, PartialEq)]
+    ))]
+    struct Test {
+        a: u32,
+        b: u32,
+    }
+
+    let decoded: FieldOf<Test> = FieldOf {
+        value: Test {
+            a: 0x0A0B0C0D,
+            b: 0x01020304,
+        },
+    };
+    let encoded: Vec<u8> = vec![
+        0x00, 0x00, 0x00, 0x08, 0x0A, 0x0B, 0x0C, 0x0D, 0x01, 0x02, 0x03, 0x04,
+    ];
+
+    let mut stream: Cursor<Vec<u8>> = Cursor::new(encoded.clone());
+    assert_eq!(FieldOf::<Test>::read_be(&mut stream).unwrap(), decoded);
+
+    let mut buffer: Cursor<Vec<u8>> = Cursor::new(vec![]);
+    decoded.write_be(&mut buffer).unwrap();
+    assert_eq!(buffer.into_inner(), encoded);
+}
+
+#[test]
+fn field_of_le() {
+    #[derive(BinRead, BinWrite, Debug, PartialEq, Default, Diff)]
+    #[diff(attr(
+        #[derive(Debug, PartialEq)]
+    ))]
+    struct Test {
+        a: u32,
+        b: u32,
+    }
+
+    let decoded: FieldOf<Test> = FieldOf {
+        value: Test {
+            a: 0x0A0B0C0D,
+            b: 0x01020304,
+        },
+    };
+    let encoded: Vec<u8> = vec![
+        0x08, 0x00, 0x00, 0x00, 0x0D, 0x0C, 0x0B, 0x0A, 0x04, 0x03, 0x02, 0x01,
+    ];
+
+    let mut stream: Cursor<Vec<u8>> = Cursor::new(encoded.clone());
+    assert_eq!(FieldOf::<Test>::read_le(&mut stream).unwrap(), decoded);
+
+    let mut buffer: Cursor<Vec<u8>> = Cursor::new(vec![]);
+    decoded.write_le(&mut buffer).unwrap();
+    assert_eq!(buffer.into_inner(), encoded);
+}