mirror of
https://github.com/Zenithsiz/dcb.git
synced 2026-02-09 03:40:23 +00:00
Refactored game::digivolve.
This commit is contained in:
3
.gitignore
vendored
3
.gitignore
vendored
@@ -1,3 +1,4 @@
|
||||
/target
|
||||
/.vscode
|
||||
/resources
|
||||
Cargo.lock
|
||||
.vscode
|
||||
|
||||
@@ -94,21 +94,21 @@ pub struct Digimon
|
||||
#[serde(default)]
|
||||
pub cross_move_effect: Option<CrossMoveEffect>,
|
||||
|
||||
/// The digimon's effect description.
|
||||
/// The effect's description.
|
||||
///
|
||||
/// The description is split along 4 lines, each
|
||||
/// being an ascii string with 20 characters at most.
|
||||
pub effect_description: [ascii::AsciiString; 4],
|
||||
|
||||
/// The effect arrow color
|
||||
/// The effect's arrow color
|
||||
#[serde(default)]
|
||||
pub effect_arrow_color: Option<ArrowColor>,
|
||||
|
||||
/// The effect conditions
|
||||
/// The effect's conditions
|
||||
#[serde(default)]
|
||||
pub effect_conditions: [Option<EffectCondition>; 2],
|
||||
|
||||
/// The effects themselves
|
||||
/// The effects
|
||||
#[serde(default)]
|
||||
pub effects: [Option<Effect>; 3],
|
||||
|
||||
@@ -405,22 +405,18 @@ impl Bytes for Digimon
|
||||
self.move_triangle.to_bytes( bytes.move_triangle ).map_err(ToBytesError::MoveTriangle)?;
|
||||
self.move_cross .to_bytes( bytes.move_cross ).map_err(ToBytesError::MoveCross )?;
|
||||
|
||||
// Effect conditions
|
||||
// Effects
|
||||
self.effect_conditions[0].to_bytes( bytes.condition_first ).into_ok();
|
||||
self.effect_conditions[1].to_bytes( bytes.condition_second ).into_ok();
|
||||
|
||||
// Effects
|
||||
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 )?;
|
||||
|
||||
// Cross move
|
||||
Option::<CrossMoveEffect>::to_bytes(&self.cross_move_effect, bytes.cross_move_effect).into_ok();
|
||||
|
||||
// Support 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)
|
||||
.map_err(ToBytesError::EffectDescriptionFirst)?;
|
||||
util::write_null_ascii_string(self.effect_description[1].as_ref(), bytes.effect_description_1)
|
||||
|
||||
@@ -1,228 +1,183 @@
|
||||
//! Digivolve
|
||||
//! A digivolve card
|
||||
//!
|
||||
//! This module contains the [`Digivolve`] struct, which describes a digivolve card.
|
||||
//!
|
||||
//! # Layout
|
||||
//! The digivolve card has a size of `0x6c` bytes, and it's layout is the following:
|
||||
//!
|
||||
//! | Offset | Size | Type | Name | Location | Details |
|
||||
//! |--------|------|---------------------|---------------------------|------------------------|-------------------------------------------------------------------------------------|
|
||||
//! | 0x0 | 0x15 | `[char; 0x15]` | Name | `name` | Null-terminated |
|
||||
//! | 0x15 | 0x4 | `u32` | Unknown | `unknown_15` | |
|
||||
//! | 0x19 | 0x20 | [`EffectCondition`] | First condition | `effect_conditions[0]` | |
|
||||
//! | 0x39 | 0x20 | [`EffectCondition`] | Second condition | `effect_conditions[1]` | |
|
||||
//! | 0x59 | 0x10 | [`Effect`] | First effect | `effects[0]` | |
|
||||
//! | 0x69 | 0x10 | [`Effect`] | Second effect | `effects[1]` | |
|
||||
//! | 0x79 | 0x10 | [`Effect`] | Third effect | `effects[2]` | |
|
||||
//! | 0x89 | 0x1 | [`ArrowColor`] | Effect arrow color | `effect_arrow_color` | |
|
||||
//! | 0x8a | 0x54 | `[[char; 0x15]; 4]` | Effect description lines | `effect_description` | Each line is` 0x15` bytes, split over 4 lines, each null terminated |
|
||||
|
||||
// Crate
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Game
|
||||
use crate::game::util;
|
||||
use crate::game::Bytes;
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
use crate::game::{
|
||||
util,
|
||||
Bytes,
|
||||
};
|
||||
|
||||
// byteorder
|
||||
//use byteorder::ByteOrder;
|
||||
//use byteorder::LittleEndian;
|
||||
/// A digivolve card
|
||||
///
|
||||
/// Contains all information about each digivolve card stored in the [`Card Table`](crate::game::card::table::Table)
|
||||
#[derive(PartialEq, Eq, Clone, Hash, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct Digivolve
|
||||
{
|
||||
/// The item's name
|
||||
///
|
||||
/// An ascii string with 20 characters at most
|
||||
pub name: ascii::AsciiString,
|
||||
|
||||
/// The effect's description.
|
||||
///
|
||||
/// The description is split along 4 lines, each
|
||||
/// being an ascii string with 20 characters at most.
|
||||
pub effect_description: [ascii::AsciiString; 4],
|
||||
|
||||
pub value0: u8,
|
||||
pub value1: u8,
|
||||
pub value2: u8,
|
||||
}
|
||||
|
||||
// Macros
|
||||
use serde::Serialize;
|
||||
use serde::Deserialize;
|
||||
/// Error type for [`Bytes::from_bytes`]
|
||||
#[derive(Debug)]
|
||||
#[derive(derive_more::Display, err_impl::Error)]
|
||||
pub enum FromBytesError
|
||||
{
|
||||
/// Unable to read the digimon name
|
||||
#[display(fmt = "Unable to read the digimon name")]
|
||||
Name( #[error(source)] util::ReadNullAsciiStringError ),
|
||||
|
||||
/// Unable to read the first support effect description
|
||||
#[display(fmt = "Unable to read the first line of the effect description")]
|
||||
EffectDescriptionFirst( #[error(source)] util::ReadNullAsciiStringError ),
|
||||
|
||||
/// Unable to read the second support effect description
|
||||
#[display(fmt = "Unable to read the second line of the effect description")]
|
||||
EffectDescriptionSecond( #[error(source)] util::ReadNullAsciiStringError ),
|
||||
|
||||
/// Unable to read the third support effect description
|
||||
#[display(fmt = "Unable to read the third line of the effect description")]
|
||||
EffectDescriptionThird( #[error(source)] util::ReadNullAsciiStringError ),
|
||||
|
||||
/// Unable to read the fourth support effect description
|
||||
#[display(fmt = "Unable to read the fourth line of the effect description")]
|
||||
EffectDescriptionFourth( #[error(source)] util::ReadNullAsciiStringError ),
|
||||
}
|
||||
|
||||
// Types
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// A digivolve card
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Digivolve
|
||||
{
|
||||
/// The basic info of the digivolve
|
||||
pub basic: Basic,
|
||||
|
||||
/// The effects
|
||||
pub effects: Effects,
|
||||
}
|
||||
/// 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 ),
|
||||
|
||||
/// The basic properties of a digivolve
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Basic
|
||||
{
|
||||
pub name: String,
|
||||
|
||||
//unknown: u16,
|
||||
}
|
||||
/// 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 ),
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct Effects
|
||||
{
|
||||
pub description: [String; 4],
|
||||
|
||||
pub value0: u8,
|
||||
pub value1: u8,
|
||||
pub value2: u8,
|
||||
|
||||
//arrow_color: Option<ArrowColor>,
|
||||
|
||||
//conditions: SupportEffectConditions,
|
||||
//effects : SupportEffects,
|
||||
}
|
||||
/// 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 ),
|
||||
|
||||
/*
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct SupportEffects
|
||||
{
|
||||
first : Option<SupportEffect>,
|
||||
second: Option<SupportEffect>,
|
||||
third : Option<SupportEffect>,
|
||||
}
|
||||
/// 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 ),
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
struct SupportEffectConditions
|
||||
{
|
||||
first : Option<SupportEffectCondition>,
|
||||
second: Option<SupportEffectCondition>,
|
||||
}
|
||||
*/
|
||||
|
||||
/// The error type thrown by `FromBytes`
|
||||
#[derive(Debug, derive_more::Display)]
|
||||
pub enum FromBytesError
|
||||
{
|
||||
/// Unable to convert name to a string
|
||||
#[display(fmt = "Unable to convert name to a string")]
|
||||
NameToString( util::ReadNullTerminatedStringError ),
|
||||
|
||||
/// Unable to read the effect arrow color
|
||||
#[display(fmt = "Unable to read the effect arrow color")]
|
||||
EffectArrowColor( crate::game::card::property::arrow_color::FromBytesError ),
|
||||
|
||||
/// Unable to convert one of the support effect descriptions to a string
|
||||
#[display(fmt = "Unable to convert the {} support effect description to a string", rank)]
|
||||
SupportEffectDescriptionToString {
|
||||
rank: &'static str,
|
||||
err: util::ReadNullTerminatedStringError,
|
||||
},
|
||||
|
||||
/// Unable to read a support effect condition
|
||||
#[display(fmt = "Unable to read the {0} support effect condition [digivolve:0x{1:x}]", rank, digivolve_pos)]
|
||||
SupportEffectCondition {
|
||||
rank: &'static str,
|
||||
digivolve_pos: u64,
|
||||
err: crate::game::card::property::effect_condition::FromBytesError,
|
||||
},
|
||||
|
||||
/// Unable to read a support effect
|
||||
#[display(fmt = "Unable to read the {} support effect", rank)]
|
||||
SupportEffect {
|
||||
rank: &'static str,
|
||||
err: crate::game::card::property::effect::FromBytesError,
|
||||
},
|
||||
}
|
||||
|
||||
impl std::error::Error for FromBytesError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::NameToString(err) |
|
||||
Self::SupportEffectDescriptionToString{err, ..} => Some(err),
|
||||
|
||||
Self::EffectArrowColor(err) => Some(err),
|
||||
|
||||
Self::SupportEffectCondition{err, ..} => Some(err),
|
||||
Self::SupportEffect{err, ..} => Some(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// The error type thrown by `ToBytes`
|
||||
#[derive(Debug, derive_more::Display)]
|
||||
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 20)", _0)]
|
||||
NameTooLong( String ),
|
||||
|
||||
/// The name was too big to be written to file
|
||||
#[display(fmt = "The {0} support effect description \"{1}\" is too long to be written to file (max is 21)", rank, string)]
|
||||
SupportEffectDescriptionTooLong {
|
||||
rank: &'static str,
|
||||
string: String,
|
||||
},
|
||||
}
|
||||
|
||||
impl std::error::Error for ToBytesError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::NameTooLong(..) |
|
||||
Self::SupportEffectDescriptionTooLong{ .. } => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// 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 ),
|
||||
}
|
||||
|
||||
// Impl
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Bytes
|
||||
impl Bytes for Digivolve
|
||||
impl Bytes for Digivolve
|
||||
{
|
||||
type ByteArray = [u8; 0x6c];
|
||||
|
||||
type FromError = FromBytesError;
|
||||
fn from_bytes(bytes: &Self::ByteArray) -> Result<Self, Self::FromError>
|
||||
{
|
||||
type ByteArray = [u8; 0x6c];
|
||||
// Split bytes
|
||||
let bytes = util::array_split!(bytes,
|
||||
name : [0x15],
|
||||
value0 : 1,
|
||||
value1 : 1,
|
||||
value2 : 1,
|
||||
effect_description_0: [0x15],
|
||||
effect_description_1: [0x15],
|
||||
effect_description_2: [0x15],
|
||||
effect_description_3: [0x15],
|
||||
);
|
||||
|
||||
type FromError = FromBytesError;
|
||||
fn from_bytes(bytes: &Self::ByteArray) -> Result<Self, Self::FromError>
|
||||
{
|
||||
Ok( Self {
|
||||
basic: Basic {
|
||||
name: util::read_null_terminated_string( &bytes[0x0..0x15] ).map_err(FromBytesError::NameToString)?.to_string(),
|
||||
},
|
||||
|
||||
effects: Effects {
|
||||
description: [
|
||||
util::read_null_terminated_string( &bytes[0x18..0x2d] ).map_err(|err| FromBytesError::SupportEffectDescriptionToString{ rank: "1st", err })?.to_string(),
|
||||
util::read_null_terminated_string( &bytes[0x2d..0x42] ).map_err(|err| FromBytesError::SupportEffectDescriptionToString{ rank: "2nd", err })?.to_string(),
|
||||
util::read_null_terminated_string( &bytes[0x42..0x57] ).map_err(|err| FromBytesError::SupportEffectDescriptionToString{ rank: "3rd", err })?.to_string(),
|
||||
util::read_null_terminated_string( &bytes[0x57..0x6c] ).map_err(|err| FromBytesError::SupportEffectDescriptionToString{ rank: "4th", err })?.to_string(),
|
||||
],
|
||||
|
||||
value0: bytes[0x15],
|
||||
value1: bytes[0x16],
|
||||
value2: bytes[0x17],
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
type ToError = ToBytesError;
|
||||
fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError>
|
||||
{
|
||||
// Basic
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Write the name
|
||||
bytes[0x0..0x15].copy_from_slice( &{
|
||||
// Check if our name is too big
|
||||
if self.basic.name.len() >= 0x15 { return Err( ToBytesError::NameTooLong( self.basic.name.clone() ) ); }
|
||||
|
||||
// Else make the buffer and copy everything over
|
||||
let mut buf = [0u8; 0x15];
|
||||
buf[ 0..self.basic.name.len() ].copy_from_slice( self.basic.name.as_bytes() );
|
||||
buf
|
||||
});
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
Ok( Self {
|
||||
name: util::read_null_ascii_string(bytes.name)
|
||||
.map_err(FromBytesError::Name)?
|
||||
.chars().collect(),
|
||||
|
||||
// Effects
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Write the support effects
|
||||
for (index, line) in self.effects.description.iter().enumerate()
|
||||
{
|
||||
bytes[0x18 + (0x15 * index) .. 0x2d + (0x15 * index)].copy_from_slice( &{
|
||||
// If the line is too big, return Err
|
||||
if line.len() >= 0x15 {
|
||||
return Err( ToBytesError::SupportEffectDescriptionTooLong {
|
||||
rank: match index {
|
||||
0 => "1st", 1 => "2nd",
|
||||
2 => "3rd", 3 => "4th",
|
||||
_ => unreachable!(),
|
||||
},
|
||||
|
||||
string: line.clone()
|
||||
});
|
||||
}
|
||||
|
||||
let mut buf = [0u8; 0x15];
|
||||
buf[ 0..line.len() ].copy_from_slice( line.as_bytes() );
|
||||
buf
|
||||
});
|
||||
}
|
||||
|
||||
bytes[0x15] = self.effects.value0;
|
||||
bytes[0x16] = self.effects.value1;
|
||||
bytes[0x17] = self.effects.value2;
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
// Effect
|
||||
value0: *bytes.value0,
|
||||
value1: *bytes.value1,
|
||||
value2: *bytes.value2,
|
||||
|
||||
// Return the bytes
|
||||
Ok(())
|
||||
}
|
||||
effect_description: [
|
||||
util::read_null_ascii_string( bytes.effect_description_0 )
|
||||
.map_err(FromBytesError::EffectDescriptionFirst)?
|
||||
.chars().collect(),
|
||||
util::read_null_ascii_string( bytes.effect_description_1 )
|
||||
.map_err(FromBytesError::EffectDescriptionSecond)?
|
||||
.chars().collect(),
|
||||
util::read_null_ascii_string( bytes.effect_description_2 )
|
||||
.map_err(FromBytesError::EffectDescriptionThird)?
|
||||
.chars().collect(),
|
||||
util::read_null_ascii_string( bytes.effect_description_3 )
|
||||
.map_err(FromBytesError::EffectDescriptionFourth)?
|
||||
.chars().collect(),
|
||||
],
|
||||
})
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
type ToError = ToBytesError;
|
||||
fn to_bytes(&self, bytes: &mut Self::ByteArray) -> Result<(), Self::ToError>
|
||||
{
|
||||
// Split bytes
|
||||
let bytes = util::array_split_mut!(bytes,
|
||||
name : [0x15],
|
||||
value0 : 1,
|
||||
value1 : 1,
|
||||
value2 : 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)?;
|
||||
|
||||
// Effects
|
||||
*bytes.value0 = self.value0;
|
||||
*bytes.value1 = self.value1;
|
||||
*bytes.value2 = self.value2;
|
||||
|
||||
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(())
|
||||
}
|
||||
}
|
||||
|
||||
@@ -32,31 +32,33 @@ use crate::game::{
|
||||
}
|
||||
};
|
||||
|
||||
/// A item card
|
||||
/// An item card
|
||||
///
|
||||
/// Contains all information about each item card stored in the [`Card Table`](crate::game::card::table::Table)
|
||||
#[derive(PartialEq, Eq, Clone, Hash, Debug)]
|
||||
#[derive(serde::Serialize, serde::Deserialize)]
|
||||
pub struct Item
|
||||
{
|
||||
/// The digimon's name
|
||||
/// The item's name
|
||||
///
|
||||
/// An ascii string with 20 characters at most
|
||||
pub name: ascii::AsciiString,
|
||||
|
||||
/// The digimon's effect description.
|
||||
/// The effect's description.
|
||||
///
|
||||
/// The description is split along 4 lines, each
|
||||
/// being an ascii string with 20 characters at most.
|
||||
pub effect_description: [ascii::AsciiString; 4],
|
||||
|
||||
/// The effect arrow color
|
||||
/// The effect's arrow color
|
||||
#[serde(default)]
|
||||
pub effect_arrow_color: Option<ArrowColor>,
|
||||
|
||||
/// The effect conditions
|
||||
/// The effect's conditions
|
||||
#[serde(default)]
|
||||
pub effect_conditions: [Option<EffectCondition>; 2],
|
||||
|
||||
/// The effects themselves
|
||||
/// The effects
|
||||
#[serde(default)]
|
||||
pub effects: [Option<Effect>; 3],
|
||||
|
||||
@@ -248,19 +250,16 @@ impl Bytes for Item
|
||||
util::write_null_ascii_string(self.name.as_ref(), bytes.name)
|
||||
.map_err(ToBytesError::Name)?;
|
||||
|
||||
// Effect conditions
|
||||
// Effects
|
||||
self.effect_conditions[0].to_bytes( bytes.condition_first ).into_ok();
|
||||
self.effect_conditions[1].to_bytes( bytes.condition_second ).into_ok();
|
||||
|
||||
// Effects
|
||||
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 )?;
|
||||
|
||||
// Support 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)
|
||||
.map_err(ToBytesError::EffectDescriptionFirst)?;
|
||||
util::write_null_ascii_string(self.effect_description[1].as_ref(), bytes.effect_description_1)
|
||||
|
||||
@@ -103,58 +103,6 @@ pub macro array_split_mut {
|
||||
}}
|
||||
}
|
||||
|
||||
// Types
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
/// Error type for `read_null_terminated_string`
|
||||
#[derive(Debug, derive_more::Display)]
|
||||
pub enum ReadNullTerminatedStringError
|
||||
{
|
||||
/// No null was found on a string
|
||||
#[display(fmt = "No null was found on a null terminated string")]
|
||||
NoNull,
|
||||
|
||||
/// A string could not be converted to utf8
|
||||
#[display(fmt = "Could not convert the string to utf8")]
|
||||
Utf8( std::str::Utf8Error ),
|
||||
}
|
||||
|
||||
impl std::error::Error for ReadNullTerminatedStringError {
|
||||
fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
|
||||
match self {
|
||||
Self::NoNull => None,
|
||||
Self::Utf8(err) => Some(err),
|
||||
}
|
||||
}
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
// Impl
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
// Functions
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
/// Reads a string from a buffer, stopping at the first null character found
|
||||
///
|
||||
/// # Errors
|
||||
/// - `NoNull`: If no null character was found until the end of the buffer.
|
||||
/// - `Utf8`: If the buffer was not valid utf8.
|
||||
pub fn read_null_terminated_string(mut buf: &[u8]) -> Result<&str, ReadNullTerminatedStringError>
|
||||
{
|
||||
// Search for the first occurence of null and reduce the buffer to before it.
|
||||
// If not found, then the string was not null terminated, so return Err
|
||||
if let Some(first_null) = buf.iter().position(|&b| b == 0) { buf = &buf[0..first_null]; }
|
||||
else { return Err( ReadNullTerminatedStringError::NoNull ); }
|
||||
|
||||
// Else try to conver the buffer into a utf8 str.
|
||||
Ok( std::str::from_utf8( buf ).map_err(ReadNullTerminatedStringError::Utf8)? )
|
||||
}
|
||||
//--------------------------------------------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
/// Error type for [`read_null_ascii_string`]
|
||||
#[derive(Debug)]
|
||||
|
||||
Reference in New Issue
Block a user