diff --git a/src/game/card/digimon.rs b/src/game/card/digimon.rs index 3b631f0..e3cf5db 100644 --- a/src/game/card/digimon.rs +++ b/src/game/card/digimon.rs @@ -191,6 +191,7 @@ pub enum FromBytesError #[display(fmt = "Unable to read the third effect")] EffectThird( #[error(source)] property::effect::FromBytesError ), } + /// Error type for [`Bytes::to_bytes`] #[derive(Debug)] #[derive(derive_more::Display, err_impl::Error)] @@ -323,16 +324,12 @@ impl Bytes for Digimon .map_err(FromBytesError::EffectThird)?, ], - cross_move_effect: (*bytes.cross_move_effect != 0) - .then(|| CrossMoveEffect::from_bytes( bytes.cross_move_effect ) ) - .transpose() + cross_move_effect: Option::::from_bytes(bytes.cross_move_effect) .map_err(FromBytesError::CrossMoveEffect)?, unknown_e2: *bytes.unknown_e2, - effect_arrow_color: (*bytes.effect_arrow_color != 0) - .then(|| ArrowColor::from_bytes( bytes.effect_arrow_color ) ) - .transpose() + effect_arrow_color: Option::::from_bytes(bytes.effect_arrow_color) .map_err(FromBytesError::ArrowColor)?, effect_description: [ @@ -425,13 +422,13 @@ impl Bytes for Digimon self.effects[2].to_bytes( bytes.effect_third ).map_err(ToBytesError::EffectThird )?; // Cross move - if let Some(move_cross) = self.cross_move_effect { move_cross.to_bytes( bytes.cross_move_effect )? }; + Option::::to_bytes(&self.cross_move_effect, bytes.cross_move_effect).into_ok(); // Unknown *bytes.unknown_e2 = self.unknown_e2; // Support arrow color - if let Some(arrow_color) = self.effect_arrow_color { arrow_color.to_bytes( bytes.effect_arrow_color )? } + Option::::to_bytes(&self.effect_arrow_color, bytes.effect_arrow_color).into_ok(); // effect_description util::write_null_ascii_string(self.effect_description[0].as_ref(), bytes.effect_description_0) diff --git a/src/game/card/property.rs b/src/game/card/property.rs index 13b1398..b7a4cf3 100644 --- a/src/game/card/property.rs +++ b/src/game/card/property.rs @@ -136,6 +136,31 @@ generate_enum_property_mod!( _ => "Unknown byte 0x{:x} for an arrow color" } + + impl crate::game::Bytes for Option { + type ByteArray = u8; + + type FromError = FromBytesError; + fn from_bytes(byte: &Self::ByteArray) -> Result + { + match byte { + 0 => Ok( None ), + _ => Ok( Some( ArrowColor::from_bytes(byte)? ) ), + } + } + + type ToError = ::ToError; + #[allow(clippy::diverging_sub_expression)] // For if we ever change `ArrowColor::ToError` + fn to_bytes(&self, byte: &mut Self::ByteArray) -> Result<(), Self::ToError> + { + match self { + Some(effect) => effect.to_bytes(byte)?, + None => *byte = 0, + } + + Ok(()) + } + } } pub mod attack_type { @@ -272,6 +297,31 @@ generate_enum_property_mod!( _ => "Unknown byte 0x{:x} for a cross move effect", } + + impl crate::game::Bytes for Option { + type ByteArray = u8; + + type FromError = FromBytesError; + fn from_bytes(byte: &Self::ByteArray) -> Result + { + match byte { + 0 => Ok( None ), + _ => Ok( Some( CrossMoveEffect::from_bytes(byte)? ) ), + } + } + + type ToError = ::ToError; + #[allow(clippy::diverging_sub_expression)] // For if we ever change `CrossMoveEffect::ToError` + fn to_bytes(&self, byte: &mut Self::ByteArray) -> Result<(), Self::ToError> + { + match self { + Some(effect) => effect.to_bytes(byte)?, + None => *byte = 0, + } + + Ok(()) + } + } } pub mod digimon_property { diff --git a/src/game/card/property/moves.rs b/src/game/card/property/moves.rs index 838bfe8..1744792 100644 --- a/src/game/card/property/moves.rs +++ b/src/game/card/property/moves.rs @@ -58,13 +58,20 @@ impl Bytes for Move type FromError = FromBytesError; fn from_bytes(bytes: &Self::ByteArray) -> Result { + // Get all byte arrays we need + let bytes = util::array_split!(bytes, + power : [0x2], + unknown: [0x4], + name : [0x16], + ); + // Return the move Ok( Self { - name : util::read_null_ascii_string( &bytes[0x6..0x1c] ) + name : util::read_null_ascii_string( bytes.name ) .map_err(FromBytesError::Name)? .chars().collect(), - power : LittleEndian::read_u16( &bytes[0x0..0x2] ), - unknown: LittleEndian::read_u32( &bytes[0x2..0x6] ), + power : LittleEndian::read_u16( bytes.power ), + unknown: LittleEndian::read_u32( bytes.unknown ), }) } diff --git a/src/game/util.rs b/src/game/util.rs index d486a98..658ef95 100644 --- a/src/game/util.rs +++ b/src/game/util.rs @@ -221,13 +221,13 @@ pub enum ReadNullAsciiStringError { } /// Reads a null-terminated ascii string from a buffer. -pub fn read_null_ascii_string(mut buf: &[u8]) -> Result<&ascii::AsciiStr, ReadNullAsciiStringError> { +pub fn read_null_ascii_string(buf: &impl AsRef<[u8]>) -> Result<&ascii::AsciiStr, ReadNullAsciiStringError> { // Find the first null and trim the buffer until it - if let Some(null_idx) = buf.iter().position(|&b| b == 0) { - buf = &buf[0..null_idx]; - } else { - return Err( ReadNullAsciiStringError::NoNull ); - } + let buf = buf.as_ref(); + let buf = match buf.iter().position(|&b| b == 0) { + Some(null_idx) => &buf[0..null_idx], + None => return Err( ReadNullAsciiStringError::NoNull ), + }; // Then convert it from Ascii ascii::AsciiStr::from_ascii(buf) @@ -254,6 +254,7 @@ pub fn write_null_ascii_string<'a>(input: &ascii::AsciiStr, buf: &'a mut [u8]) - } // Else copy everything over and set the last byte to null + // Note: We leave all other bytes as they are, no need to set them to 0 buf[ 0..input.len() ].copy_from_slice( input.as_bytes() ); buf[ input.len() ] = 0;