Made game::util::read_null_ascii_string more generic.

Added some implementations of `Bytes` for `Option<...>` where relevant.
Started using `array_split` in `Move::from_bytes`.
This commit is contained in:
2020-05-01 05:41:04 +01:00
parent 596bf177d6
commit 80e011dd82
4 changed files with 72 additions and 17 deletions

View File

@@ -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::<CrossMoveEffect>::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::<ArrowColor>::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::<CrossMoveEffect>::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::<ArrowColor>::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)

View File

@@ -136,6 +136,31 @@ generate_enum_property_mod!(
_ => "Unknown byte 0x{:x} for an arrow color"
}
impl crate::game::Bytes for Option<ArrowColor> {
type ByteArray = u8;
type FromError = FromBytesError;
fn from_bytes(byte: &Self::ByteArray) -> Result<Self, Self::FromError>
{
match byte {
0 => Ok( None ),
_ => Ok( Some( ArrowColor::from_bytes(byte)? ) ),
}
}
type ToError = <ArrowColor as crate::game::Bytes>::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<CrossMoveEffect> {
type ByteArray = u8;
type FromError = FromBytesError;
fn from_bytes(byte: &Self::ByteArray) -> Result<Self, Self::FromError>
{
match byte {
0 => Ok( None ),
_ => Ok( Some( CrossMoveEffect::from_bytes(byte)? ) ),
}
}
type ToError = <CrossMoveEffect as crate::game::Bytes>::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 {

View File

@@ -58,13 +58,20 @@ impl Bytes for Move
type FromError = FromBytesError;
fn from_bytes(bytes: &Self::ByteArray) -> Result<Self, Self::FromError>
{
// 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 ),
})
}

View File

@@ -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;