diff --git a/src/game/card/table.rs b/src/game/card/table.rs index 00d3ab2..02f0edc 100644 --- a/src/game/card/table.rs +++ b/src/game/card/table.rs @@ -17,7 +17,7 @@ use crate::{ Bytes, }, io::{address::Data, GameFile}, - util::array_split_mut, + util::{array_split, array_split_mut}, }; use byteorder::{ByteOrder, LittleEndian}; use std::{ @@ -26,6 +26,9 @@ use std::{ }; /// The table storing all cards +/// +/// See the [module containing](self) this struct for more details +/// on where the table is deserialized from and it's features / restrictions. #[derive(PartialEq, Eq, Clone, Debug)] #[derive(serde::Serialize, serde::Deserialize)] pub struct Table { @@ -44,6 +47,7 @@ impl Table { /// Table header size pub const HEADER_BYTE_SIZE: usize = 0x8; /// The magic in the table header + /// = "0ACD" pub const HEADER_MAGIC: u32 = 0x44434130; /// The max size of the card table // TODO: Check the theoretical max, which is currently thought to be `0x14ff5` @@ -59,6 +63,15 @@ impl Table { pub fn card_count(&self) -> usize { self.digimons.len() + self.items.len() + self.digivolves.len() } + + /// Returns the byte size of all cards in this table + #[must_use] + #[rustfmt::skip] + pub fn cards_byte_size(&self) -> usize { + self.digimons .len() * (0x3 + CardType::Digimon .byte_size() + 0x1) + + self.items .len() * (0x3 + CardType::Item .byte_size() + 0x1) + + self.digivolves.len() * (0x3 + CardType::Digivolve.byte_size() + 0x1) + } } impl Table { @@ -69,22 +82,27 @@ impl Table { .map_err(DeserializeError::Seek)?; // Read header - let mut header_bytes = [0u8; 0x8]; + let mut header_bytes = [0u8; Self::HEADER_BYTE_SIZE]; file.read_exact(&mut header_bytes).map_err(DeserializeError::ReadHeader)?; + let header = array_split! {&header_bytes, + magic: [0x4], + + digimons_len: [0x2], + items_len: 1, + digivolves_len: 1, + }; // Check if the magic is right - let magic = LittleEndian::read_u32(&header_bytes[0x0..0x4]); + let magic = LittleEndian::read_u32(header.magic); if magic != Self::HEADER_MAGIC { return Err(DeserializeError::HeaderMagic { magic }); } // Then check the number of each card - let digimon_cards: usize = LittleEndian::read_u16(&header_bytes[0x4..0x6]).into(); - let item_cards: usize = header_bytes[0x6].into(); - let digivolve_cards: usize = header_bytes[0x7].into(); - log::trace!("Found {} digimon cards", digimon_cards); - log::trace!("Found {} item cards", item_cards); - log::trace!("Found {} digivolve cards", digivolve_cards); + let digimon_cards: usize = LittleEndian::read_u16(header.digimons_len).into(); + let item_cards: usize = (*header.items_len).into(); + let digivolve_cards: usize = (*header.digivolves_len).into(); + log::trace!("Found {digimon_cards} digimon, {item_cards} item, {digivolve_cards} digivolve cards"); // And calculate the number of cards let cards_len = digimon_cards + item_cards + digivolve_cards; @@ -93,7 +111,6 @@ impl Table { let table_size = digimon_cards * (0x3 + CardType::Digimon.byte_size() + 0x1) + item_cards * (0x3 + CardType::Item.byte_size() + 0x1) + digivolve_cards * (0x3 + CardType::Digivolve.byte_size() + 0x1); - log::trace!("{} total bytes of cards", table_size); if table_size > Self::MAX_BYTE_SIZE { return Err(DeserializeError::TooManyCards { digimon_cards, @@ -118,7 +135,7 @@ impl Table { let card_id = LittleEndian::read_u16(&card_header_bytes[0x0..0x2]); let card_type = CardType::from_bytes(&card_header_bytes[0x2]).map_err(|err| DeserializeError::UnknownCardType { id: cur_id, err })?; - log::trace!("Found {} with id {}", card_type, card_id); + log::trace!("Found #{}: {}", card_id, card_type); // If the card id isn't what we expected, log warning if usize::from(card_id) != cur_id { @@ -165,9 +182,7 @@ impl Table { /// Serializes this card table to `file`. pub fn serialize(&self, file: &mut GameFile) -> Result<(), SerializeError> { // Get the final table size - let table_size = self.digimons.len() * (0x3 + CardType::Digimon.byte_size() + 0x1) + - self.items.len() * (0x3 + CardType::Item.byte_size() + 0x1) + - self.digivolves.len() * (0x3 + CardType::Digivolve.byte_size() + 0x1); + let table_size = self.cards_byte_size(); // If the total table size is bigger than the max, return Err if table_size > Self::MAX_BYTE_SIZE { @@ -184,118 +199,75 @@ impl Table { // Write header let mut header_bytes = [0u8; 0x8]; - { - let bytes = array_split_mut!(&mut header_bytes, - magic: [0x4], + let header = array_split_mut!(&mut header_bytes, + magic: [0x4], - digimons_len: [0x2], - items_len: 1, - digivolves_len: 1, - ); + digimons_len: [0x2], + items_len: 1, + digivolves_len: 1, + ); - // Set magic - LittleEndian::write_u32(bytes.magic, Self::HEADER_MAGIC); + // Set magic + LittleEndian::write_u32(header.magic, Self::HEADER_MAGIC); - // Write card lens - log::trace!("Writing {} digimon cards", self.digimons.len()); - log::trace!("Writing {} item cards", self.items.len()); - log::trace!("Writing {} digivolve cards", self.digivolves.len()); - LittleEndian::write_u16( - bytes.digimons_len, - self.digimons.len().try_into().expect("Number of digimon cards exceeded `u16`"), - ); - *bytes.items_len = self.items.len().try_into().expect("Number of item cards exceeded `u8`"); - *bytes.digivolves_len = self.digivolves.len().try_into().expect("Number of digivolve cards exceeded `u8`"); - } + // Write card lens + log::trace!("Writing {} digimon cards", self.digimons.len()); + log::trace!("Writing {} item cards", self.items.len()); + log::trace!("Writing {} digivolve cards", self.digivolves.len()); + LittleEndian::write_u16( + header.digimons_len, + self.digimons.len().try_into().expect("Number of digimon cards exceeded `u16`"), + ); + *header.items_len = self.items.len().try_into().expect("Number of item cards exceeded `u8`"); + *header.digivolves_len = self.digivolves.len().try_into().expect("Number of digivolve cards exceeded `u8`"); + // And write the header file.write_all(&header_bytes).map_err(SerializeError::WriteHeader)?; - // Write all digimon, items and digivolves - for (rel_id, digimon) in self.digimons.iter().enumerate() { - // Current id through the whole table - let cur_id = rel_id; + // Macro to help write all cards to file + macro_rules! write_card { + ($cards:expr, $prev_ids:expr, $card_type:ident, $ErrVariant:ident) => { + for (rel_id, card) in $cards.iter().enumerate() { + // Current id through the whole table + let cur_id = $prev_ids + rel_id; - // Card bytes - let mut card_bytes = [0; 0x3 + CardType::Digimon.byte_size() + 0x1]; - let bytes = array_split_mut!(&mut card_bytes, - header_id : [0x2], - header_type: 1, - digimon : [CardType::Digimon.byte_size()], - footer : 1, - ); + // Card bytes + let mut card_bytes = [0; 0x3 + CardType::$card_type.byte_size() + 0x1]; + let bytes = array_split_mut!(&mut card_bytes, + header_id : [0x2], + header_type: 1, + card : [CardType::$card_type.byte_size()], + footer : 1, + ); - // Write the header - LittleEndian::write_u16(bytes.header_id, cur_id.try_into().expect("Card ID exceeded `u16`")); - CardType::Digimon.to_bytes(bytes.header_type)?; + // Write the header + LittleEndian::write_u16(bytes.header_id, cur_id.try_into().expect("Card ID exceeded `u16`")); + CardType::$card_type.to_bytes(bytes.header_type)?; - // Write the digimon - digimon - .to_bytes(bytes.digimon) - .map_err(|err| SerializeError::ParseDigimonCard { id: cur_id, err })?; + // Write the card + card + .to_bytes(bytes.card) + .map_err(|err| SerializeError::$ErrVariant { id: cur_id, err })?; - // Write the footer - *bytes.footer = 0; + // Write the footer + *bytes.footer = 0; - log::trace!("Writing Digimon with id {}", cur_id); - file.write_all(&card_bytes) - .map_err(|err| SerializeError::WriteDigimonCard { id: cur_id, err })?; + log::trace!("#{}: Writing {}", cur_id, CardType::$card_type); + file.write_all(&card_bytes) + .map_err(|err| SerializeError::WriteCard { + id: cur_id, + card_type: CardType::$card_type, + err + })?; + } + } } - for (rel_id, item) in self.items.iter().enumerate() { - // Current id through the whole table - let cur_id = self.digimons.len() + rel_id; - // Card bytes - let mut card_bytes = [0; 0x3 + CardType::Item.byte_size() + 0x1]; - let bytes = array_split_mut!(&mut card_bytes, - header_id : [0x2], - header_type: 1, - item : [CardType::Item.byte_size()], - footer : 1, - ); - - // Write the header - LittleEndian::write_u16(bytes.header_id, cur_id.try_into().expect("Card ID exceeded `u16`")); - CardType::Item.to_bytes(bytes.header_type)?; - - // Write the item - item.to_bytes(bytes.item) - .map_err(|err| SerializeError::ParseItemCard { id: cur_id, err })?; - - // Write the footer - *bytes.footer = 0; - - log::trace!("Writing Item with id {}", cur_id); - file.write_all(&card_bytes) - .map_err(|err| SerializeError::WriteItemCard { id: cur_id, err })?; - } - for (rel_id, digivolve) in self.digivolves.iter().enumerate() { - // Current id through the whole table - let cur_id = self.digimons.len() + self.items.len() + rel_id; - - // Card bytes - let mut card_bytes = [0; 0x3 + CardType::Digivolve.byte_size() + 0x1]; - let bytes = array_split_mut!(&mut card_bytes, - header_id : [0x2], - header_type: 1, - item : [CardType::Digivolve.byte_size()], - footer : 1, - ); - - // Write the header - LittleEndian::write_u16(bytes.header_id, cur_id.try_into().expect("Card ID exceeded `u16`")); - CardType::Digivolve.to_bytes(bytes.header_type)?; - - // Write the digivolve - digivolve - .to_bytes(bytes.item) - .map_err(|err| SerializeError::ParseDigivolveCard { id: cur_id, err })?; - - // Write the footer - *bytes.footer = 0; - - log::trace!("Writing Digivolve with id {}", cur_id); - file.write_all(&card_bytes) - .map_err(|err| SerializeError::WriteDigivolveCard { id: cur_id, err })?; + // Write all cards + #[rustfmt::skip] { + write_card! { self.digimons , 0 , Digimon , SerializeDigimonCard } + write_card! { self.items , self.digimons.len() , Item , SerializeItemCard } + write_card! { self.digivolves, self.digimons.len() + self.items.len(), Digivolve, SerializeDigivolveCard } } // And return Ok diff --git a/src/game/card/table/error.rs b/src/game/card/table/error.rs index b767c30..622e0cc 100644 --- a/src/game/card/table/error.rs +++ b/src/game/card/table/error.rs @@ -15,7 +15,7 @@ pub enum DeserializeError { ReadHeader(#[source] std::io::Error), /// The magic of the table was wrong - #[error("Found wrong table header magic (expected {:x}, found {:x})", Table::HEADER_MAGIC, magic)] + #[error("Found wrong table header magic (expected {:#x}, found {:#x})", Table::HEADER_MAGIC, magic)] HeaderMagic { /// Magic we found magic: u32, @@ -23,10 +23,7 @@ pub enum DeserializeError { /// There were too many cards #[error( - "Too many cards in table ({} digimon, {} item, {} digivolve, {} / {} bytes max)", - digimon_cards, - item_cards, - digivolve_cards, + "Too many cards in table ({digimon_cards} digimon, {item_cards} item, {digivolve_cards} digivolve, {} / {} bytes max)", digimon_cards * (0x3 + CardType::Digimon .byte_size() + 0x1) + item_cards * (0x3 + CardType::Item .byte_size() + 0x1) + digivolve_cards * (0x3 + CardType::Digivolve.byte_size() + 0x1), @@ -127,20 +124,9 @@ pub enum DeserializeError { /// Error type for [`Table::serialize`] #[derive(Debug, thiserror::Error)] pub enum SerializeError { - /// Unable to seek game file - #[error("Unable to seek game file to card table")] - Seek(#[source] std::io::Error), - - /// Unable to write table header - #[error("Unable to write table header")] - WriteHeader(#[source] std::io::Error), - /// There were too many cards #[error( - "Too many cards in table ({} digimon, {} item, {} digivolve, {} / {} bytes max)", - digimon_cards, - item_cards, - digivolve_cards, + "Too many cards in table ({digimon_cards} digimon, {item_cards} item, {digivolve_cards} digivolve, {} / {} bytes max)", digimon_cards * (0x3 + CardType::Digimon .byte_size() + 0x1) + item_cards * (0x3 + CardType::Item .byte_size() + 0x1) + digivolve_cards * (0x3 + CardType::Digivolve.byte_size() + 0x1), @@ -157,42 +143,31 @@ pub enum SerializeError { digivolve_cards: usize, }, - /// Unable to write a digimon card - #[error("Unable to write digimon card with id {}", id)] - WriteDigimonCard { + /// Unable to seek game file + #[error("Unable to seek game file to card table")] + Seek(#[source] std::io::Error), + + /// Unable to write table header + #[error("Unable to write table header")] + WriteHeader(#[source] std::io::Error), + + /// Unable to write a card + #[error("Unable to write {} card with id {}", card_type, id)] + WriteCard { /// Id of card id: usize, + /// Card type + card_type: CardType, + /// Underlying error #[source] err: std::io::Error, }, - /// Unable to write an item card - #[error("Unable to write item card with id {}", id)] - WriteItemCard { - /// Id of card - id: usize, - - /// Underlying error - #[source] - err: std::io::Error, - }, - - /// Unable to write a digivolve card - #[error("Unable to write digivolve card with id {}", id)] - WriteDigivolveCard { - /// Id of card - id: usize, - - /// Underlying error - #[source] - err: std::io::Error, - }, - - /// Unable to parse a digimon card - #[error("Unable to parse digimon card with id {}", id)] - ParseDigimonCard { + /// Unable to serialize a digimon card + #[error("Unable to serialize digimon card with id {}", id)] + SerializeDigimonCard { /// Id of card id: usize, @@ -201,9 +176,9 @@ pub enum SerializeError { err: card::digimon::ToBytesError, }, - /// Unable to parse an item card - #[error("Unable to parse item card with id {}", id)] - ParseItemCard { + /// Unable to serialize an item card + #[error("Unable to serialize item card with id {}", id)] + SerializeItemCard { /// Id of card id: usize, @@ -212,9 +187,9 @@ pub enum SerializeError { err: card::item::ToBytesError, }, - /// Unable to parse a digivolve card - #[error("Unable to parse digivolve card with id {}", id)] - ParseDigivolveCard { + /// Unable to serialize a digivolve card + #[error("Unable to serialize digivolve card with id {}", id)] + SerializeDigivolveCard { /// Id of card id: usize, diff --git a/src/game/deck/table.rs b/src/game/deck/table.rs index edd7be8..6a7f309 100644 --- a/src/game/deck/table.rs +++ b/src/game/deck/table.rs @@ -1,11 +1,22 @@ //! The table of all decks in the game +// Modules +pub mod error; + +// Exports +pub use error::{DeserializeError, SerializeError}; + // Imports use crate::{ - game::{deck::deck, Bytes, Deck}, + game::{Bytes, Deck}, io::{address::Data, GameFile}, + util::array_split_mut, +}; +use byteorder::{ByteOrder, LittleEndian}; +use std::{ + convert::TryInto, + io::{Read, Seek, Write}, }; -use std::io::{Read, Seek, Write}; /// The decks table, where all decks are stored #[derive(PartialEq, Eq, Clone, Debug)] @@ -17,76 +28,16 @@ pub struct Table { // Constants impl Table { + /// Table header size + pub const HEADER_BYTE_SIZE: usize = 0x8; + /// The magic in the table header + /// = "33KD" + pub const HEADER_MAGIC: u32 = 0x444b3033; + /// The max size of the deck table + // TODO: Verify this + pub const MAX_BYTE_SIZE: usize = 0x4452; /// The start address of the decks table - const DECK_TABLE_START_ADDRESS: Data = Data::from_u64(0x21a6808); -} - -/// Error type for [`Table::deserialize`] -#[derive(Debug, thiserror::Error)] -pub enum DeserializeError { - /// Unable to seek game file - #[error("Unable to seek game file to card table")] - Seek(#[source] std::io::Error), - - /// Unable to read table header - #[error("Unable to read table header")] - ReadHeader(#[source] std::io::Error), - - /// Could not read a deck entry - #[error("Unable to read deck entry with id {}", id)] - ReadDeck { - /// Id of card - id: usize, - - /// Underlying error - #[source] - err: std::io::Error, - }, - - /// Could not deserialize a deck entry - #[error("Unable to serialize deck entry with id {}", id)] - DeserializeDeck { - /// Id of card - id: usize, - - /// Underlying error - #[source] - err: deck::FromBytesError, - }, -} - -/// Error type for [`Table::serialize`] -#[derive(Debug, thiserror::Error)] -pub enum SerializeError { - /// Unable to seek game file - #[error("Unable to seek game file to card table")] - Seek(#[source] std::io::Error), - - /// Unable to read table header - #[error("Unable to read table header")] - WriteHeader(#[source] std::io::Error), - - /// Could not deserialize a deck entry - #[error("Unable to deserialize deck entry with id {}", id)] - SerializeDeck { - /// Id of card - id: usize, - - /// Underlying error - #[source] - err: deck::ToBytesError, - }, - - /// Could not write a deck entry - #[error("Unable to read deck entry with id {}", id)] - WriteDeck { - /// Id of card - id: usize, - - /// Underlying error - #[source] - err: std::io::Error, - }, + const START_ADDRESS: Data = Data::from_u64(0x21a6808); } impl Table { @@ -95,15 +46,32 @@ impl Table { where R: Read + Write + Seek, { - // The deck array - let mut decks = vec![]; - // Seek to the beginning of the deck table - file.seek(std::io::SeekFrom::Start(u64::from(Self::DECK_TABLE_START_ADDRESS))) + file.seek(std::io::SeekFrom::Start(u64::from(Self::START_ADDRESS))) .map_err(DeserializeError::Seek)?; + // Read header + let mut header_bytes = [0u8; Self::HEADER_BYTE_SIZE]; + file.read_exact(&mut header_bytes).map_err(DeserializeError::ReadHeader)?; + + // Check if the magic is right + let magic = LittleEndian::read_u32(&header_bytes[0x0..0x4]); + if magic != Self::HEADER_MAGIC { + return Err(DeserializeError::HeaderMagic { magic }); + } + + // Extract the number of decks + let decks_count: usize = header_bytes[0x4].into(); + log::trace!("Found {decks_count} decks"); + + // If there are too many decks, return Err + if decks_count * std::mem::size_of::<::ByteArray>() > Self::MAX_BYTE_SIZE { + return Err(DeserializeError::TooManyDecks { decks_count }); + } + // Then get each deck - for id in 0..159 { + let mut decks = vec![]; + for id in 0..decks_count { // Read all bytes of the deck let mut bytes = [0; 0x6e]; file.read_exact(&mut bytes).map_err(|err| DeserializeError::ReadDeck { id, err })?; @@ -111,6 +79,9 @@ impl Table { // And try to serialize the deck let deck = Deck::from_bytes(&bytes).map_err(|err| DeserializeError::DeserializeDeck { id, err })?; + // Log the deck + log::trace!("Found deck #{}: {}", id, deck.name); + // And add it decks.push(deck); } @@ -124,11 +95,37 @@ impl Table { where R: Read + Write + Seek, { + // If the total table size is bigger than the max, return Err + if self.decks.len() * std::mem::size_of::<::ByteArray>() > Self::MAX_BYTE_SIZE { + return Err(SerializeError::TooManyDecks { + decks_count: self.decks.len(), + }); + } + // Seek to the beginning of the deck table - file.seek(std::io::SeekFrom::Start(u64::from(Self::DECK_TABLE_START_ADDRESS))) + file.seek(std::io::SeekFrom::Start(u64::from(Self::START_ADDRESS))) .map_err(SerializeError::Seek)?; - // Then get each deck + // Write header + let mut header_bytes = [0u8; 0x8]; + let header = array_split_mut!(&mut header_bytes, + magic: [0x4], + + decks_count: 1, + _unknown: [0x3], + ); + + // Set magic + LittleEndian::write_u32(header.magic, Self::HEADER_MAGIC); + + // Write deck len + log::trace!("Writing {} decks", self.decks.len()); + *header.decks_count = self.decks.len().try_into().expect("Number of decks exceeded `u8`"); + + // And write the header + file.write_all(&header_bytes).map_err(SerializeError::WriteHeader)?; + + // Then write each deck for (id, deck) in self.decks.iter().enumerate() { // Parse each deck into bytes let mut bytes = [0; 0x6e]; diff --git a/src/game/deck/table/error.rs b/src/game/deck/table/error.rs new file mode 100644 index 0000000..7fb14f1 --- /dev/null +++ b/src/game/deck/table/error.rs @@ -0,0 +1,102 @@ +//! Errors + +// Imports +use super::{Bytes, Deck, Table}; +use crate::game::deck::deck; + +/// Error type for [`Table::deserialize`] +#[derive(Debug, thiserror::Error)] +pub enum DeserializeError { + /// Unable to seek game file + #[error("Unable to seek game file to card table")] + Seek(#[source] std::io::Error), + + /// Unable to read table header + #[error("Unable to read table header")] + ReadHeader(#[source] std::io::Error), + + /// The magic of the table was wrong + #[error("Found wrong table header magic (expected {:#}, found {:#x})", Table::HEADER_MAGIC, magic)] + HeaderMagic { + /// Magic we found + magic: u32, + }, + + /// There were too many decks + #[error( + "Too many decks in table ({decks_count} decks, {} / {} bytes max)", + decks_count * std::mem::size_of::<::ByteArray>(), + Table::MAX_BYTE_SIZE + )] + TooManyDecks { + /// Number of decks + decks_count: usize, + }, + + /// Could not read a deck entry + #[error("Unable to read deck entry with id {}", id)] + ReadDeck { + /// Id of card + id: usize, + + /// Underlying error + #[source] + err: std::io::Error, + }, + + /// Could not deserialize a deck entry + #[error("Unable to serialize deck entry with id {}", id)] + DeserializeDeck { + /// Id of card + id: usize, + + /// Underlying error + #[source] + err: deck::FromBytesError, + }, +} + +/// Error type for [`Table::serialize`] +#[derive(Debug, thiserror::Error)] +pub enum SerializeError { + /// Unable to seek game file + #[error("Unable to seek game file to card table")] + Seek(#[source] std::io::Error), + + /// There were too many decks + #[error( + "Too many decks in table ({decks_count} decks, {} / {} bytes max)", + decks_count * std::mem::size_of::<::ByteArray>(), + Table::MAX_BYTE_SIZE + )] + TooManyDecks { + /// Number of decks + decks_count: usize, + }, + + /// Unable to write table header + #[error("Unable to write table header")] + WriteHeader(#[source] std::io::Error), + + /// Could not deserialize a deck entry + #[error("Unable to deserialize deck entry with id {}", id)] + SerializeDeck { + /// Id of card + id: usize, + + /// Underlying error + #[source] + err: deck::ToBytesError, + }, + + /// Could not write a deck entry + #[error("Unable to read deck entry with id {}", id)] + WriteDeck { + /// Id of card + id: usize, + + /// Underlying error + #[source] + err: std::io::Error, + }, +} diff --git a/src/lib.rs b/src/lib.rs index e7f5ef4..14c19e9 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -35,7 +35,8 @@ decl_macro, stmt_expr_attributes, unwrap_infallible, - external_doc + external_doc, + format_args_capture )] // Lints #![warn(clippy::restriction, clippy::pedantic, clippy::nursery)] @@ -50,7 +51,7 @@ // it is the safest alternative. #![allow(clippy::expect_used)] // Like-wise with `.expect("...")`, we use `unreachable!` / `todo!` when we know a branch -// if unreachable, and if it ever does get reached, panicking would be the +// if unreachable or not yet finished, and if it ever does get reached, panicking would be the // safest option #![allow(clippy::unreachable, clippy::todo)] // We find it more important to be able to copy paste literals such as `0xabcd1234` than diff --git a/src/util/array_split.rs b/src/util/array_split.rs index eb73e3f..83b0185 100644 --- a/src/util/array_split.rs +++ b/src/util/array_split.rs @@ -69,6 +69,7 @@ pub macro array_split_mut { clippy::used_underscore_binding, clippy::ptr_offset_with_cast, clippy::indexing_slicing, + dead_code )] // Struct holding all fields