diff --git a/Cargo.toml b/Cargo.toml index c52c15b..4fa5cdf 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -11,7 +11,6 @@ log = "0.4" # Util byteorder = "1.3" -arrayvec = { version = "0.5", features = ["serde"] } ascii = { version = "1.0", features = ["serde"] } arrayref = "0.3" diff --git a/src/game/bytes.rs b/src/game/bytes.rs index 534cafa..ba8a48c 100644 --- a/src/game/bytes.rs +++ b/src/game/bytes.rs @@ -6,17 +6,19 @@ where Self: Sized { /// The type of array required by this structure + /// + /// *MUST* be a `[u8; N]` type ByteArray: Sized; /// The error type used for the operation type FromError: std::fmt::Debug + std::error::Error; - - /// Reads `bytes` and returns a result with `Self` - fn from_bytes(bytes: &Self::ByteArray) -> Result; /// The error type used for the operation type ToError: std::fmt::Debug + std::error::Error; - /// Writes bytes into `bytes` from self + /// Constructs this structure from `bytes` + fn from_bytes(bytes: &Self::ByteArray) -> Result; + + /// Writes this structure to `bytes` fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError>; } diff --git a/src/game/card/digimon.rs b/src/game/card/digimon.rs index 9c82f37..6d905ac 100644 --- a/src/game/card/digimon.rs +++ b/src/game/card/digimon.rs @@ -56,7 +56,7 @@ pub struct Digimon /// The digimon's name /// /// An ascii string with 20 characters at most - pub name: arrayvec::ArrayVec<[ascii::AsciiChar; 20]>, + pub name: ascii::AsciiString, /// The digimon's speciality /// @@ -103,7 +103,7 @@ pub struct Digimon /// /// The description is split along 4 lines, each /// being an ascii string with 20 characters at most. - pub effect_description: [arrayvec::ArrayVec<[ascii::AsciiChar; 20]>; 4], + pub effect_description: [ascii::AsciiString; 4], /// The effect arrow color #[serde(default)] @@ -118,7 +118,7 @@ pub struct Digimon pub effects: [Option; 3], } -/// The error type thrown by [`Bytes::from_bytes`] +/// Error type for [`Bytes::from_bytes`] #[derive(Debug)] #[derive(derive_more::Display, err_impl::Error)] pub enum FromBytesError @@ -191,6 +191,43 @@ pub enum FromBytesError #[display(fmt = "Unable to read the third effect")] EffectThird( #[error(source)] property::support_effect::FromBytesError ), } +/// Error type for [`Bytes::to_bytes`] +#[derive(Debug)] +#[derive(derive_more::Display, err_impl::Error)] +pub enum ToBytesError +{ + /// Unable to write the digimon name + #[display(fmt = "Unable to write the digimon name")] + Name( #[error(source)] util::WriteNullAsciiStringError ), + + /// Unable to write the first support effect description + #[display(fmt = "Unable to write the first line of the effect description")] + EffectDescriptionFirst( #[error(source)] util::WriteNullAsciiStringError ), + + /// Unable to write the second support effect description + #[display(fmt = "Unable to write the second line of the effect description")] + EffectDescriptionSecond( #[error(source)] util::WriteNullAsciiStringError ), + + /// Unable to write the third support effect description + #[display(fmt = "Unable to write the third line of the effect description")] + EffectDescriptionThird( #[error(source)] util::WriteNullAsciiStringError ), + + /// Unable to write the fourth support effect description + #[display(fmt = "Unable to write the fourth line of the effect description")] + EffectDescriptionFourth( #[error(source)] util::WriteNullAsciiStringError ), + + /// Unable to write the circle move + #[display(fmt = "Unable to write the circle move")] + MoveCircle( #[error(source)] property::moves::ToBytesError ), + + /// Unable to write the triangle move + #[display(fmt = "Unable to write the triangle move")] + MoveTriangle( #[error(source)] property::moves::ToBytesError ), + + /// Unable to write the cross move + #[display(fmt = "Unable to write the cross move")] + MoveCross( #[error(source)] property::moves::ToBytesError ), +} impl Bytes for Digimon { @@ -200,118 +237,13 @@ impl Bytes for Digimon fn from_bytes(bytes: &Self::ByteArray) -> Result { // Get all byte arrays we need - util::array_split!(bytes, - 0x00..0x1d => _, - 0x1d..0x39 => move_circle, - 0x39..0x55 => move_triangle, - 0x55..0x71 => move_cross, - 0x71..0x91 => condition_first, - 0x91..0xb1 => condition_second, - 0xb1..0xc1 => effect_first, - 0xc1..0xd1 => effect_second, - 0xd1..0xe1 => effect_third, - 0xe1..0x138 => _, - ); - - // Return the struct after building it - Ok( Self { - // 0x0 - 0x1d - name: util::read_null_ascii_string( &bytes[0x0..0x15] ) - .map_err(FromBytesError::Name)? - .chars().collect(), - - unknown_15: LittleEndian::read_u16( &bytes[0x15..0x17] ), - - speciality: Speciality::from_bytes( &( (bytes[0x17] & 0xF0) >> 4 ) ) - .map_err(FromBytesError::Speciality)?, - - level: Level::from_bytes( &( (bytes[0x17] & 0x0F) >> 0 ) ) - .map_err(FromBytesError::Level)?, - - dp_cost : bytes[0x18], - dp_give : bytes[0x19], - unknown_1a: bytes[0x1a], - - hp: LittleEndian::read_u16( &bytes[0x1b..0x1d] ), - - // 0x1d - 0x71 - move_circle: Move::from_bytes( move_circle ) - .map_err(FromBytesError::MoveCircle)?, - move_triangle: Move::from_bytes( move_triangle ) - .map_err(FromBytesError::MoveTriangle)?, - move_cross: Move::from_bytes( move_cross ) - .map_err(FromBytesError::MoveCross)?, - - // 0x71 - 0x138 - effect_conditions: [ - (bytes[0x73] != 0) - .then(|| SupportCondition::from_bytes( condition_first ) ) - .transpose() - .map_err(FromBytesError::EffectConditionFirst)?, - - (bytes[0x93] != 0) - .then(|| SupportCondition::from_bytes( condition_second ) ) - .transpose() - .map_err(FromBytesError::EffectConditionSecond)?, - ], - - effects: [ - (bytes[0xb1] != 0) - .then(|| SupportEffect::from_bytes( effect_first ) ) - .transpose() - .map_err(FromBytesError::EffectFirst)?, - - (bytes[0xc1] != 0) - .then(|| SupportEffect::from_bytes( effect_second ) ) - .transpose() - .map_err(FromBytesError::EffectSecond)?, - - (bytes[0xd1] != 0) - .then(|| SupportEffect::from_bytes( effect_third ) ) - .transpose() - .map_err(FromBytesError::EffectThird)?, - ], - - cross_move_effect: (bytes[0xe1] != 0) - .then(|| CrossMoveEffect::from_bytes( &bytes[0xe1] ) ) - .transpose() - .map_err(FromBytesError::CrossMoveEffect)?, - - unknown_e2: bytes[0xe2], - - effect_arrow_color: (bytes[0xe3] != 0) - .then(|| ArrowColor::from_bytes( &bytes[0xe3] ) ) - .transpose() - .map_err(FromBytesError::ArrowColor)?, - - effect_description: [ - util::read_null_ascii_string( &bytes[0x0e4..0x0f9] ) - .map_err(FromBytesError::EffectDescriptionFirst)? - .chars().collect(), - util::read_null_ascii_string( &bytes[0x0f9..0x10e] ) - .map_err(FromBytesError::EffectDescriptionSecond)? - .chars().collect(), - util::read_null_ascii_string( &bytes[0x10e..0x123] ) - .map_err(FromBytesError::EffectDescriptionThird)? - .chars().collect(), - util::read_null_ascii_string( &bytes[0x123..0x138] ) - .map_err(FromBytesError::EffectDescriptionFourth)? - .chars().collect(), - ], - }) - } - - type ToError = !; - fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError> - { - // Get all byte arrays we need - util::array_split_mut!(bytes, + let bytes = util::array_split!(bytes, 0x00..0x15 => name, 0x15..0x17 => unknown_15, - 0x17..0x18 => speciality_level, - 0x18..0x19 => dp_cost, - 0x19..0x1a => dp_give, - 0x1a..0x1b => unknown_1a, + =0x17 => speciality_level, + =0x18 => dp_cost, + =0x19 => dp_give, + =0x1a => unknown_1a, 0x1b..0x1d => hp, 0x1d..0x39 => move_circle, 0x39..0x55 => move_triangle, @@ -327,15 +259,129 @@ impl Bytes for Digimon 0xe4..0x138 => effect_description, ); - // name - name.copy_from_slice( - // Note: `self.name` is at most [char; 20], this cannot fail - util::write_null_ascii_string(self.name.as_ref().as_ref(), &mut [0u8; 21]) - .expect("Name was too large for output buffer") + // Return the struct after building it + Ok( Self { + // 0x0 - 0x1d + name: util::read_null_ascii_string(bytes.name) + .map_err(FromBytesError::Name)? + .chars().collect(), + + unknown_15: LittleEndian::read_u16(bytes.unknown_15), + + speciality: Speciality::from_bytes( &( (bytes.speciality_level & 0xF0) >> 4 ) ) + .map_err(FromBytesError::Speciality)?, + + level: Level::from_bytes( &( (bytes.speciality_level & 0x0F) >> 0 ) ) + .map_err(FromBytesError::Level)?, + + dp_cost : *bytes.dp_cost, + dp_give : *bytes.dp_give, + unknown_1a: *bytes.unknown_1a, + + hp: LittleEndian::read_u16( bytes.hp ), + + // 0x1d - 0x71 + move_circle: Move::from_bytes( bytes.move_circle ) + .map_err(FromBytesError::MoveCircle)?, + move_triangle: Move::from_bytes( bytes.move_triangle ) + .map_err(FromBytesError::MoveTriangle)?, + move_cross: Move::from_bytes( bytes.move_cross ) + .map_err(FromBytesError::MoveCross)?, + + // 0x71 - 0x138 + effect_conditions: [ + (bytes.condition_first[2] != 0) + .then(|| SupportCondition::from_bytes( bytes.condition_first ) ) + .transpose() + .map_err(FromBytesError::EffectConditionFirst)?, + + (bytes.condition_second[2] != 0) + .then(|| SupportCondition::from_bytes( bytes.condition_second ) ) + .transpose() + .map_err(FromBytesError::EffectConditionSecond)?, + ], + + effects: [ + (bytes.effect_first[0] != 0) + .then(|| SupportEffect::from_bytes( bytes.effect_first ) ) + .transpose() + .map_err(FromBytesError::EffectFirst)?, + + (bytes.effect_second[0] != 0) + .then(|| SupportEffect::from_bytes( bytes.effect_second ) ) + .transpose() + .map_err(FromBytesError::EffectSecond)?, + + (bytes.effect_third[0] != 0) + .then(|| SupportEffect::from_bytes( bytes.effect_third ) ) + .transpose() + .map_err(FromBytesError::EffectThird)?, + ], + + cross_move_effect: (bytes.cross_move_effect[0] != 0) + .then(|| CrossMoveEffect::from_bytes( &bytes.cross_move_effect[0] ) ) + .transpose() + .map_err(FromBytesError::CrossMoveEffect)?, + + unknown_e2: bytes.unknown_e2[0], + + effect_arrow_color: (bytes.effect_arrow_color[0] != 0) + .then(|| ArrowColor::from_bytes( &bytes.effect_arrow_color[0] ) ) + .transpose() + .map_err(FromBytesError::ArrowColor)?, + + effect_description: [ + util::read_null_ascii_string( &bytes.effect_description[0x00..0x15] ) + .map_err(FromBytesError::EffectDescriptionFirst)? + .chars().collect(), + util::read_null_ascii_string( &bytes.effect_description[0x15..0x2a] ) + .map_err(FromBytesError::EffectDescriptionSecond)? + .chars().collect(), + util::read_null_ascii_string( &bytes.effect_description[0x2a..0x3f] ) + .map_err(FromBytesError::EffectDescriptionThird)? + .chars().collect(), + util::read_null_ascii_string( &bytes.effect_description[0x3f..0x54] ) + .map_err(FromBytesError::EffectDescriptionFourth)? + .chars().collect(), + ], + }) + } + + type ToError = ToBytesError; + fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError> + { + // Get all byte arrays we need + let bytes = util::array_split_mut!(bytes, + name : [0x15], + unknown_15 : [0x2], + speciality_level : 0x1, + dp_cost : 0x1, + dp_give : 0x1, + unknown_1a : 0x1, + hp : [0x2], + move_circle : [0x1c], + move_triangle : [0x1c], + move_cross : [0x1c], + condition_first : [0x20], + condition_second : [0x20], + effect_first : [0x10], + effect_second : [0x10], + effect_third : [0x10], + cross_move_effect : 1, + unknown_e2 : 1, + effect_arrow_color : 1, + effect_description_0: [0x15], + effect_description_1: [0x15], + effect_description_2: [0x15], + effect_description_3: [0x15], ); + // name + util::write_null_ascii_string(self.name.as_ref(), bytes.name) + .map_err(ToBytesError::Name)?; + // unknown_15 - LittleEndian::write_u16(unknown_15, self.unknown_15); + LittleEndian::write_u16(bytes.unknown_15, self.unknown_15); // Speciality / Level { @@ -346,58 +392,53 @@ impl Bytes for Digimon self.level.to_bytes(&mut level_byte)?; // Merge them - speciality_level[0] = (speciality_byte << 4) | level_byte; + *bytes.speciality_level = (speciality_byte << 4) | level_byte; } // DP / +P - dp_cost[0] = self.dp_cost; - dp_give[0] = self.dp_give; + *bytes.dp_cost = self.dp_cost; + *bytes.dp_give = self.dp_give; // Unknown - unknown_1a[0] = self.unknown_1a; + *bytes.unknown_1a = self.unknown_1a; // Health - LittleEndian::write_u16(hp, self.hp); + LittleEndian::write_u16(bytes.hp, self.hp); // Moves - self. move_circle.to_bytes( move_circle )?; - self.move_triangle.to_bytes( move_triangle )?; - self. move_cross.to_bytes( move_cross )?; + self. move_circle.to_bytes( bytes.move_circle ).map_err(ToBytesError::MoveCircle )?; + self.move_triangle.to_bytes( bytes.move_triangle ).map_err(ToBytesError::MoveTriangle)?; + self. move_cross.to_bytes( bytes.move_cross ).map_err(ToBytesError::MoveCross )?; // Support conditions // Note: Although support conditions and effects aren't written if they're None, // a bit pattern of all 0s is a valid pattern and means "None" to the game. - if let Some(support_condition) = &self.effect_conditions[0] { support_condition.to_bytes( condition_first )?; } - if let Some(support_condition) = &self.effect_conditions[1] { support_condition.to_bytes( condition_second )?; } + if let Some(support_condition) = &self.effect_conditions[0] { support_condition.to_bytes( bytes.condition_first )?; } + if let Some(support_condition) = &self.effect_conditions[1] { support_condition.to_bytes( bytes.condition_second )?; } // Support effects - if let Some(support_effect) = &self.effects[0] { support_effect.to_bytes( effect_first )?; } - if let Some(support_effect) = &self.effects[1] { support_effect.to_bytes( effect_second )?; } - if let Some(support_effect) = &self.effects[2] { support_effect.to_bytes( effect_third )?; } + if let Some(support_effect) = &self.effects[0] { support_effect.to_bytes( bytes.effect_first )?; } + if let Some(support_effect) = &self.effects[1] { support_effect.to_bytes( bytes.effect_second )?; } + if let Some(support_effect) = &self.effects[2] { support_effect.to_bytes( bytes.effect_third )?; } // Cross move - if let Some(move_cross) = self.cross_move_effect { move_cross.to_bytes( &mut cross_move_effect[0] )? }; + if let Some(move_cross) = self.cross_move_effect { move_cross.to_bytes( bytes.cross_move_effect )? }; // Unknown - unknown_e2[0] = self.unknown_e2; + *bytes.unknown_e2 = self.unknown_e2; // Support arrow color - if let Some(arrow_color) = self.effect_arrow_color { arrow_color.to_bytes( &mut effect_arrow_color[0] )? } + if let Some(arrow_color) = self.effect_arrow_color { arrow_color.to_bytes( bytes.effect_arrow_color )? } // effect_description - // Note: Each string is at most [char; 20], this cannot fail - effect_description[0x00..0x15].copy_from_slice( util::write_null_ascii_string(self.effect_description[0].as_ref().as_ref(), &mut [0u8; 21]) - .expect("First line of effect description was too large for output buffer") - ); - effect_description[0x15..0x2a].copy_from_slice( util::write_null_ascii_string(self.effect_description[1].as_ref().as_ref(), &mut [0u8; 21]) - .expect("Second line of effect description was too large for output buffer") - ); - effect_description[0x2a..0x3f].copy_from_slice( util::write_null_ascii_string(self.effect_description[2].as_ref().as_ref(), &mut [0u8; 21]) - .expect("Third line of effect description was too large for output buffer") - ); - effect_description[0x3f..0x54].copy_from_slice( util::write_null_ascii_string(self.effect_description[3].as_ref().as_ref(), &mut [0u8; 21]) - .expect("Fourth line of effect description was too large for output buffer") - ); + util::write_null_ascii_string(self.effect_description[0].as_ref(), bytes.effect_description_0) + .map_err(ToBytesError::EffectDescriptionFirst)?; + util::write_null_ascii_string(self.effect_description[1].as_ref(), bytes.effect_description_1) + .map_err(ToBytesError::EffectDescriptionSecond)?; + util::write_null_ascii_string(self.effect_description[2].as_ref(), bytes.effect_description_2) + .map_err(ToBytesError::EffectDescriptionThird)?; + util::write_null_ascii_string(self.effect_description[3].as_ref(), bytes.effect_description_3) + .map_err(ToBytesError::EffectDescriptionFourth)?; // Return Ok Ok(()) diff --git a/src/game/card/property/moves.rs b/src/game/card/property/moves.rs index de57f4b..4f64b6b 100644 --- a/src/game/card/property/moves.rs +++ b/src/game/card/property/moves.rs @@ -9,7 +9,7 @@ //! |--------|------|----------------------|---------------------------|------------------------|-----------------------------------| //! | 0x0 | 0x2 | `u16` | Power | `power` | | //! | 0x2 | 0x4 | `u32` | Unknown | `unknown` | Most likely stores animation data | -//! | 0x4 | 0x16 | `[char; 0x16]` | Name | `name` | Null-terminated | +//! | 0x6 | 0x16 | `[char; 0x16]` | Name | `name` | Null-terminated | // byteorder use byteorder::{ByteOrder, LittleEndian}; @@ -23,7 +23,7 @@ use crate::game::{util, Bytes}; pub struct Move { /// The move's name - name: arrayvec::ArrayVec<[ascii::AsciiChar; 21]>, + name: ascii::AsciiString, /// The move's power power: u16, @@ -45,9 +45,9 @@ pub enum FromBytesError #[derive(Debug, derive_more::Display, err_impl::Error)] pub enum ToBytesError { - /// The name was too big to be written to file - #[display(fmt = "The name \"{}\" is too long to be written to file (max is 21)", _0)] - NameTooLong( String ), + /// Unable to write the move name + #[display(fmt = "Unable to write the move name")] + Name( #[error(source)] util::WriteNullAsciiStringError ), } // Bytes @@ -60,7 +60,7 @@ impl Bytes for Move { // And return the move Ok( Self { - name : util::read_null_ascii_string( &bytes[0x0..0x15] ) + name : util::read_null_ascii_string( &bytes[0x6..0x1c] ) .map_err(FromBytesError::Name)? .chars().collect(), power : LittleEndian::read_u16( &bytes[0x0..0x2] ), @@ -68,26 +68,23 @@ impl Bytes for Move }) } - type ToError = !; + type ToError = ToBytesError; fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError> { // Get all byte arrays we need - util::array_split_mut!(bytes, - 0x0..0x02 => power, - 0x2..0x04 => unknown, - 0x4..0x1c => name, + let bytes = util::array_split_mut!(bytes, + power : [0x2], + unknown: [0x4], + name : [0x16], ); // Write the name - name.copy_from_slice( - // Note: `self.name` is at most [char; 21], this cannot fail - util::write_null_ascii_string(self.name.as_ref().as_ref(), &mut [0u8; 22]) - .expect("Name was too large for output buffer") - ); + util::write_null_ascii_string(self.name.as_ref(), bytes.name) + .map_err(ToBytesError::Name)?; // Then write the power and the unknown - LittleEndian::write_u16(power , self.power ); - LittleEndian::write_u32(unknown, self.unknown); + LittleEndian::write_u16(bytes.power , self.power ); + LittleEndian::write_u32(bytes.unknown, self.unknown); // And return Ok Ok(()) diff --git a/src/game/card/property/support_effect.rs b/src/game/card/property/support_effect.rs index ae918d5..ecb7a5d 100644 --- a/src/game/card/property/support_effect.rs +++ b/src/game/card/property/support_effect.rs @@ -291,36 +291,36 @@ impl Bytes for SupportEffect fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError> { // Get all byte arrays we need - util::array_split_mut!(bytes, - 0x0..0x01 => exists, - 0x1..0x02 => effect_type, - 0x2..0x03 => bytes_a, - 0x3..0x04 => _, - 0x4..0x05 => bytes_b, - 0x5..0x06 => _, - 0x6..0x07 => bytes_c, - 0x7..0x0a => _, - 0xa..0x0c => bytes_x, - 0xc..0x0e => bytes_y, - 0xe..0x0f => _, - 0xf..0x10 => bytes_op, + let bytes = util::array_split_mut!(bytes, + exists : 0x1, + effect_type: 0x1, + a : 0x1, + _unknown_3 : 0x1, + b : 0x1, + _unknown_5 : 0x1, + c : 0x1, + _unknown_7 : [0x3], + x : [0x2], + y : [0x2], + _unknown_e : 0x1, + op : 0x1, ); // Set that the effect exists - exists[0] = 1; + *bytes.exists = 1; // Check our variant and fill `bytes` with info #[allow(clippy::unneeded_field_pattern)] // Placeholder match self { Self::ChangeProperty { property, a, b, c, x, y, op } => { - property.to_bytes(&mut effect_type[0])?; - effect_type[0] -= 1; - if let Some(a) = a { a.to_bytes(&mut bytes_a[0])?; } - if let Some(b) = b { b.to_bytes(&mut bytes_b[0])?; } - if let Some(c) = c { c.to_bytes(&mut bytes_c[0])?; } - LittleEndian::write_u16(bytes_x, *x); - LittleEndian::write_u16(bytes_y, *y); - op.to_bytes(&mut bytes_op[0])?; + property.to_bytes(bytes.effect_type)?; + *bytes.effect_type -= 1; + if let Some(a) = a { a.to_bytes(bytes.a)?; } + if let Some(b) = b { b.to_bytes(bytes.b)?; } + if let Some(c) = c { c.to_bytes(bytes.c)?; } + LittleEndian::write_u16(bytes.x, *x); + LittleEndian::write_u16(bytes.y, *y); + op.to_bytes(bytes.op)?; }, Self::UseAttack { player: _, attack: _ } => todo!(), diff --git a/src/game/card/table.rs b/src/game/card/table.rs index 3aa82b4..c722ac3 100644 --- a/src/game/card/table.rs +++ b/src/game/card/table.rs @@ -243,9 +243,9 @@ impl Table { // If there are too many cards, return Err - 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); + 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::debug!("[Table Header] {} total bytes of cards", table_size); if table_size > Self::MAX_BYTE_SIZE { return Err( DeserializeError::TooManyCards { digimon_cards, @@ -254,8 +254,8 @@ impl Table { } ); } // Create the arrays with capacity - let mut digimons = Vec::with_capacity(digimon_cards); - let mut items = Vec::with_capacity(item_cards); + let mut digimons = Vec::with_capacity(digimon_cards); + let mut items = Vec::with_capacity(item_cards); let mut digivolves = Vec::with_capacity(digivolve_cards); // Read until the table is over diff --git a/src/game/util.rs b/src/game/util.rs index 5d5bd46..d418e10 100644 --- a/src/game/util.rs +++ b/src/game/util.rs @@ -6,38 +6,95 @@ //! All items in this module will eventually be depracated and moved //! somewhere else, but this change might take some time. -/// Splits an array into it's various element arrays + pub macro array_split { ( $arr:ident, - $( $start:literal..$end:literal => $name:tt),* $(,)? - ) => { + $( + $( $start:literal..$end:literal => $arr_name:tt )? + $( =$location:literal => $val_name:tt )? + , + )* + ) => {{ + #![allow(clippy::used_underscore_binding)] + + // Struct holding all fields + struct __Fields<'a, T> { + $( + $( $arr_name: &'a [T; $end - $start], )? + $( $val_name: &'a T, )? + )* + } + + // Get everything from `array_refs` let ( $( - $name, + $( $arr_name, )? + $( $val_name, )? )* ) = ::arrayref::array_refs!( $arr, - $( $end - $start ),* + $( + $( $end - $start )? + $( 1 + (0 * $location) )? + ),* ); - } + + // And return the fields + __Fields { + $( + $( $arr_name, )? + $( $val_name: &( $val_name[0] ), )? + )* + } + }} } -/// Splits an array mutable into it's various element arrays pub macro array_split_mut { ( $arr:ident, - $( $start:literal..$end:literal => $name:tt),* $(,)? - ) => { + $( + $name:ident : + + $( [$arr_size:literal] )? + $( $val_size:literal )? + + ),* $(,)? + ) => {{ + #![allow(clippy::used_underscore_binding)] + + // Struct holding all fields + struct __Fields<'a, T> { + $( + $name: + + $( &'a mut [T; $arr_size], )? + $( &'a mut T, #[cfg(os = "Os that does not exist")] __field: [u8; $val_size], )? + )* + } + + // Get everything from `array_refs` let ( $( - $name, - )* + $name + ),* ) = ::arrayref::mut_array_refs!( $arr, - $( $end - $start ),* + $( + $( $arr_size )? + $( $val_size )? + ),* ); - } + + // And return the fields + __Fields { + $( + $name + $( : &mut ( $name[$val_size - $val_size] ) )? + , + )* + } + }} } // Types @@ -142,6 +199,8 @@ pub macro array_split_mut { } //-------------------------------------------------------------------------------------------------- + + /// Error type for [`read_null_ascii_string`] #[derive(Debug)] #[derive(derive_more::Display, err_impl::Error)] @@ -174,7 +233,7 @@ pub fn read_null_ascii_string(mut buf: &[u8]) -> Result<&ascii::AsciiStr, ReadNu #[derive(derive_more::Display, err_impl::Error)] pub enum WriteNullAsciiStringError { /// The input string was too large - #[display(fmt = "Input string was too large for buffer. ({} / {})", "input_len", "buffer_len")] + #[display(fmt = "Input string was too large for buffer. ({}+1 / {})", "input_len", "buffer_len")] TooLarge { input_len : usize, buffer_len: usize, @@ -183,7 +242,7 @@ pub enum WriteNullAsciiStringError { /// Writes a null-terminated ascii string to a buffer and returns it pub fn write_null_ascii_string<'a>(input: &ascii::AsciiStr, buf: &'a mut [u8]) -> Result<&'a mut [u8], WriteNullAsciiStringError> { - // If the input string is too large, return Err + // If the input string doesn't fit into the buffer (excluding the null byte), return Err if input.len() >= buf.len() { return Err(WriteNullAsciiStringError::TooLarge{ input_len: input.len(), buffer_len: buf.len() }); } diff --git a/src/lib.rs b/src/lib.rs index 51a1367..5f56470 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -29,6 +29,7 @@ unsized_locals, bool_to_option, decl_macro, + stmt_expr_attributes, )] // Lints