mirror of
https://github.com/Zenithsiz/dcb.git
synced 2026-02-09 03:40:23 +00:00
Reworked util module.
Changed all functions that read/write ascii strings to a trait.
This commit is contained in:
@@ -3,7 +3,11 @@
|
||||
// Imports
|
||||
use crate::game::{
|
||||
card::property::{self, ArrowColor, CrossMoveEffect, Effect, EffectCondition, Level, Move, Speciality},
|
||||
util, Bytes,
|
||||
util::{
|
||||
array_split, array_split_mut,
|
||||
null_ascii_string::{self, NullAsciiString},
|
||||
},
|
||||
Bytes,
|
||||
};
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
@@ -87,23 +91,23 @@ pub struct Digimon {
|
||||
pub enum FromBytesError {
|
||||
/// Unable to read the digimon name
|
||||
#[error("Unable to read the digimon name")]
|
||||
Name(#[source] util::ReadNullAsciiStringError),
|
||||
Name(#[source] null_ascii_string::ReadError),
|
||||
|
||||
/// Unable to read the first support effect description
|
||||
#[error("Unable to read the first line of the effect description")]
|
||||
EffectDescriptionFirst(#[source] util::ReadNullAsciiStringError),
|
||||
EffectDescriptionFirst(#[source] null_ascii_string::ReadError),
|
||||
|
||||
/// Unable to read the second support effect description
|
||||
#[error("Unable to read the second line of the effect description")]
|
||||
EffectDescriptionSecond(#[source] util::ReadNullAsciiStringError),
|
||||
EffectDescriptionSecond(#[source] null_ascii_string::ReadError),
|
||||
|
||||
/// Unable to read the third support effect description
|
||||
#[error("Unable to read the third line of the effect description")]
|
||||
EffectDescriptionThird(#[source] util::ReadNullAsciiStringError),
|
||||
EffectDescriptionThird(#[source] null_ascii_string::ReadError),
|
||||
|
||||
/// Unable to read the fourth support effect description
|
||||
#[error("Unable to read the fourth line of the effect description")]
|
||||
EffectDescriptionFourth(#[source] util::ReadNullAsciiStringError),
|
||||
EffectDescriptionFourth(#[source] null_ascii_string::ReadError),
|
||||
|
||||
/// An unknown speciality was found
|
||||
#[error("Unknown speciality found")]
|
||||
@@ -159,23 +163,23 @@ pub enum FromBytesError {
|
||||
pub enum ToBytesError {
|
||||
/// Unable to write the digimon name
|
||||
#[error("Unable to write the digimon name")]
|
||||
Name(#[source] util::WriteNullAsciiStringError),
|
||||
Name(#[source] null_ascii_string::WriteError),
|
||||
|
||||
/// Unable to write the first support effect description
|
||||
#[error("Unable to write the first line of the effect description")]
|
||||
EffectDescriptionFirst(#[source] util::WriteNullAsciiStringError),
|
||||
EffectDescriptionFirst(#[source] null_ascii_string::WriteError),
|
||||
|
||||
/// Unable to write the second support effect description
|
||||
#[error("Unable to write the second line of the effect description")]
|
||||
EffectDescriptionSecond(#[source] util::WriteNullAsciiStringError),
|
||||
EffectDescriptionSecond(#[source] null_ascii_string::WriteError),
|
||||
|
||||
/// Unable to write the third support effect description
|
||||
#[error("Unable to write the third line of the effect description")]
|
||||
EffectDescriptionThird(#[source] util::WriteNullAsciiStringError),
|
||||
EffectDescriptionThird(#[source] null_ascii_string::WriteError),
|
||||
|
||||
/// Unable to write the fourth support effect description
|
||||
#[error("Unable to write the fourth line of the effect description")]
|
||||
EffectDescriptionFourth(#[source] util::WriteNullAsciiStringError),
|
||||
EffectDescriptionFourth(#[source] null_ascii_string::WriteError),
|
||||
|
||||
/// Unable to write the circle move
|
||||
#[error("Unable to write the circle move")]
|
||||
@@ -209,7 +213,7 @@ impl Bytes for Digimon {
|
||||
|
||||
fn from_bytes(bytes: &Self::ByteArray) -> Result<Self, Self::FromError> {
|
||||
// Split bytes
|
||||
let bytes = util::array_split!(bytes,
|
||||
let bytes = array_split!(bytes,
|
||||
name : [0x15],
|
||||
unknown_15 : [0x2],
|
||||
speciality_level : 0x1,
|
||||
@@ -236,7 +240,7 @@ impl Bytes for Digimon {
|
||||
|
||||
// Return the struct after building it
|
||||
Ok(Self {
|
||||
name: util::read_null_ascii_string(bytes.name).map_err(FromBytesError::Name)?.to_ascii_string(),
|
||||
name: bytes.name.read_string().map_err(FromBytesError::Name)?.to_ascii_string(),
|
||||
|
||||
speciality: Speciality::from_bytes(&((bytes.speciality_level & 0xF0) >> 4)).map_err(FromBytesError::Speciality)?,
|
||||
|
||||
@@ -269,16 +273,24 @@ impl Bytes for Digimon {
|
||||
effect_arrow_color: Option::<ArrowColor>::from_bytes(bytes.effect_arrow_color).map_err(FromBytesError::ArrowColor)?,
|
||||
|
||||
effect_description: [
|
||||
util::read_null_ascii_string(bytes.effect_description_0)
|
||||
bytes
|
||||
.effect_description_0
|
||||
.read_string()
|
||||
.map_err(FromBytesError::EffectDescriptionFirst)?
|
||||
.to_ascii_string(),
|
||||
util::read_null_ascii_string(bytes.effect_description_1)
|
||||
bytes
|
||||
.effect_description_1
|
||||
.read_string()
|
||||
.map_err(FromBytesError::EffectDescriptionSecond)?
|
||||
.to_ascii_string(),
|
||||
util::read_null_ascii_string(bytes.effect_description_2)
|
||||
bytes
|
||||
.effect_description_2
|
||||
.read_string()
|
||||
.map_err(FromBytesError::EffectDescriptionThird)?
|
||||
.to_ascii_string(),
|
||||
util::read_null_ascii_string(bytes.effect_description_3)
|
||||
bytes
|
||||
.effect_description_3
|
||||
.read_string()
|
||||
.map_err(FromBytesError::EffectDescriptionFourth)?
|
||||
.to_ascii_string(),
|
||||
],
|
||||
@@ -292,7 +304,7 @@ impl Bytes for Digimon {
|
||||
|
||||
fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError> {
|
||||
// Split bytes
|
||||
let bytes = util::array_split_mut!(bytes,
|
||||
let bytes = array_split_mut!(bytes,
|
||||
name : [0x15],
|
||||
unknown_15 : [0x2],
|
||||
speciality_level : 0x1,
|
||||
@@ -318,7 +330,7 @@ impl Bytes for Digimon {
|
||||
);
|
||||
|
||||
// Name
|
||||
util::write_null_ascii_string(self.name.as_ref(), bytes.name).map_err(ToBytesError::Name)?;
|
||||
bytes.name.write_string(&self.name).map_err(ToBytesError::Name)?;
|
||||
|
||||
// Speciality / Level
|
||||
{
|
||||
@@ -356,13 +368,21 @@ impl Bytes for Digimon {
|
||||
|
||||
Option::<ArrowColor>::to_bytes(&self.effect_arrow_color, bytes.effect_arrow_color).into_ok();
|
||||
|
||||
util::write_null_ascii_string(self.effect_description[0].as_ref(), bytes.effect_description_0)
|
||||
bytes
|
||||
.effect_description_0
|
||||
.write_string(&self.effect_description[0])
|
||||
.map_err(ToBytesError::EffectDescriptionFirst)?;
|
||||
util::write_null_ascii_string(self.effect_description[1].as_ref(), bytes.effect_description_1)
|
||||
bytes
|
||||
.effect_description_1
|
||||
.write_string(&self.effect_description[1])
|
||||
.map_err(ToBytesError::EffectDescriptionSecond)?;
|
||||
util::write_null_ascii_string(self.effect_description[2].as_ref(), bytes.effect_description_2)
|
||||
bytes
|
||||
.effect_description_2
|
||||
.write_string(&self.effect_description[2])
|
||||
.map_err(ToBytesError::EffectDescriptionThird)?;
|
||||
util::write_null_ascii_string(self.effect_description[3].as_ref(), bytes.effect_description_3)
|
||||
bytes
|
||||
.effect_description_3
|
||||
.write_string(&self.effect_description[3])
|
||||
.map_err(ToBytesError::EffectDescriptionFourth)?;
|
||||
|
||||
// Unknown
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
#![doc(include = "digivolve.md")]
|
||||
|
||||
// Imports
|
||||
use crate::game::{util, Bytes};
|
||||
use crate::game::{
|
||||
util::{
|
||||
array_split, array_split_mut,
|
||||
null_ascii_string::{self, NullAsciiString},
|
||||
},
|
||||
Bytes,
|
||||
};
|
||||
|
||||
/// A digivolve card
|
||||
///
|
||||
@@ -29,23 +35,23 @@ pub struct Digivolve {
|
||||
pub enum FromBytesError {
|
||||
/// Unable to read the digimon name
|
||||
#[error("Unable to read the digimon name")]
|
||||
Name(#[source] util::ReadNullAsciiStringError),
|
||||
Name(#[source] null_ascii_string::ReadError),
|
||||
|
||||
/// Unable to read the first support effect description
|
||||
#[error("Unable to read the first line of the effect description")]
|
||||
EffectDescriptionFirst(#[source] util::ReadNullAsciiStringError),
|
||||
EffectDescriptionFirst(#[source] null_ascii_string::ReadError),
|
||||
|
||||
/// Unable to read the second support effect description
|
||||
#[error("Unable to read the second line of the effect description")]
|
||||
EffectDescriptionSecond(#[source] util::ReadNullAsciiStringError),
|
||||
EffectDescriptionSecond(#[source] null_ascii_string::ReadError),
|
||||
|
||||
/// Unable to read the third support effect description
|
||||
#[error("Unable to read the third line of the effect description")]
|
||||
EffectDescriptionThird(#[source] util::ReadNullAsciiStringError),
|
||||
EffectDescriptionThird(#[source] null_ascii_string::ReadError),
|
||||
|
||||
/// Unable to read the fourth support effect description
|
||||
#[error("Unable to read the fourth line of the effect description")]
|
||||
EffectDescriptionFourth(#[source] util::ReadNullAsciiStringError),
|
||||
EffectDescriptionFourth(#[source] null_ascii_string::ReadError),
|
||||
}
|
||||
|
||||
/// Error type for [`Bytes::to_bytes`]
|
||||
@@ -53,23 +59,23 @@ pub enum FromBytesError {
|
||||
pub enum ToBytesError {
|
||||
/// Unable to write the digimon name
|
||||
#[error("Unable to write the digimon name")]
|
||||
Name(#[source] util::WriteNullAsciiStringError),
|
||||
Name(#[source] null_ascii_string::WriteError),
|
||||
|
||||
/// Unable to write the first support effect description
|
||||
#[error("Unable to write the first line of the effect description")]
|
||||
EffectDescriptionFirst(#[source] util::WriteNullAsciiStringError),
|
||||
EffectDescriptionFirst(#[source] null_ascii_string::WriteError),
|
||||
|
||||
/// Unable to write the second support effect description
|
||||
#[error("Unable to write the second line of the effect description")]
|
||||
EffectDescriptionSecond(#[source] util::WriteNullAsciiStringError),
|
||||
EffectDescriptionSecond(#[source] null_ascii_string::WriteError),
|
||||
|
||||
/// Unable to write the third support effect description
|
||||
#[error("Unable to write the third line of the effect description")]
|
||||
EffectDescriptionThird(#[source] util::WriteNullAsciiStringError),
|
||||
EffectDescriptionThird(#[source] null_ascii_string::WriteError),
|
||||
|
||||
/// Unable to write the fourth support effect description
|
||||
#[error("Unable to write the fourth line of the effect description")]
|
||||
EffectDescriptionFourth(#[source] util::WriteNullAsciiStringError),
|
||||
EffectDescriptionFourth(#[source] null_ascii_string::WriteError),
|
||||
}
|
||||
|
||||
impl Bytes for Digivolve {
|
||||
@@ -79,7 +85,7 @@ impl Bytes for Digivolve {
|
||||
|
||||
fn from_bytes(bytes: &Self::ByteArray) -> Result<Self, Self::FromError> {
|
||||
// Split bytes
|
||||
let bytes = util::array_split!(bytes,
|
||||
let bytes = array_split!(bytes,
|
||||
name : [0x15],
|
||||
unknown_15 : [0x3],
|
||||
effect_description_0: [0x15],
|
||||
@@ -90,20 +96,28 @@ impl Bytes for Digivolve {
|
||||
|
||||
Ok(Self {
|
||||
// Name
|
||||
name: util::read_null_ascii_string(bytes.name).map_err(FromBytesError::Name)?.to_ascii_string(),
|
||||
name: bytes.name.read_string().map_err(FromBytesError::Name)?.to_ascii_string(),
|
||||
|
||||
// Effect
|
||||
effect_description: [
|
||||
util::read_null_ascii_string(bytes.effect_description_0)
|
||||
bytes
|
||||
.effect_description_0
|
||||
.read_string()
|
||||
.map_err(FromBytesError::EffectDescriptionFirst)?
|
||||
.to_ascii_string(),
|
||||
util::read_null_ascii_string(bytes.effect_description_1)
|
||||
bytes
|
||||
.effect_description_1
|
||||
.read_string()
|
||||
.map_err(FromBytesError::EffectDescriptionSecond)?
|
||||
.to_ascii_string(),
|
||||
util::read_null_ascii_string(bytes.effect_description_2)
|
||||
bytes
|
||||
.effect_description_2
|
||||
.read_string()
|
||||
.map_err(FromBytesError::EffectDescriptionThird)?
|
||||
.to_ascii_string(),
|
||||
util::read_null_ascii_string(bytes.effect_description_3)
|
||||
bytes
|
||||
.effect_description_3
|
||||
.read_string()
|
||||
.map_err(FromBytesError::EffectDescriptionFourth)?
|
||||
.to_ascii_string(),
|
||||
],
|
||||
@@ -115,7 +129,7 @@ impl Bytes for Digivolve {
|
||||
|
||||
fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError> {
|
||||
// Split bytes
|
||||
let bytes = util::array_split_mut!(bytes,
|
||||
let bytes = array_split_mut!(bytes,
|
||||
name : [0x15],
|
||||
unknown_15 : [0x3],
|
||||
effect_description_0: [0x15],
|
||||
@@ -125,16 +139,24 @@ impl Bytes for Digivolve {
|
||||
);
|
||||
|
||||
// Name
|
||||
util::write_null_ascii_string(self.name.as_ref(), bytes.name).map_err(ToBytesError::Name)?;
|
||||
bytes.name.write_string(&self.name).map_err(ToBytesError::Name)?;
|
||||
|
||||
// Effects
|
||||
util::write_null_ascii_string(self.effect_description[0].as_ref(), bytes.effect_description_0)
|
||||
bytes
|
||||
.effect_description_0
|
||||
.write_string(&self.effect_description[0])
|
||||
.map_err(ToBytesError::EffectDescriptionFirst)?;
|
||||
util::write_null_ascii_string(self.effect_description[1].as_ref(), bytes.effect_description_1)
|
||||
bytes
|
||||
.effect_description_1
|
||||
.write_string(&self.effect_description[1])
|
||||
.map_err(ToBytesError::EffectDescriptionSecond)?;
|
||||
util::write_null_ascii_string(self.effect_description[2].as_ref(), bytes.effect_description_2)
|
||||
bytes
|
||||
.effect_description_2
|
||||
.write_string(&self.effect_description[2])
|
||||
.map_err(ToBytesError::EffectDescriptionThird)?;
|
||||
util::write_null_ascii_string(self.effect_description[3].as_ref(), bytes.effect_description_3)
|
||||
bytes
|
||||
.effect_description_3
|
||||
.write_string(&self.effect_description[3])
|
||||
.map_err(ToBytesError::EffectDescriptionFourth)?;
|
||||
|
||||
// Unknown
|
||||
|
||||
@@ -3,7 +3,11 @@
|
||||
// Imports
|
||||
use crate::game::{
|
||||
card::property::{self, ArrowColor, Effect, EffectCondition},
|
||||
util, Bytes,
|
||||
util::{
|
||||
array_split, array_split_mut,
|
||||
null_ascii_string::{self, NullAsciiString},
|
||||
},
|
||||
Bytes,
|
||||
};
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
@@ -45,23 +49,23 @@ pub struct Item {
|
||||
pub enum FromBytesError {
|
||||
/// Unable to read the digimon name
|
||||
#[error("Unable to read the digimon name")]
|
||||
Name(#[source] util::ReadNullAsciiStringError),
|
||||
Name(#[source] null_ascii_string::ReadError),
|
||||
|
||||
/// Unable to read the first support effect description
|
||||
#[error("Unable to read the first line of the effect description")]
|
||||
EffectDescriptionFirst(#[source] util::ReadNullAsciiStringError),
|
||||
EffectDescriptionFirst(#[source] null_ascii_string::ReadError),
|
||||
|
||||
/// Unable to read the second support effect description
|
||||
#[error("Unable to read the second line of the effect description")]
|
||||
EffectDescriptionSecond(#[source] util::ReadNullAsciiStringError),
|
||||
EffectDescriptionSecond(#[source] null_ascii_string::ReadError),
|
||||
|
||||
/// Unable to read the third support effect description
|
||||
#[error("Unable to read the third line of the effect description")]
|
||||
EffectDescriptionThird(#[source] util::ReadNullAsciiStringError),
|
||||
EffectDescriptionThird(#[source] null_ascii_string::ReadError),
|
||||
|
||||
/// Unable to read the fourth support effect description
|
||||
#[error("Unable to read the fourth line of the effect description")]
|
||||
EffectDescriptionFourth(#[source] util::ReadNullAsciiStringError),
|
||||
EffectDescriptionFourth(#[source] null_ascii_string::ReadError),
|
||||
|
||||
/// An unknown effect arrow color was found
|
||||
#[error("Unknown effect arrow color found")]
|
||||
@@ -93,23 +97,23 @@ pub enum FromBytesError {
|
||||
pub enum ToBytesError {
|
||||
/// Unable to write the digimon name
|
||||
#[error("Unable to write the digimon name")]
|
||||
Name(#[source] util::WriteNullAsciiStringError),
|
||||
Name(#[source] null_ascii_string::WriteError),
|
||||
|
||||
/// Unable to write the first support effect description
|
||||
#[error("Unable to write the first line of the effect description")]
|
||||
EffectDescriptionFirst(#[source] util::WriteNullAsciiStringError),
|
||||
EffectDescriptionFirst(#[source] null_ascii_string::WriteError),
|
||||
|
||||
/// Unable to write the second support effect description
|
||||
#[error("Unable to write the second line of the effect description")]
|
||||
EffectDescriptionSecond(#[source] util::WriteNullAsciiStringError),
|
||||
EffectDescriptionSecond(#[source] null_ascii_string::WriteError),
|
||||
|
||||
/// Unable to write the third support effect description
|
||||
#[error("Unable to write the third line of the effect description")]
|
||||
EffectDescriptionThird(#[source] util::WriteNullAsciiStringError),
|
||||
EffectDescriptionThird(#[source] null_ascii_string::WriteError),
|
||||
|
||||
/// Unable to write the fourth support effect description
|
||||
#[error("Unable to write the fourth line of the effect description")]
|
||||
EffectDescriptionFourth(#[source] util::WriteNullAsciiStringError),
|
||||
EffectDescriptionFourth(#[source] null_ascii_string::WriteError),
|
||||
|
||||
/// Unable to write the first effect
|
||||
#[error("Unable to write the first effect")]
|
||||
@@ -131,7 +135,7 @@ impl Bytes for Item {
|
||||
|
||||
fn from_bytes(bytes: &Self::ByteArray) -> Result<Self, Self::FromError> {
|
||||
// Split bytes
|
||||
let bytes = util::array_split!(bytes,
|
||||
let bytes = array_split!(bytes,
|
||||
name : [0x15],
|
||||
unknown_15 : [0x4],
|
||||
condition_first : [0x20],
|
||||
@@ -148,7 +152,7 @@ impl Bytes for Item {
|
||||
|
||||
// And return the struct
|
||||
Ok(Self {
|
||||
name: util::read_null_ascii_string(bytes.name).map_err(FromBytesError::Name)?.to_ascii_string(),
|
||||
name: bytes.name.read_string().map_err(FromBytesError::Name)?.to_ascii_string(),
|
||||
|
||||
// Effects
|
||||
effect_conditions: [
|
||||
@@ -165,16 +169,24 @@ impl Bytes for Item {
|
||||
effect_arrow_color: Option::<ArrowColor>::from_bytes(bytes.effect_arrow_color).map_err(FromBytesError::ArrowColor)?,
|
||||
|
||||
effect_description: [
|
||||
util::read_null_ascii_string(bytes.effect_description_0)
|
||||
bytes
|
||||
.effect_description_0
|
||||
.read_string()
|
||||
.map_err(FromBytesError::EffectDescriptionFirst)?
|
||||
.to_ascii_string(),
|
||||
util::read_null_ascii_string(bytes.effect_description_1)
|
||||
bytes
|
||||
.effect_description_1
|
||||
.read_string()
|
||||
.map_err(FromBytesError::EffectDescriptionSecond)?
|
||||
.to_ascii_string(),
|
||||
util::read_null_ascii_string(bytes.effect_description_2)
|
||||
bytes
|
||||
.effect_description_2
|
||||
.read_string()
|
||||
.map_err(FromBytesError::EffectDescriptionThird)?
|
||||
.to_ascii_string(),
|
||||
util::read_null_ascii_string(bytes.effect_description_3)
|
||||
bytes
|
||||
.effect_description_3
|
||||
.read_string()
|
||||
.map_err(FromBytesError::EffectDescriptionFourth)?
|
||||
.to_ascii_string(),
|
||||
],
|
||||
@@ -186,7 +198,7 @@ impl Bytes for Item {
|
||||
|
||||
fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError> {
|
||||
// Split bytes
|
||||
let bytes = util::array_split_mut!(bytes,
|
||||
let bytes = array_split_mut!(bytes,
|
||||
name : [0x15],
|
||||
unknown_15 : [0x4],
|
||||
condition_first : [0x20],
|
||||
@@ -202,7 +214,7 @@ impl Bytes for Item {
|
||||
);
|
||||
|
||||
// Name
|
||||
util::write_null_ascii_string(self.name.as_ref(), bytes.name).map_err(ToBytesError::Name)?;
|
||||
bytes.name.write_string(&self.name).map_err(ToBytesError::Name)?;
|
||||
|
||||
// Effects
|
||||
self.effect_conditions[0].to_bytes(bytes.condition_first).into_ok();
|
||||
@@ -214,13 +226,21 @@ impl Bytes for Item {
|
||||
|
||||
Option::<ArrowColor>::to_bytes(&self.effect_arrow_color, bytes.effect_arrow_color).into_ok();
|
||||
|
||||
util::write_null_ascii_string(self.effect_description[0].as_ref(), bytes.effect_description_0)
|
||||
bytes
|
||||
.effect_description_0
|
||||
.write_string(&self.effect_description[0])
|
||||
.map_err(ToBytesError::EffectDescriptionFirst)?;
|
||||
util::write_null_ascii_string(self.effect_description[1].as_ref(), bytes.effect_description_1)
|
||||
bytes
|
||||
.effect_description_1
|
||||
.write_string(&self.effect_description[1])
|
||||
.map_err(ToBytesError::EffectDescriptionSecond)?;
|
||||
util::write_null_ascii_string(self.effect_description[2].as_ref(), bytes.effect_description_2)
|
||||
bytes
|
||||
.effect_description_2
|
||||
.write_string(&self.effect_description[2])
|
||||
.map_err(ToBytesError::EffectDescriptionThird)?;
|
||||
util::write_null_ascii_string(self.effect_description[3].as_ref(), bytes.effect_description_3)
|
||||
bytes
|
||||
.effect_description_3
|
||||
.write_string(&self.effect_description[3])
|
||||
.map_err(ToBytesError::EffectDescriptionFourth)?;
|
||||
|
||||
// Unknown
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
// Imports
|
||||
use crate::game::{
|
||||
card::property::{self, AttackType, DigimonProperty, EffectOperation, PlayerType, Slot},
|
||||
util, Bytes,
|
||||
util::{array_split, array_split_mut},
|
||||
Bytes,
|
||||
};
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
@@ -214,7 +215,7 @@ impl Bytes for Effect {
|
||||
use Slot::{Dp as DpSlot, Hand, Offline as OfflineDeck, Online as OnlineDeck};
|
||||
|
||||
// Get all byte arrays we need
|
||||
let bytes = util::array_split!(bytes,
|
||||
let bytes = array_split!(bytes,
|
||||
effect_type: 0x1,
|
||||
a : 0x1,
|
||||
_unknown_3 : 0x1,
|
||||
@@ -323,7 +324,7 @@ impl Bytes for Effect {
|
||||
use Slot::{Dp as DpSlot, Hand, Offline as OfflineDeck, Online as OnlineDeck};
|
||||
|
||||
// Get all byte arrays we need
|
||||
let bytes = util::array_split_mut!(bytes,
|
||||
let bytes = array_split_mut!(bytes,
|
||||
effect_type: 0x1,
|
||||
a : 0x1,
|
||||
_unknown_3 : 0x1,
|
||||
@@ -464,7 +465,7 @@ impl Bytes for Option<Effect> {
|
||||
|
||||
// `bytes` should include the `exists` byte
|
||||
fn from_bytes(bytes: &Self::ByteArray) -> Result<Self, Self::FromError> {
|
||||
let bytes = util::array_split!(bytes,
|
||||
let bytes = array_split!(bytes,
|
||||
exists : 0x1,
|
||||
effect : [0xf],
|
||||
);
|
||||
@@ -479,7 +480,7 @@ impl Bytes for Option<Effect> {
|
||||
}
|
||||
|
||||
fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError> {
|
||||
let bytes = util::array_split_mut!(bytes,
|
||||
let bytes = array_split_mut!(bytes,
|
||||
exists: 0x1,
|
||||
effect: [0xf],
|
||||
);
|
||||
|
||||
@@ -3,7 +3,8 @@
|
||||
// Imports
|
||||
use crate::game::{
|
||||
card::property::{self, DigimonProperty, EffectConditionOperation},
|
||||
util, Bytes,
|
||||
util::{array_split, array_split_mut},
|
||||
Bytes,
|
||||
};
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
@@ -64,7 +65,7 @@ impl Bytes for EffectCondition {
|
||||
type ToError = !;
|
||||
|
||||
fn from_bytes(bytes: &Self::ByteArray) -> Result<Self, Self::FromError> {
|
||||
let bytes = util::array_split!(bytes,
|
||||
let bytes = array_split!(bytes,
|
||||
misfire : 0x1,
|
||||
unknown_1 : 0x1,
|
||||
property_cmp: 0x1,
|
||||
@@ -96,7 +97,7 @@ impl Bytes for EffectCondition {
|
||||
}
|
||||
|
||||
fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError> {
|
||||
let bytes = util::array_split_mut!(bytes,
|
||||
let bytes = array_split_mut!(bytes,
|
||||
misfire : 0x1,
|
||||
unknown_1 : 0x1,
|
||||
property_cmp: 0x1,
|
||||
|
||||
@@ -5,7 +5,13 @@
|
||||
mod test;
|
||||
|
||||
// Imports
|
||||
use crate::game::{util, Bytes};
|
||||
use crate::game::{
|
||||
util::{
|
||||
array_split, array_split_mut,
|
||||
null_ascii_string::{self, NullAsciiString},
|
||||
},
|
||||
Bytes,
|
||||
};
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
/// A digimon's move
|
||||
@@ -27,7 +33,7 @@ pub struct Move {
|
||||
pub enum FromBytesError {
|
||||
/// Unable to read the move name
|
||||
#[error("Unable to read the move name")]
|
||||
Name(#[source] util::ReadNullAsciiStringError),
|
||||
Name(#[source] null_ascii_string::ReadError),
|
||||
}
|
||||
|
||||
/// Error type for [`Bytes::to_bytes`]
|
||||
@@ -35,7 +41,7 @@ pub enum FromBytesError {
|
||||
pub enum ToBytesError {
|
||||
/// Unable to write the move name
|
||||
#[error("Unable to write the move name")]
|
||||
Name(#[source] util::WriteNullAsciiStringError),
|
||||
Name(#[source] null_ascii_string::WriteError),
|
||||
}
|
||||
|
||||
// Bytes
|
||||
@@ -46,7 +52,7 @@ impl Bytes for Move {
|
||||
|
||||
fn from_bytes(bytes: &Self::ByteArray) -> Result<Self, Self::FromError> {
|
||||
// Get all byte arrays we need
|
||||
let bytes = util::array_split!(bytes,
|
||||
let bytes = array_split!(bytes,
|
||||
power : [0x2],
|
||||
unknown: [0x4],
|
||||
name : [0x16],
|
||||
@@ -54,7 +60,7 @@ impl Bytes for Move {
|
||||
|
||||
// Return the move
|
||||
Ok(Self {
|
||||
name: util::read_null_ascii_string(bytes.name).map_err(FromBytesError::Name)?.to_ascii_string(),
|
||||
name: bytes.name.read_string().map_err(FromBytesError::Name)?.to_ascii_string(),
|
||||
power: LittleEndian::read_u16(bytes.power),
|
||||
unknown: LittleEndian::read_u32(bytes.unknown),
|
||||
})
|
||||
@@ -62,14 +68,14 @@ impl Bytes for Move {
|
||||
|
||||
fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError> {
|
||||
// Get all byte arrays we need
|
||||
let bytes = util::array_split_mut!(bytes,
|
||||
let bytes = array_split_mut!(bytes,
|
||||
power : [0x2],
|
||||
unknown: [0x4],
|
||||
name : [0x16],
|
||||
);
|
||||
|
||||
// Write the name
|
||||
util::write_null_ascii_string(self.name.as_ref(), bytes.name).map_err(ToBytesError::Name)?;
|
||||
bytes.name.write_string(&self.name).map_err(ToBytesError::Name)?;
|
||||
|
||||
// Then write the power and the unknown
|
||||
LittleEndian::write_u16(bytes.power, self.power);
|
||||
|
||||
@@ -8,7 +8,8 @@ use crate::{
|
||||
property::{self, CardType},
|
||||
Digimon, Digivolve, Item,
|
||||
},
|
||||
util, Bytes,
|
||||
util::array_split_mut,
|
||||
Bytes,
|
||||
},
|
||||
io::{address::Data, GameFile},
|
||||
};
|
||||
@@ -396,7 +397,7 @@ impl Table {
|
||||
// Write header
|
||||
let mut header_bytes = [0u8; 0x8];
|
||||
{
|
||||
let bytes = util::array_split_mut!(&mut header_bytes,
|
||||
let bytes = array_split_mut!(&mut header_bytes,
|
||||
magic: [0x4],
|
||||
|
||||
digimons_len: [0x2],
|
||||
@@ -426,7 +427,7 @@ impl Table {
|
||||
|
||||
// Card bytes
|
||||
let mut card_bytes = [0; 0x3 + CardType::Digimon.byte_size() + 0x1];
|
||||
let bytes = util::array_split_mut!(&mut card_bytes,
|
||||
let bytes = array_split_mut!(&mut card_bytes,
|
||||
header_id : [0x2],
|
||||
header_type: 1,
|
||||
digimon : [CardType::Digimon.byte_size()],
|
||||
@@ -455,7 +456,7 @@ impl Table {
|
||||
|
||||
// Card bytes
|
||||
let mut card_bytes = [0; 0x3 + CardType::Item.byte_size() + 0x1];
|
||||
let bytes = util::array_split_mut!(&mut card_bytes,
|
||||
let bytes = array_split_mut!(&mut card_bytes,
|
||||
header_id : [0x2],
|
||||
header_type: 1,
|
||||
item : [CardType::Item.byte_size()],
|
||||
@@ -483,7 +484,7 @@ impl Table {
|
||||
|
||||
// Card bytes
|
||||
let mut card_bytes = [0; 0x3 + CardType::Digivolve.byte_size() + 0x1];
|
||||
let bytes = util::array_split_mut!(&mut card_bytes,
|
||||
let bytes = array_split_mut!(&mut card_bytes,
|
||||
header_id : [0x2],
|
||||
header_type: 1,
|
||||
item : [CardType::Digivolve.byte_size()],
|
||||
|
||||
@@ -1,7 +1,13 @@
|
||||
//! Decks
|
||||
|
||||
// Imports
|
||||
use crate::game::{util, Bytes};
|
||||
use crate::game::{
|
||||
util::{
|
||||
array_split, array_split_mut,
|
||||
null_ascii_string::{self, NullAsciiString},
|
||||
},
|
||||
Bytes,
|
||||
};
|
||||
use byteorder::{ByteOrder, LittleEndian};
|
||||
|
||||
/// A deck
|
||||
@@ -26,11 +32,11 @@ pub struct Deck {
|
||||
pub enum FromBytesError {
|
||||
/// Unable to read the deck name
|
||||
#[error("Unable to read the deck name")]
|
||||
Name(#[source] util::ReadMaybeNullAsciiStringError),
|
||||
Name(#[source] null_ascii_string::ReadError),
|
||||
|
||||
/// Unable to read the deck owner
|
||||
#[error("Unable to read the deck owner")]
|
||||
Owner(#[source] util::ReadMaybeNullAsciiStringError),
|
||||
Owner(#[source] null_ascii_string::ReadError),
|
||||
}
|
||||
|
||||
/// Error type for [`Bytes::to_bytes`]
|
||||
@@ -38,11 +44,11 @@ pub enum FromBytesError {
|
||||
pub enum ToBytesError {
|
||||
/// Unable to write the deck name
|
||||
#[error("Unable to write the deck name")]
|
||||
Name(#[source] util::WriteMaybeNullAsciiStringError),
|
||||
Name(#[source] null_ascii_string::WriteError),
|
||||
|
||||
/// Unable to write the deck owner
|
||||
#[error("Unable to write the deck owner")]
|
||||
Owner(#[source] util::WriteMaybeNullAsciiStringError),
|
||||
Owner(#[source] null_ascii_string::WriteError),
|
||||
}
|
||||
|
||||
impl Bytes for Deck {
|
||||
@@ -52,7 +58,7 @@ impl Bytes for Deck {
|
||||
|
||||
fn from_bytes(bytes: &Self::ByteArray) -> Result<Self, Self::FromError> {
|
||||
// Split the bytes
|
||||
let bytes = util::array_split!(bytes,
|
||||
let bytes = array_split!(bytes,
|
||||
deck : [0x3c],
|
||||
name : [0x13],
|
||||
owner : [0x13],
|
||||
@@ -60,13 +66,9 @@ impl Bytes for Deck {
|
||||
);
|
||||
|
||||
Ok(Self {
|
||||
name: util::read_maybe_null_ascii_string(bytes.name)
|
||||
.map_err(FromBytesError::Name)?
|
||||
.to_ascii_string(),
|
||||
name: bytes.name.read_string().map_err(FromBytesError::Name)?.to_ascii_string(),
|
||||
|
||||
owner: util::read_maybe_null_ascii_string(bytes.owner)
|
||||
.map_err(FromBytesError::Owner)?
|
||||
.to_ascii_string(),
|
||||
owner: bytes.owner.read_string().map_err(FromBytesError::Owner)?.to_ascii_string(),
|
||||
|
||||
cards: {
|
||||
let mut cards_buf = [0; 0x1e];
|
||||
@@ -84,7 +86,7 @@ impl Bytes for Deck {
|
||||
|
||||
fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError> {
|
||||
// Split the bytes
|
||||
let bytes = util::array_split_mut!(bytes,
|
||||
let bytes = array_split_mut!(bytes,
|
||||
deck : [0x3c],
|
||||
name : [0x13],
|
||||
owner : [0x13],
|
||||
@@ -92,8 +94,8 @@ impl Bytes for Deck {
|
||||
);
|
||||
|
||||
// Name / Owner
|
||||
util::write_maybe_null_ascii_string(&self.name, bytes.name).map_err(ToBytesError::Name)?;
|
||||
util::write_maybe_null_ascii_string(&self.owner, bytes.owner).map_err(ToBytesError::Owner)?;
|
||||
bytes.name.write_string(&self.name).map_err(ToBytesError::Name)?;
|
||||
bytes.owner.write_string(&self.owner).map_err(ToBytesError::Owner)?;
|
||||
|
||||
// Deck
|
||||
for (card_id, card) in self.cards.iter().enumerate() {
|
||||
|
||||
216
src/game/util.rs
216
src/game/util.rs
@@ -6,215 +6,9 @@
|
||||
//! All items in this module will eventually be deprecated and moved
|
||||
//! somewhere else, but this change might take some time.
|
||||
|
||||
pub macro array_split {
|
||||
(
|
||||
$arr:expr,
|
||||
$(
|
||||
$name:ident :
|
||||
// Modules
|
||||
pub mod array_split;
|
||||
pub mod null_ascii_string;
|
||||
|
||||
$( [$arr_size:expr] )?
|
||||
$( $val_size:literal )?
|
||||
|
||||
),* $(,)?
|
||||
) => {{
|
||||
#![allow(
|
||||
clippy::used_underscore_binding,
|
||||
clippy::ptr_offset_with_cast,
|
||||
clippy::indexing_slicing,
|
||||
)]
|
||||
|
||||
// Struct holding all fields
|
||||
struct Fields<'a, T> {
|
||||
$(
|
||||
$name:
|
||||
|
||||
$( &'a [T; $arr_size], )?
|
||||
$( &'a T, #[cfg(invalid)] __field: [u8; $val_size], )?
|
||||
)*
|
||||
}
|
||||
|
||||
// Get everything from `array_refs`
|
||||
let (
|
||||
$(
|
||||
$name
|
||||
),*
|
||||
) = ::arrayref::array_refs!(
|
||||
$arr,
|
||||
$(
|
||||
$( $arr_size )?
|
||||
$( $val_size )?
|
||||
),*
|
||||
);
|
||||
|
||||
// And return the fields
|
||||
Fields {
|
||||
$(
|
||||
$name
|
||||
$( : &( $name[$val_size - $val_size] ) )?
|
||||
,
|
||||
)*
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
pub macro array_split_mut {
|
||||
(
|
||||
$arr:expr,
|
||||
$(
|
||||
$name:ident :
|
||||
|
||||
$( [$arr_size:expr] )?
|
||||
$( $val_size:literal )?
|
||||
|
||||
),* $(,)?
|
||||
) => {{
|
||||
#![allow(
|
||||
clippy::used_underscore_binding,
|
||||
clippy::ptr_offset_with_cast,
|
||||
clippy::indexing_slicing,
|
||||
)]
|
||||
|
||||
// Struct holding all fields
|
||||
struct Fields<'a, T> {
|
||||
$(
|
||||
$name:
|
||||
|
||||
$( &'a mut [T; $arr_size], )?
|
||||
$( &'a mut T, #[cfg(invalid)] __field: [u8; $val_size], )?
|
||||
)*
|
||||
}
|
||||
|
||||
// Get everything from `array_refs`
|
||||
let (
|
||||
$(
|
||||
$name
|
||||
),*
|
||||
) = ::arrayref::mut_array_refs!(
|
||||
$arr,
|
||||
$(
|
||||
$( $arr_size )?
|
||||
$( $val_size )?
|
||||
),*
|
||||
);
|
||||
|
||||
// And return the fields
|
||||
Fields {
|
||||
$(
|
||||
$name
|
||||
$( : &mut ( $name[$val_size - $val_size] ) )?
|
||||
,
|
||||
)*
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
/// Error type for [`read_null_ascii_string`]
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug, thiserror::Error)]
|
||||
pub enum ReadNullAsciiStringError {
|
||||
/// No null was found in the string
|
||||
#[error("No null was found on the buffer")]
|
||||
NoNull,
|
||||
|
||||
/// The string was not ascii
|
||||
#[error("The buffer did not contain valid Ascii")]
|
||||
NotAscii(#[source] ascii::AsAsciiStrError),
|
||||
}
|
||||
|
||||
/// Reads a null-terminated ascii string from a buffer.
|
||||
pub fn read_null_ascii_string(buf: &impl AsRef<[u8]>) -> Result<&ascii::AsciiStr, ReadNullAsciiStringError> {
|
||||
// Find the first null and trim the buffer until it
|
||||
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).map_err(ReadNullAsciiStringError::NotAscii)
|
||||
}
|
||||
|
||||
/// Error type for [`read_maybe_null_ascii_string`]
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug, thiserror::Error)]
|
||||
pub enum ReadMaybeNullAsciiStringError {
|
||||
/// The string was not ascii
|
||||
#[error("The buffer did not contain valid Ascii")]
|
||||
NotAscii(#[source] ascii::AsAsciiStrError),
|
||||
}
|
||||
|
||||
/// Reads a possibly null-terminated ascii string from a buffer.
|
||||
pub fn read_maybe_null_ascii_string(buf: &impl AsRef<[u8]>) -> Result<&ascii::AsciiStr, ReadMaybeNullAsciiStringError> {
|
||||
// Find the first null and trim the buffer until it
|
||||
let buf = buf.as_ref();
|
||||
let buf = match buf.iter().position(|&b| b == 0) {
|
||||
Some(null_idx) => &buf[0..null_idx],
|
||||
None => buf,
|
||||
};
|
||||
|
||||
// Then convert it from Ascii
|
||||
ascii::AsciiStr::from_ascii(buf).map_err(ReadMaybeNullAsciiStringError::NotAscii)
|
||||
}
|
||||
|
||||
/// Error type for [`write_null_ascii_string`]
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug, thiserror::Error)]
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
pub enum WriteNullAsciiStringError {
|
||||
/// The input string was too large
|
||||
#[error("Input string was too large for buffer. ({}+1 / {})", input_len, buffer_len)]
|
||||
TooLarge { input_len: usize, buffer_len: usize },
|
||||
}
|
||||
|
||||
/// 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 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(),
|
||||
});
|
||||
}
|
||||
|
||||
// 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;
|
||||
|
||||
// And return Ok with the buffer
|
||||
Ok(buf)
|
||||
}
|
||||
|
||||
/// Error type for [`write_maybe_null_ascii_string`]
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug, thiserror::Error)]
|
||||
pub enum WriteMaybeNullAsciiStringError {
|
||||
/// The input string was too large
|
||||
#[error("Input string was too large for buffer. ({} / {})", input_len, buffer_len)]
|
||||
TooLarge {
|
||||
/// Length of input string
|
||||
input_len: usize,
|
||||
|
||||
/// Length of buffer
|
||||
buffer_len: usize,
|
||||
},
|
||||
}
|
||||
|
||||
/// Writes a possibly null-terminated ascii string to a buffer and returns it
|
||||
pub fn write_maybe_null_ascii_string<'a>(input: &ascii::AsciiStr, buf: &'a mut [u8]) -> Result<&'a mut [u8], WriteMaybeNullAsciiStringError> {
|
||||
// If the input string doesn't fit into the buffer, return Err
|
||||
if input.len() > buf.len() {
|
||||
return Err(WriteMaybeNullAsciiStringError::TooLarge {
|
||||
input_len: input.len(),
|
||||
buffer_len: buf.len(),
|
||||
});
|
||||
}
|
||||
|
||||
// Copy everything over to the slice
|
||||
// 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());
|
||||
|
||||
// If there's a character left, write it to null
|
||||
if let Some(null_byte) = buf.get_mut(input.len()) {
|
||||
*null_byte = 0;
|
||||
}
|
||||
|
||||
// And return Ok with the buffer
|
||||
Ok(buf)
|
||||
}
|
||||
// Exports
|
||||
pub use array_split::{array_split, array_split_mut};
|
||||
|
||||
109
src/game/util/array_split.rs
Normal file
109
src/game/util/array_split.rs
Normal file
@@ -0,0 +1,109 @@
|
||||
//! Array splitters
|
||||
|
||||
/// Splits an array into various members
|
||||
pub macro array_split {
|
||||
(
|
||||
$arr:expr,
|
||||
$(
|
||||
$name:ident :
|
||||
|
||||
$( [$arr_size:expr] )?
|
||||
$( $val_size:literal )?
|
||||
|
||||
),* $(,)?
|
||||
) => {{
|
||||
#![allow(
|
||||
clippy::used_underscore_binding,
|
||||
clippy::ptr_offset_with_cast,
|
||||
clippy::indexing_slicing,
|
||||
)]
|
||||
|
||||
// Struct holding all fields
|
||||
struct Fields<'a, T> {
|
||||
$(
|
||||
$name:
|
||||
|
||||
$( &'a [T; $arr_size], )?
|
||||
$( &'a T, #[cfg(invalid)] __field: [u8; $val_size], )?
|
||||
)*
|
||||
}
|
||||
|
||||
// Get everything from `array_refs`
|
||||
let (
|
||||
$(
|
||||
$name
|
||||
),*
|
||||
) = ::arrayref::array_refs!(
|
||||
$arr,
|
||||
$(
|
||||
$( $arr_size )?
|
||||
$( $val_size )?
|
||||
),*
|
||||
);
|
||||
|
||||
// And return the fields
|
||||
Fields {
|
||||
$(
|
||||
$name
|
||||
$( : &( $name[$val_size - $val_size] ) )?
|
||||
,
|
||||
)*
|
||||
}
|
||||
}}
|
||||
}
|
||||
|
||||
/// Splits an array into various members mutably
|
||||
#[allow(clippy::module_name_repetitions)] // `_mut` version should be in the same module
|
||||
pub macro array_split_mut {
|
||||
(
|
||||
$arr:expr,
|
||||
$(
|
||||
$name:ident :
|
||||
|
||||
$( [$arr_size:expr] )?
|
||||
$( $val_size:literal )?
|
||||
|
||||
),* $(,)?
|
||||
) => {{
|
||||
#![allow(
|
||||
clippy::used_underscore_binding,
|
||||
clippy::ptr_offset_with_cast,
|
||||
clippy::indexing_slicing,
|
||||
)]
|
||||
|
||||
// Struct holding all fields
|
||||
struct Fields<'a, T> {
|
||||
$(
|
||||
$name:
|
||||
|
||||
$( &'a mut [T; $arr_size], )?
|
||||
// Note: This `cfg` is simply done so that `__field` never appears.
|
||||
// The `__field` serves to identify when this part should be written.
|
||||
$( &'a mut T, #[cfg(invalid)] __field: [u8; $val_size], )?
|
||||
)*
|
||||
}
|
||||
|
||||
// Get everything from `array_refs`
|
||||
let (
|
||||
$(
|
||||
$name
|
||||
),*
|
||||
) = ::arrayref::mut_array_refs!(
|
||||
$arr,
|
||||
$(
|
||||
$( $arr_size )?
|
||||
$( $val_size )?
|
||||
),*
|
||||
);
|
||||
|
||||
// And return the fields
|
||||
Fields {
|
||||
$(
|
||||
$name
|
||||
// Note: This serves to turn a `&mut [u8; 1]` into a `&mut u8`.
|
||||
$( : &mut ( $name[$val_size - $val_size] ) )?
|
||||
,
|
||||
)*
|
||||
}
|
||||
}}
|
||||
}
|
||||
47
src/game/util/null_ascii_string.rs
Normal file
47
src/game/util/null_ascii_string.rs
Normal file
@@ -0,0 +1,47 @@
|
||||
//! Null-terminated ascii string helpers
|
||||
|
||||
// Modules
|
||||
pub mod error;
|
||||
|
||||
// Exports
|
||||
pub use error::{ReadError, WriteError};
|
||||
|
||||
/// Trait for reading null terminated ascii strings from a buffer
|
||||
pub trait NullAsciiString {
|
||||
/// Reads a null terminated ascii string from this buffer and returns it
|
||||
fn read_string(&self) -> Result<&ascii::AsciiStr, ReadError>;
|
||||
|
||||
/// Writes a null terminated ascii string to this buffer and returns it
|
||||
fn write_string(&mut self, s: &ascii::AsciiStr) -> Result<&Self, WriteError>;
|
||||
}
|
||||
|
||||
impl NullAsciiString for [u8] {
|
||||
fn read_string(&self) -> Result<&ascii::AsciiStr, ReadError> {
|
||||
// Find the first null and trim the buffer until it
|
||||
let buf = match self.iter().position(|&b| b == b'\0') {
|
||||
Some(idx) => &self[0..idx],
|
||||
None => return Err(ReadError::NoNull),
|
||||
};
|
||||
|
||||
// Then convert it from Ascii
|
||||
ascii::AsciiStr::from_ascii(buf).map_err(ReadError::NotAscii)
|
||||
}
|
||||
|
||||
fn write_string(&mut self, input: &ascii::AsciiStr) -> Result<&Self, WriteError> {
|
||||
// If the input string doesn't fit into the buffer (excluding the null byte), return Err
|
||||
if input.len() >= self.len() {
|
||||
return Err(WriteError::TooLarge {
|
||||
input_len: input.len(),
|
||||
buffer_len: self.len(),
|
||||
});
|
||||
}
|
||||
|
||||
// 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
|
||||
self[0..input.len()].copy_from_slice(input.as_bytes());
|
||||
self[input.len()] = 0;
|
||||
|
||||
// And return Ok with the buffer
|
||||
Ok(self)
|
||||
}
|
||||
}
|
||||
22
src/game/util/null_ascii_string/error.rs
Normal file
22
src/game/util/null_ascii_string/error.rs
Normal file
@@ -0,0 +1,22 @@
|
||||
//! Errors
|
||||
|
||||
/// Error type for [`read`](super::read)
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug, thiserror::Error)]
|
||||
pub enum ReadError {
|
||||
/// No null was found in the string
|
||||
#[error("No null was found on the buffer")]
|
||||
NoNull,
|
||||
|
||||
/// The string was not ascii
|
||||
#[error("The buffer did not contain valid Ascii")]
|
||||
NotAscii(#[source] ascii::AsAsciiStrError),
|
||||
}
|
||||
|
||||
/// Error type for [`write`](super::read)
|
||||
#[derive(PartialEq, Eq, Clone, Copy, Debug, thiserror::Error)]
|
||||
#[allow(clippy::missing_docs_in_private_items)]
|
||||
pub enum WriteError {
|
||||
/// The input string was too large
|
||||
#[error("Input string was too large for buffer. ({}+1 / {})", input_len, buffer_len)]
|
||||
TooLarge { input_len: usize, buffer_len: usize },
|
||||
}
|
||||
@@ -79,7 +79,7 @@
|
||||
// Although we generally try to avoid this, this can happen due to our module organization.
|
||||
// In the future, this lint should be removed globally and only enabled for modules which
|
||||
// actually require the use of it.
|
||||
#![allow(clippy::module_inception)]
|
||||
#![allow(clippy::module_inception, clippy::module_name_repetitions)]
|
||||
// False positives:
|
||||
// TODO: Remove them in the future once they are no longer triggered.
|
||||
// We only slice arrays, which are verified at compile time. This
|
||||
|
||||
Reference in New Issue
Block a user