From 03c92a1184ba9a13cab074c72ad190c66585de56 Mon Sep 17 00:00:00 2001
From: Danny McClanahan <1305167+cosmicexplorer@users.noreply.github.com>
Date: Sat, 18 May 2024 04:13:11 -0400
Subject: [PATCH] add to_and_from_le! macro

---
 src/spec.rs  | 156 ++++++++++++++++-----------------------------------
 src/types.rs | 126 +++++++++++------------------------------
 2 files changed, 79 insertions(+), 203 deletions(-)

diff --git a/src/spec.rs b/src/spec.rs
index fee4d2dc..26c9d4a2 100644
--- a/src/spec.rs
+++ b/src/spec.rs
@@ -143,6 +143,24 @@ macro_rules! to_le {
     };
 }
 
+/* TODO: derive macro to generate these fields? */
+/// Implement `from_le()` and `to_le()`, providing the field specification to both macros
+/// and methods.
+macro_rules! to_and_from_le {
+    ($($args:tt),+ $(,)?) => {
+        #[inline(always)]
+        fn from_le(mut self) -> Self {
+            from_le![self, [$($args),+]];
+            self
+        }
+        #[inline(always)]
+        fn to_le(mut self) -> Self {
+            to_le![self, [$($args),+]];
+            self
+        }
+    };
+}
+
 #[derive(Copy, Clone, Debug)]
 #[repr(packed)]
 pub struct Zip32CDEBlock {
@@ -166,41 +184,16 @@ impl Block for Zip32CDEBlock {
 
     const ERROR: ZipError = ZipError::InvalidArchive("Invalid digital signature header");
 
-    #[inline(always)]
-    fn from_le(mut self) -> Self {
-        from_le![
-            self,
-            [
-                (magic, Magic),
-                (disk_number, u16),
-                (disk_with_central_directory, u16),
-                (number_of_files_on_this_disk, u16),
-                (number_of_files, u16),
-                (central_directory_size, u32),
-                (central_directory_offset, u32),
-                (zip_file_comment_length, u16)
-            ]
-        ];
-        self
-    }
-
-    #[inline(always)]
-    fn to_le(mut self) -> Self {
-        to_le![
-            self,
-            [
-                (magic, Magic),
-                (disk_number, u16),
-                (disk_with_central_directory, u16),
-                (number_of_files_on_this_disk, u16),
-                (number_of_files, u16),
-                (central_directory_size, u32),
-                (central_directory_offset, u32),
-                (zip_file_comment_length, u16)
-            ]
-        ];
-        self
-    }
+    to_and_from_le![
+        (magic, Magic),
+        (disk_number, u16),
+        (disk_with_central_directory, u16),
+        (number_of_files_on_this_disk, u16),
+        (number_of_files, u16),
+        (central_directory_size, u32),
+        (central_directory_offset, u32),
+        (zip_file_comment_length, u16)
+    ];
 }
 
 #[derive(Debug)]
@@ -368,33 +361,12 @@ impl Block for Zip64CDELocatorBlock {
     const ERROR: ZipError =
         ZipError::InvalidArchive("Invalid zip64 locator digital signature header");
 
-    #[inline(always)]
-    fn from_le(mut self) -> Self {
-        from_le![
-            self,
-            [
-                (magic, Magic),
-                (disk_with_central_directory, u32),
-                (end_of_central_directory_offset, u64),
-                (number_of_disks, u32),
-            ]
-        ];
-        self
-    }
-
-    #[inline(always)]
-    fn to_le(mut self) -> Self {
-        to_le![
-            self,
-            [
-                (magic, Magic),
-                (disk_with_central_directory, u32),
-                (end_of_central_directory_offset, u64),
-                (number_of_disks, u32),
-            ]
-        ];
-        self
-    }
+    to_and_from_le![
+        (magic, Magic),
+        (disk_with_central_directory, u32),
+        (end_of_central_directory_offset, u64),
+        (number_of_disks, u32),
+    ];
 }
 
 pub struct Zip64CentralDirectoryEndLocator {
@@ -463,45 +435,18 @@ impl Block for Zip64CDEBlock {
 
     const ERROR: ZipError = ZipError::InvalidArchive("Invalid digital signature header");
 
-    #[inline(always)]
-    fn from_le(mut self) -> Self {
-        from_le![
-            self,
-            [
-                (magic, Magic),
-                (record_size, u64),
-                (version_made_by, u16),
-                (version_needed_to_extract, u16),
-                (disk_number, u32),
-                (disk_with_central_directory, u32),
-                (number_of_files_on_this_disk, u64),
-                (number_of_files, u64),
-                (central_directory_size, u64),
-                (central_directory_offset, u64),
-            ]
-        ];
-        self
-    }
-
-    #[inline(always)]
-    fn to_le(mut self) -> Self {
-        to_le![
-            self,
-            [
-                (magic, Magic),
-                (record_size, u64),
-                (version_made_by, u16),
-                (version_needed_to_extract, u16),
-                (disk_number, u32),
-                (disk_with_central_directory, u32),
-                (number_of_files_on_this_disk, u64),
-                (number_of_files, u64),
-                (central_directory_size, u64),
-                (central_directory_offset, u64),
-            ]
-        ];
-        self
-    }
+    to_and_from_le![
+        (magic, Magic),
+        (record_size, u64),
+        (version_made_by, u16),
+        (version_needed_to_extract, u16),
+        (disk_number, u32),
+        (disk_with_central_directory, u32),
+        (number_of_files_on_this_disk, u64),
+        (number_of_files, u64),
+        (central_directory_size, u64),
+        (central_directory_offset, u64),
+    ];
 }
 
 pub struct Zip64CentralDirectoryEnd {
@@ -730,14 +675,7 @@ mod test {
 
         const ERROR: ZipError = ZipError::InvalidArchive("unreachable");
 
-        fn from_le(mut self) -> Self {
-            from_le![self, [(magic, Magic), (file_name_length, u16)]];
-            self
-        }
-        fn to_le(mut self) -> Self {
-            to_le![self, [(magic, Magic), (file_name_length, u16)]];
-            self
-        }
+        to_and_from_le![(magic, Magic), (file_name_length, u16)];
     }
 
     /// Demonstrate that a block object can be safely written to memory and deserialized back out.
diff --git a/src/types.rs b/src/types.rs
index 8452fef1..74d60d74 100644
--- a/src/types.rs
+++ b/src/types.rs
@@ -820,59 +820,25 @@ impl Block for ZipEntryBlock {
 
     const ERROR: ZipError = ZipError::InvalidArchive("Invalid Central Directory header");
 
-    #[inline(always)]
-    fn from_le(mut self) -> Self {
-        from_le![
-            self,
-            [
-                (magic, spec::Magic),
-                (version_made_by, u16),
-                (version_to_extract, u16),
-                (flags, u16),
-                (compression_method, u16),
-                (last_mod_time, u16),
-                (last_mod_date, u16),
-                (crc32, u32),
-                (compressed_size, u32),
-                (uncompressed_size, u32),
-                (file_name_length, u16),
-                (extra_field_length, u16),
-                (file_comment_length, u16),
-                (disk_number, u16),
-                (internal_file_attributes, u16),
-                (external_file_attributes, u32),
-                (offset, u32),
-            ]
-        ];
-        self
-    }
-
-    #[inline(always)]
-    fn to_le(mut self) -> Self {
-        to_le![
-            self,
-            [
-                (magic, spec::Magic),
-                (version_made_by, u16),
-                (version_to_extract, u16),
-                (flags, u16),
-                (compression_method, u16),
-                (last_mod_time, u16),
-                (last_mod_date, u16),
-                (crc32, u32),
-                (compressed_size, u32),
-                (uncompressed_size, u32),
-                (file_name_length, u16),
-                (extra_field_length, u16),
-                (file_comment_length, u16),
-                (disk_number, u16),
-                (internal_file_attributes, u16),
-                (external_file_attributes, u32),
-                (offset, u32),
-            ]
-        ];
-        self
-    }
+    to_and_from_le![
+        (magic, spec::Magic),
+        (version_made_by, u16),
+        (version_to_extract, u16),
+        (flags, u16),
+        (compression_method, u16),
+        (last_mod_time, u16),
+        (last_mod_date, u16),
+        (crc32, u32),
+        (compressed_size, u32),
+        (uncompressed_size, u32),
+        (file_name_length, u16),
+        (extra_field_length, u16),
+        (file_comment_length, u16),
+        (disk_number, u16),
+        (internal_file_attributes, u16),
+        (external_file_attributes, u32),
+        (offset, u32),
+    ];
 }
 
 #[derive(Copy, Clone, Debug)]
@@ -901,47 +867,19 @@ impl Block for ZipLocalEntryBlock {
 
     const ERROR: ZipError = ZipError::InvalidArchive("Invalid local file header");
 
-    #[inline(always)]
-    fn from_le(mut self) -> Self {
-        from_le![
-            self,
-            [
-                (magic, spec::Magic),
-                (version_made_by, u16),
-                (flags, u16),
-                (compression_method, u16),
-                (last_mod_time, u16),
-                (last_mod_date, u16),
-                (crc32, u32),
-                (compressed_size, u32),
-                (uncompressed_size, u32),
-                (file_name_length, u16),
-                (extra_field_length, u16),
-            ]
-        ];
-        self
-    }
-
-    #[inline(always)]
-    fn to_le(mut self) -> Self {
-        to_le![
-            self,
-            [
-                (magic, spec::Magic),
-                (version_made_by, u16),
-                (flags, u16),
-                (compression_method, u16),
-                (last_mod_time, u16),
-                (last_mod_date, u16),
-                (crc32, u32),
-                (compressed_size, u32),
-                (uncompressed_size, u32),
-                (file_name_length, u16),
-                (extra_field_length, u16),
-            ]
-        ];
-        self
-    }
+    to_and_from_le![
+        (magic, spec::Magic),
+        (version_made_by, u16),
+        (flags, u16),
+        (compression_method, u16),
+        (last_mod_time, u16),
+        (last_mod_date, u16),
+        (crc32, u32),
+        (compressed_size, u32),
+        (uncompressed_size, u32),
+        (file_name_length, u16),
+        (extra_field_length, u16),
+    ];
 }
 
 /// The encryption specification used to encrypt a file with AES.