Moved Bytes interface to dcb-bytes crate.

Instead of implementing `Bytes for Option<T>`, a proxy is now used, as `dcb-bytes` is in a separate crate.
This commit is contained in:
Filipe Rodrigues 2020-09-20 02:34:39 +01:00
parent 152c8250ff
commit 2a39f8b438
21 changed files with 261 additions and 103 deletions

View File

@ -1,5 +1,7 @@
[workspace]
members = [
"dcb"
"dcb",
"dcb-bytes",
"dcb-bytes-derive"
]

View File

@ -0,0 +1,8 @@
[package]
name = "dcb-bytes-derive"
version = "0.1.0"
authors = ["Filipe Rodrigues <filipejacintorodrigues1@gmail.com>"]
edition = "2018"
[dependencies]

View File

@ -0,0 +1 @@
//! Derive macros for [`Bytes`](dcb_bytes::Bytes)

8
dcb-bytes/Cargo.toml Normal file
View File

@ -0,0 +1,8 @@
[package]
name = "dcb-bytes"
version = "0.1.0"
authors = ["Filipe Rodrigues <filipejacintorodrigues1@gmail.com>"]
edition = "2018"
[dependencies]

62
dcb-bytes/src/lib.rs Normal file
View File

@ -0,0 +1,62 @@
//! Bytes conversions for [`dcb`].
// Features
#![feature(unsafe_block_in_unsafe_fn, min_const_generics)]
// Lints
#![warn(clippy::restriction, clippy::pedantic, clippy::nursery)]
// Instead of `unwrap`, we must use `expect` and provide a reason
#![forbid(clippy::unwrap_used)]
// We must use `unsafe` in unsafe `fn`s and specify if the guarantee is
// made by the caller or by us.
#![forbid(unsafe_op_in_unsafe_fn)]
// We'll disable the ones we don't need
#![allow(clippy::blanket_clippy_restriction_lints)]
// Necessary items may be inlined using `LTO`, so we don't need to mark them as inline
#![allow(clippy::missing_inline_in_public_items)]
// We prefer tail returns where possible, as they help with code readability in most cases.
#![allow(clippy::implicit_return)]
// We're fine with shadowing, as long as the variable is used for the same purpose.
// Hence why `clippy::shadow_unrelated` isn't allowed.
#![allow(clippy::shadow_reuse, clippy::shadow_same)]
// We panic when we know it won't happen, or if it does happen, then a panic is the best option
#![allow(clippy::panic, clippy::expect_used, clippy::unreachable, clippy::todo)]
// We use `expect` even in functions that return a `Result` / `Option` if there is a logic error
#![allow(clippy::unwrap_in_result)]
// We find it more important to be able to copy paste literals such as `0xabcd1234` than
// being able to read them, which does not provide many benefits
#![allow(clippy::unreadable_literal, clippy::unseparated_literal_suffix)]
// We separate implementations per their functionality usually, such as constructors, getters, setters, and others.
#![allow(clippy::multiple_inherent_impl)]
// Many operations we need to repeat, and to keep symmetry
#![allow(clippy::identity_op)]
// We only introduce items before their first usage, which sometimes is half-way through the code.
// We make sure that we only use the item after introduced, however.
#![allow(clippy::items_after_statements)]
// Useful for when they either change a lot with new variants / data,
// or for symmetry purposes
#![allow(clippy::match_same_arms)]
// In this library we have very grain-level error types, each function
// will have it's own error type ideally, so any errors are explicit
// by the type, without needing a section for them
#![allow(clippy::missing_errors_doc)]
// 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, clippy::module_name_repetitions)]
// We use integer arithmetic and operations with the correct intent
#![allow(clippy::integer_arithmetic, clippy::integer_division)]
// We prefer using match ergonomic where possible
#![allow(clippy::pattern_type_mismatch)]
// Sometimes the blocks make it easier to invert their order
#![allow(clippy::if_not_else)]
// 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
// lint currently triggers for `&[T; N]`, which we pass around a lot.
#![allow(clippy::indexing_slicing)]
// Modules
pub mod bytes;
// Exports
pub use bytes::{ByteArray, Bytes};

View File

@ -6,6 +6,9 @@ edition = "2018"
[dependencies]
# Dcb
dcb-bytes = { version = "0.1", path = "../dcb-bytes" }
# Log
log = "0.4"

