Refactored array_split(_mut) macro.

Now using `AsciiString` instead of `arrayvec::ArrayVec<[ascii::AsciiChar; _]>`.
This commit is contained in:
Filipe Rodrigues 2020-04-26 07:10:45 +01:00
parent f2c0218096
commit 8b4b11113a
8 changed files with 312 additions and 213 deletions

View File

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

View File

@ -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<Self, Self::FromError>;
/// 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<Self, Self::FromError>;
/// Writes this structure to `bytes`
fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError>;
}

View File

@ -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<SupportEffect>; 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<Self, Self::FromError>
{
// 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(())

View File

@ -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(())

View File

@ -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!(),

View File

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

View File

@ -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() });
}

View File

@ -29,6 +29,7 @@
unsized_locals,
bool_to_option,
decl_macro,
stmt_expr_attributes,
)]
// Lints