View File

@ -15,13 +15,11 @@
//#![allow(clippy::missing_docs_in_private_items)] // A lot of our private items are simple digimon types, so they don't need documentation
// Modules
pub mod bytes;
pub mod card;
pub mod deck;
pub mod validation;
// Exports
pub use bytes::Bytes;
pub use card::{Digimon, Digivolve, Item, Table as CardTable};
pub use deck::{Deck, Table as DeckTable};
pub use validation::{Validatable, Validation};

View File

@ -8,14 +8,15 @@ pub use error::{FromBytesError, ToBytesError};
// Imports
use crate::{
game::{
card::property::{ArrowColor, CrossMoveEffect, Effect, EffectCondition, Level, Move, Speciality},
Bytes,
game::card::property::{
ArrowColor, CrossMoveEffect, Effect, EffectCondition, Level, MaybeArrowColor, MaybeCrossMoveEffect, MaybeEffect, MaybeEffectCondition, Move,
Speciality,
},
util::{array_split, null_ascii_string::NullAsciiString, array_split_mut},
util::{array_split, array_split_mut, null_ascii_string::NullAsciiString},
AsciiStrArr,
};
use byteorder::{ByteOrder, LittleEndian};
use dcb_bytes::Bytes;
// TODO: Remove these
/// Name alias for [`Digimon`]
@ -148,19 +149,27 @@ impl Bytes for Digimon {
// Effects
effect_conditions: [
Option::<EffectCondition>::from_bytes(bytes.condition_first).map_err(FromBytesError::EffectConditionFirst)?,
Option::<EffectCondition>::from_bytes(bytes.condition_second).map_err(FromBytesError::EffectConditionSecond)?,
MaybeEffectCondition::from_bytes(bytes.condition_first)
.map_err(FromBytesError::EffectConditionFirst)?
.into(),
MaybeEffectCondition::from_bytes(bytes.condition_second)
.map_err(FromBytesError::EffectConditionSecond)?
.into(),
],
effects: [
Option::<Effect>::from_bytes(bytes.effect_first).map_err(FromBytesError::EffectFirst)?,
Option::<Effect>::from_bytes(bytes.effect_second).map_err(FromBytesError::EffectSecond)?,
Option::<Effect>::from_bytes(bytes.effect_third).map_err(FromBytesError::EffectThird)?,
MaybeEffect::from_bytes(bytes.effect_first).map_err(FromBytesError::EffectFirst)?.into(),
MaybeEffect::from_bytes(bytes.effect_second).map_err(FromBytesError::EffectSecond)?.into(),
MaybeEffect::from_bytes(bytes.effect_third).map_err(FromBytesError::EffectThird)?.into(),
],
cross_move_effect: Option::<CrossMoveEffect>::from_bytes(bytes.cross_move_effect).map_err(FromBytesError::CrossMoveEffect)?,
cross_move_effect: MaybeCrossMoveEffect::from_bytes(bytes.cross_move_effect)
.map_err(FromBytesError::CrossMoveEffect)?
.into(),
effect_arrow_color: Option::<ArrowColor>::from_bytes(bytes.effect_arrow_color).map_err(FromBytesError::ArrowColor)?,
effect_arrow_color: MaybeArrowColor::from_bytes(bytes.effect_arrow_color)
.map_err(FromBytesError::ArrowColor)?
.into(),
effect_description: [
bytes.effect_description_0.read_string().map_err(FromBytesError::EffectDescription1)?,
@ -231,16 +240,30 @@ impl Bytes for Digimon {
self.move_cross.to_bytes(bytes.move_cross).into_ok();
// Effects
self.effect_conditions[0].to_bytes(bytes.condition_first).into_ok();
self.effect_conditions[1].to_bytes(bytes.condition_second).into_ok();
<&MaybeEffectCondition>::from(&self.effect_conditions[0])
.to_bytes(bytes.condition_first)
.into_ok();
<&MaybeEffectCondition>::from(&self.effect_conditions[1])
.to_bytes(bytes.condition_second)
.into_ok();
self.effects[0].to_bytes(bytes.effect_first).map_err(ToBytesError::EffectFirst)?;
self.effects[1].to_bytes(bytes.effect_second).map_err(ToBytesError::EffectSecond)?;
self.effects[2].to_bytes(bytes.effect_third).map_err(ToBytesError::EffectThird)?;
<&MaybeEffect>::from(&self.effects[0])
.to_bytes(bytes.effect_first)
.map_err(ToBytesError::EffectFirst)?;
<&MaybeEffect>::from(&self.effects[1])
.to_bytes(bytes.effect_second)
.map_err(ToBytesError::EffectSecond)?;
<&MaybeEffect>::from(&self.effects[2])
.to_bytes(bytes.effect_third)
.map_err(ToBytesError::EffectThird)?;
Option::<CrossMoveEffect>::to_bytes(&self.cross_move_effect, bytes.cross_move_effect).into_ok();
<&MaybeCrossMoveEffect>::from(&self.cross_move_effect)
.to_bytes(bytes.cross_move_effect)
.into_ok();
Option::<ArrowColor>::to_bytes(&self.effect_arrow_color, bytes.effect_arrow_color).into_ok();
<&MaybeArrowColor>::from(&self.effect_arrow_color)
.to_bytes(bytes.effect_arrow_color)
.into_ok();
bytes.effect_description_0.write_string(&self.effect_description[0]);
bytes.effect_description_1.write_string(&self.effect_description[1]);

View File

@ -2,13 +2,13 @@
// Imports
use crate::{
game::Bytes,
util::{
array_split, array_split_mut,
null_ascii_string::{self, NullAsciiString},
},
AsciiStrArr,
};
use dcb_bytes::Bytes;
// TODO: Remove these
/// Name alias for [`Digimon`]

View File

@ -2,10 +2,7 @@
// Imports
use crate::{
game::{
card::property::{self, ArrowColor, Effect, EffectCondition},
Bytes,
},
game::card::property::{self, ArrowColor, Effect, EffectCondition, MaybeArrowColor, MaybeEffect, MaybeEffectCondition},
util::{
array_split, array_split_mut,
null_ascii_string::{self, NullAsciiString},
@ -13,6 +10,7 @@ use crate::{
AsciiStrArr,
};
use byteorder::{ByteOrder, LittleEndian};
use dcb_bytes::Bytes;
// TODO: Remove these
/// Name alias for [`Digimon`]
@ -147,17 +145,23 @@ impl Bytes for Item {
// Effects
effect_conditions: [
Option::<EffectCondition>::from_bytes(bytes.condition_first).map_err(FromBytesError::EffectConditionFirst)?,
Option::<EffectCondition>::from_bytes(bytes.condition_second).map_err(FromBytesError::EffectConditionSecond)?,
MaybeEffectCondition::from_bytes(bytes.condition_first)
.map_err(FromBytesError::EffectConditionFirst)?
.into(),
MaybeEffectCondition::from_bytes(bytes.condition_second)
.map_err(FromBytesError::EffectConditionSecond)?
.into(),
],
effects: [
Option::<Effect>::from_bytes(bytes.effect_first).map_err(FromBytesError::EffectFirst)?,
Option::<Effect>::from_bytes(bytes.effect_second).map_err(FromBytesError::EffectSecond)?,
Option::<Effect>::from_bytes(bytes.effect_third).map_err(FromBytesError::EffectThird)?,
MaybeEffect::from_bytes(bytes.effect_first).map_err(FromBytesError::EffectFirst)?.into(),
MaybeEffect::from_bytes(bytes.effect_second).map_err(FromBytesError::EffectSecond)?.into(),
MaybeEffect::from_bytes(bytes.effect_third).map_err(FromBytesError::EffectThird)?.into(),
],
effect_arrow_color: Option::<ArrowColor>::from_bytes(bytes.effect_arrow_color).map_err(FromBytesError::ArrowColor)?,
effect_arrow_color: MaybeArrowColor::from_bytes(bytes.effect_arrow_color)
.map_err(FromBytesError::ArrowColor)?
.into(),
effect_description: [
bytes.effect_description_0.read_string().map_err(FromBytesError::EffectDescription1)?,
@ -192,14 +196,26 @@ impl Bytes for Item {
bytes.name.write_string(&self.name);
// Effects
self.effect_conditions[0].to_bytes(bytes.condition_first).into_ok();
self.effect_conditions[1].to_bytes(bytes.condition_second).into_ok();
<&MaybeEffectCondition>::from(&self.effect_conditions[0])
.to_bytes(bytes.condition_first)
.into_ok();
<&MaybeEffectCondition>::from(&self.effect_conditions[1])
.to_bytes(bytes.condition_second)
.into_ok();
self.effects[0].to_bytes(bytes.effect_first).map_err(ToBytesError::EffectFirst)?;
self.effects[1].to_bytes(bytes.effect_second).map_err(ToBytesError::EffectSecond)?;
self.effects[2].to_bytes(bytes.effect_third).map_err(ToBytesError::EffectThird)?;
<&MaybeEffect>::from(&self.effects[0])
.to_bytes(bytes.effect_first)
.map_err(ToBytesError::EffectFirst)?;
<&MaybeEffect>::from(&self.effects[1])
.to_bytes(bytes.effect_second)
.map_err(ToBytesError::EffectSecond)?;
<&MaybeEffect>::from(&self.effects[2])
.to_bytes(bytes.effect_third)
.map_err(ToBytesError::EffectThird)?;
Option::<ArrowColor>::to_bytes(&self.effect_arrow_color, bytes.effect_arrow_color).into_ok();
<&MaybeArrowColor>::from(&self.effect_arrow_color)
.to_bytes(bytes.effect_arrow_color)
.into_ok();
bytes.effect_description_0.write_string(&self.effect_description[0]);
bytes.effect_description_1.write_string(&self.effect_description[1]);

View File

@ -58,11 +58,14 @@ generate_enum_property_mod!(
#[must_use]
pub const fn byte_size(self) -> usize
{
use crate::game::card::{Digimon, Item, Digivolve};
use dcb_bytes::Bytes;
match self
{
Self::Digimon => std::mem::size_of::< <crate::game::card::Digimon as crate::game::Bytes>::ByteArray >(),
Self::Item => std::mem::size_of::< <crate::game::card::Item as crate::game::Bytes>::ByteArray >(),
Self::Digivolve => std::mem::size_of::< <crate::game::card::Digivolve as crate::game::Bytes>::ByteArray >(),
Self::Digimon => std::mem::size_of::< <Digimon as Bytes>::ByteArray >(),
Self::Item => std::mem::size_of::< <Item as Bytes>::ByteArray >(),
Self::Digivolve => std::mem::size_of::< <Digivolve as Bytes>::ByteArray >(),
}
}
}
@ -211,9 +214,9 @@ generate_enum_property_mod!(
);
util::generate_enum_property_option!(
ArrowColor => 0,
CrossMoveEffect => 0,
DigimonProperty => 0,
pub struct MaybeArrowColor (ArrowColor ) => 0,
pub struct MaybeCrossMoveEffect (CrossMoveEffect ) => 0,
pub struct MaybeDigimonProperty (DigimonProperty ) => 0,
);
// Complex
@ -227,8 +230,8 @@ pub use attack_type::AttackType;
pub use card_type::CardType;
pub use cross_move_effect::CrossMoveEffect;
pub use digimon_property::DigimonProperty;
pub use effect::Effect;
pub use effect_condition::EffectCondition;
pub use effect::{Effect, MaybeEffect};
pub use effect_condition::{EffectCondition, MaybeEffectCondition};
pub use effect_condition_operation::EffectConditionOperation;
pub use effect_operation::EffectOperation;
pub use level::Level;

View File

@ -2,13 +2,11 @@
// Imports
use crate::{
game::{
card::property::{self, AttackType, DigimonProperty, EffectOperation, PlayerType, Slot},
Bytes,
},
game::card::property::{self, AttackType, DigimonProperty, EffectOperation, PlayerType, Slot},
util::{array_split, array_split_mut},
};
use byteorder::{ByteOrder, LittleEndian};
use dcb_bytes::Bytes;
/// A digimon's support effects
///
@ -460,7 +458,19 @@ impl Bytes for Effect {
}
}
impl Bytes for Option<Effect> {
/// A possible effect
#[derive(derive_more::From, derive_more::Into)]
pub struct MaybeEffect(Option<Effect>);
impl<'a> From<&'a Option<Effect>> for &'a MaybeEffect {
#[allow(clippy::as_conversions)] // We need `as` to make pointer casts
fn from(opt: &'a Option<Effect>) -> Self {
// SAFETY: We're `repr(transparent)`, so this cast is safe
unsafe { &*(opt as *const Option<Effect> as *const MaybeEffect) }
}
}
impl Bytes for MaybeEffect {
type ByteArray = [u8; 0x10];
type FromError = FromBytesError;
type ToError = ToBytesError;
@ -474,11 +484,11 @@ impl Bytes for Option<Effect> {
// If the exists byte is 0, return None
if *bytes.exists == 0 {
return Ok(None);
return Ok(Self(None));
}
// Else get the effect
Ok(Some(Effect::from_bytes(bytes.effect)?))
Ok(Self(Some(Effect::from_bytes(bytes.effect)?)))
}
fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError> {
@ -488,7 +498,7 @@ impl Bytes for Option<Effect> {
);
// Check if we exist
match self {
match &self.0 {
Some(effect) => {
*bytes.exists = 1;
effect.to_bytes(bytes.effect)?;

View File

@ -2,13 +2,11 @@
// Imports
use crate::{
game::{
card::property::{self, DigimonProperty, EffectConditionOperation},
Bytes,
},
game::card::property::{self, DigimonProperty, EffectConditionOperation, MaybeDigimonProperty},
util::{array_split, array_split_mut},
};
use byteorder::{ByteOrder, LittleEndian};
use dcb_bytes::Bytes;
/// A digimon's support effect condition
#[derive(PartialEq, Eq, Clone, Copy, Hash, Debug)]
@ -84,7 +82,9 @@ impl Bytes for EffectCondition {
misfire: (*bytes.misfire != 0),
property_cmp: DigimonProperty::from_bytes(bytes.property_cmp).map_err(FromBytesError::Condition)?,
arg_property: Option::<DigimonProperty>::from_bytes(bytes.arg_property).map_err(FromBytesError::PropertyArgument)?,
arg_property: MaybeDigimonProperty::from_bytes(bytes.arg_property)
.map_err(FromBytesError::PropertyArgument)?
.into(),
arg_num: LittleEndian::read_u16(bytes.arg_num),
@ -119,7 +119,7 @@ impl Bytes for EffectCondition {
self.property_cmp.to_bytes(bytes.property_cmp).into_ok();
// Arguments
self.arg_property.to_bytes(bytes.arg_property).into_ok();
<&MaybeDigimonProperty>::from(&self.arg_property).to_bytes(bytes.arg_property).into_ok();
LittleEndian::write_u16(bytes.arg_num, self.arg_num);
self.operation.to_bytes(bytes.operation).into_ok();
@ -135,25 +135,39 @@ impl Bytes for EffectCondition {
}
}
impl Bytes for Option<EffectCondition> {
/// A possible effect condition
#[repr(transparent)]
#[derive(derive_more::From, derive_more::Into)]
pub struct MaybeEffectCondition(Option<EffectCondition>);
impl<'a> From<&'a Option<EffectCondition>> for &'a MaybeEffectCondition {
#[allow(clippy::as_conversions)] // We need `as` to make pointer casts
fn from(opt: &'a Option<EffectCondition>) -> Self {
// SAFETY: We're `repr(transparent)`, so this cast is safe
unsafe { &*(opt as *const Option<EffectCondition> as *const MaybeEffectCondition) }
}
}
impl Bytes for MaybeEffectCondition {
type ByteArray = [u8; 0x20];
type FromError = FromBytesError;
type ToError = <EffectCondition as crate::game::Bytes>::ToError;
type ToError = <EffectCondition as Bytes>::ToError;
fn from_bytes(bytes: &Self::ByteArray) -> Result<Self, Self::FromError> {
// If we have no property comparison, return None
if bytes[0x2] == 0 {
return Ok(None);
return Ok(Self(None));
}
// Else build the type
Ok(Some(EffectCondition::from_bytes(bytes)?))
Ok(Self(Some(EffectCondition::from_bytes(bytes)?)))
}
#[allow(clippy::diverging_sub_expression)] // For if we ever change `EffectCondition::ToError`
fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError> {
// Check if we exist
match self {
match self.0 {
Some(cond) => cond.to_bytes(bytes)?,
None => bytes[0x2] = 0,
};

View File

@ -6,7 +6,7 @@ mod test;
// Imports
use crate::{
game::{Bytes, Validatable, Validation},
game::{Validatable, Validation},
util::{
array_split, array_split_mut,
null_ascii_string::{self, NullAsciiString},
@ -14,6 +14,7 @@ use crate::{
AsciiStrArr,
};
use byteorder::{ByteOrder, LittleEndian};
use dcb_bytes::Bytes;
// TODO: Remove these
/// Name alias for [`Digimon`]

View File

@ -8,18 +8,16 @@ pub use error::{DeserializeError, SerializeError};
// Imports
use crate::{
game::{
card::{
self,
property::{self, CardType},
Digimon, Digivolve, Item,
},
Bytes,
game::card::{
self,
property::{self, CardType},
Digimon, Digivolve, Item,
},
io::{address::Data, GameFile},
util::{array_split, array_split_mut},
};
use byteorder::{ByteOrder, LittleEndian};
use dcb_bytes::Bytes;
use std::{
convert::TryInto,
io::{Read, Seek, Write},

View File

@ -57,9 +57,9 @@ generate_enum_property_mod! {
}
generate_enum_property_option!(
City => 0,
ArmorEvo => 0,
Music => 0,
pub struct MaybeCity (City ) => 0,
pub struct MaybeArmorEvo(ArmorEvo) => 0,
pub struct MaybeMusic (Music ) => 0,
);
// Modules

View File

@ -2,10 +2,7 @@
// Imports
use crate::{
game::{
deck::{armor_evo, city, music, ArmorEvo, City, Music},
Bytes,
},
game::deck::{armor_evo, city, music, ArmorEvo, City, MaybeArmorEvo, MaybeCity, MaybeMusic, Music},
util::{
array_split, array_split_mut,
null_ascii_string::{self, NullAsciiString},
@ -13,6 +10,7 @@ use crate::{
AsciiStrArr,
};
use byteorder::{ByteOrder, LittleEndian};
use dcb_bytes::Bytes;
/// Card id type
pub type CardId = u16;
@ -119,10 +117,10 @@ impl Bytes for Deck {
name: bytes.name.read_string().map_err(FromBytesError::Name)?,
owner: bytes.owner.read_string().map_err(FromBytesError::Owner)?,
cards,
city: Option::<City>::from_bytes(bytes.city).map_err(FromBytesError::City)?,
armor_evo: Option::<ArmorEvo>::from_bytes(bytes.armor_evo).map_err(FromBytesError::ArmorEvo)?,
battle_music: Option::<Music>::from_bytes(bytes.battle_music).map_err(FromBytesError::BattleMusic)?,
polygon_music: Option::<Music>::from_bytes(bytes.polygon_music).map_err(FromBytesError::PolygonMusic)?,
city: MaybeCity::from_bytes(bytes.city).map_err(FromBytesError::City)?.into(),
armor_evo: MaybeArmorEvo::from_bytes(bytes.armor_evo).map_err(FromBytesError::ArmorEvo)?.into(),
battle_music: MaybeMusic::from_bytes(bytes.battle_music).map_err(FromBytesError::BattleMusic)?.into(),
polygon_music: MaybeMusic::from_bytes(bytes.polygon_music).map_err(FromBytesError::PolygonMusic)?.into(),
experience: *bytes.experience,
unknown_64: *bytes.unknown_64,
unknown_6a: *bytes.unknown_6a,
@ -160,14 +158,14 @@ impl Bytes for Deck {
*bytes.experience = self.experience;
// City
self.city.to_bytes(bytes.city).into_ok();
<&MaybeCity>::from(&self.city).to_bytes(bytes.city).into_ok();
// Armor evo
self.armor_evo.to_bytes(bytes.armor_evo).into_ok();
<&MaybeArmorEvo>::from(&self.armor_evo).to_bytes(bytes.armor_evo).into_ok();
// Music
self.battle_music.to_bytes(bytes.battle_music).into_ok();
self.polygon_music.to_bytes(bytes.polygon_music).into_ok();
<&MaybeMusic>::from(&self.battle_music).to_bytes(bytes.battle_music).into_ok();
<&MaybeMusic>::from(&self.polygon_music).to_bytes(bytes.polygon_music).into_ok();
// Unknown
*bytes.unknown_64 = self.unknown_64;

View File

@ -8,7 +8,7 @@ pub use error::{DeserializeError, SerializeError};
// Imports
use crate::{
game::{Bytes, Deck},
game::{Deck},
io::{address::Data, GameFile},
util::array_split_mut,
};
@ -17,6 +17,7 @@ use std::{
convert::TryInto,
io::{Read, Seek, Write},
};
use dcb_bytes::Bytes;
/// The decks table, where all decks are stored
#[derive(PartialEq, Eq, Clone, Debug)]

View File

@ -107,5 +107,5 @@ mod util;
// Exports
pub use ascii_str_arr::AsciiStrArr;
pub use game::{Bytes, CardTable, Deck, DeckTable, Digimon, Digivolve, Item, Validatable, Validation};
pub use game::{CardTable, Deck, DeckTable, Digimon, Digivolve, Item, Validatable, Validation};
pub use io::GameFile;

View File

@ -74,7 +74,7 @@ macro_rules! generate_enum_property_mod
)+
}
/// Error type for [`$crate::game::Bytes::from_bytes`]
/// Error type for [`::dcb_bytes::Bytes::from_bytes`]
#[derive(PartialEq, Eq, Clone, Copy, ::std::fmt::Debug, ::thiserror::Error)]
pub enum FromBytesError {
@ -85,7 +85,7 @@ macro_rules! generate_enum_property_mod
}
}
impl $crate::game::Bytes for $enum_name
impl ::dcb_bytes::Bytes for $enum_name
{
type ByteArray = u8;
@ -129,33 +129,45 @@ macro_rules! generate_enum_property_mod
}
}
/// Implements [`Bytes`](crate::game::Bytes) for `Option<E>` where `E`
/// Implements [`Bytes`](dcb_bytes::Bytes) for `Option<E>` where `E`
/// is the first argument of this macro and an enum.
///
/// This is done by supplying a sentinel value which is read/written as `None`.
pub macro generate_enum_property_option {
(
$( $enum_name:ty => $sentinel_value:literal ),* $(,)?
$( $struct_vis:vis struct $struct_name:ident ( $enum_vis:vis $enum_name:ty ) => $sentinel_value:literal ),* $(,)?
) => {
$(
#[allow(clippy::diverging_sub_expression)] // Errors might be `!`
impl $crate::game::Bytes for Option<$enum_name> {
type ByteArray = <$enum_name as $crate::game::Bytes>::ByteArray;
#[repr(transparent)]
#[derive(derive_more::From, derive_more::Into)]
$struct_vis struct $struct_name( $enum_vis Option<$enum_name> );
type FromError = <$enum_name as $crate::game::Bytes>::FromError;
impl<'a> From<&'a Option<$enum_name>> for &'a $struct_name {
#[allow(clippy::as_conversions)] // We need `as` to make pointer casts
fn from(opt: &'a Option<$enum_name>) -> Self {
// SAFETY: We're `repr(transparent)`, so this cast is safe
unsafe { &*(opt as *const Option<$enum_name> as *const $struct_name) }
}
}
#[allow(clippy::diverging_sub_expression)] // Errors might be `!`
impl ::dcb_bytes::Bytes for $struct_name {
type ByteArray = <$enum_name as ::dcb_bytes::Bytes>::ByteArray;
type FromError = <$enum_name as ::dcb_bytes::Bytes>::FromError;
fn from_bytes(bytes: &Self::ByteArray) -> Result<Self, Self::FromError>
{
match bytes {
$sentinel_value => Ok( None ),
_ => Ok( Some( $crate::game::Bytes::from_bytes(bytes)? ) ),
$sentinel_value => Ok( Self(None) ),
_ => Ok( Self(Some( ::dcb_bytes::Bytes::from_bytes(bytes)? )) ),
}
}
type ToError = <$enum_name as $crate::game::Bytes>::ToError;
type ToError = <$enum_name as ::dcb_bytes::Bytes>::ToError;
fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError>
{
match self {
Some(value) => $crate::game::Bytes::to_bytes(value, bytes)?,
match &self.0 {
Some(value) => ::dcb_bytes::Bytes::to_bytes(value, bytes)?,
None => *bytes = $sentinel_value,
}