From 0a3a455b316eca21062d738a8667c827f91d8b56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Maxime=20=E2=80=9Cpep=E2=80=9D=20Buquet?= Date: Mon, 15 Nov 2021 13:16:50 +0100 Subject: [PATCH] pkstrings: Move conversion cost to String away from from creation time MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Maxime “pep” Buquet --- pkstrings/src/lib.rs | 2 +- pkstrings/src/pkstring.rs | 84 ++++++++++++++++++++++----------------- pkstrings/src/tests.rs | 13 +++--- 3 files changed, 56 insertions(+), 43 deletions(-) diff --git a/pkstrings/src/lib.rs b/pkstrings/src/lib.rs index 8d69eb8..f6a5574 100644 --- a/pkstrings/src/lib.rs +++ b/pkstrings/src/lib.rs @@ -18,4 +18,4 @@ pub mod pkstring; #[cfg(test)] mod tests; -pub use pkstring::PKString; +pub use pkstring::{Error, PKString}; diff --git a/pkstrings/src/pkstring.rs b/pkstrings/src/pkstring.rs index f466e4f..ec9432f 100644 --- a/pkstrings/src/pkstring.rs +++ b/pkstrings/src/pkstring.rs @@ -17,6 +17,18 @@ use std::convert::TryFrom; use std::fmt; use std::ops::Deref; +const fn in_range(ord: u8) -> bool { + match ord { + 0x00 | + 0x49..=0x4c | 0x4e..=0x5f | // Control characters + 0x60..=0x78 | // Holdover from the japanese game + 0x79..=0x7f | // Text box borders + 0x80..=0xbf | + 0xe0..=0xff => true, + _ => false, + } +} + const fn strtohex(chr: &char) -> Option { Some(match chr { cap @ 'A'..='Z' => 0x80 - ('A' as u8) + (*cap as u8), @@ -55,7 +67,7 @@ const fn strtohex(chr: &char) -> Option { }) } -const fn hextostr(hex: u8) -> Option { +const fn hextochr(hex: u8) -> Option { Some(match hex { cap @ 0x80..=0x99 => (('A' as u8) + (cap - 0x80)) as char, 0x9a => '(', @@ -102,10 +114,10 @@ impl fmt::Display for Error { } #[derive(Debug, Clone, Eq, PartialEq)] -pub struct PKString(String); +pub struct PKString(Vec); impl Deref for PKString { - type Target = String; + type Target = Vec; fn deref(&self) -> &Self::Target { &self.0 @@ -114,7 +126,7 @@ impl Deref for PKString { impl fmt::Display for PKString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_fmt(format_args!("{}", &self.0)) + f.write_fmt(format_args!("{:?}", &self.0)) } } @@ -122,14 +134,11 @@ impl TryFrom for PKString { type Error = Error; fn try_from(ord: u8) -> Result { - let mut buf = String::with_capacity(1); - - match hextostr(ord) { - Some(chr) => buf.push(chr.clone()), - None => return Err(Error::InvalidByte(ord)), + if in_range(ord) { + Ok(PKString(vec![ord])) + } else { + Err(Error::InvalidByte(ord)) } - - Ok(PKString(buf)) } } @@ -137,12 +146,13 @@ impl TryFrom<&[u8]> for PKString { type Error = Error; fn try_from(data: &[u8]) -> Result { - let mut buf = String::with_capacity(data.len()); + let mut buf = Vec::with_capacity(data.len()); for ord in data { - match hextostr(*ord) { - Some(chr) => buf.push(chr.clone()), - None => return Err(Error::InvalidByte(*ord)), + if in_range(*ord) { + buf.push(*ord); + } else { + return Err(Error::InvalidByte(*ord)) } } @@ -162,7 +172,16 @@ impl TryFrom<&str> for PKString { type Error = Error; fn try_from(data: &str) -> Result { - PKString::try_from(String::from(data)) + let mut buf = Vec::with_capacity(data.len()); + + for chr in data.chars() { + match strtohex(&chr) { + Some(ord) => buf.push(ord), + None => return Err(Error::InvalidCharacter(chr)), + } + } + + Ok(PKString(buf)) } } @@ -170,36 +189,29 @@ impl TryFrom for PKString { type Error = Error; fn try_from(data: String) -> Result { - for chr in data.chars() { - if strtohex(&chr).is_none() { - return Err(Error::InvalidCharacter(chr)); - } - } - - Ok(PKString(data)) + PKString::try_from(data.as_str()) } } impl From for Vec { fn from(pkstr: PKString) -> Vec { - let mut vec = Vec::with_capacity(pkstr.len()); - - for chr in pkstr.0.chars() { - if let Some(ord) = strtohex(&chr) { - vec.push(ord); - } else { - // TODO: Change this. - panic!(); - } - } - - vec + pkstr.0 } } impl From for String { fn from(pkstr: PKString) -> String { - pkstr.0 + let placeholder = '_'; + let mut buf = String::new(); + + for ord in pkstr.0 { + match hextochr(ord) { + Some(chr) => buf.push(chr), + None => buf.push(placeholder.clone()), + } + } + + buf } } diff --git a/pkstrings/src/tests.rs b/pkstrings/src/tests.rs index 4664808..16cb65f 100644 --- a/pkstrings/src/tests.rs +++ b/pkstrings/src/tests.rs @@ -13,11 +13,12 @@ // You should have received a copy of the GNU Affero General Public License // along with this program. If not, see . -use crate::PKString; +use crate::{PKString, Error}; use std::convert::TryFrom; const GARY_SLICE_U8: &[u8] = &[0x86, 0x80, 0x91, 0x98]; const GARY_STR: &str = "GARY"; +const INVALID_BYTE: u8 = 0x01; #[test] fn test_try_from_u8() { @@ -26,7 +27,7 @@ fn test_try_from_u8() { Err(_) => panic!(), } - match PKString::try_from(0x79) { // Invalid + match PKString::try_from(INVALID_BYTE) { Ok(_) => panic!(), Err(_) => (), } @@ -42,12 +43,12 @@ fn test_try_from_slice_u8() { let invalid: &[u8] = &[ 0x86, 0x80, - 0x79, // Invalid + INVALID_BYTE, 0x98, ]; match PKString::try_from(invalid) { - Ok(_) => panic!(), - Err(_) => (), + Err(Error::InvalidByte(ord)) => assert_eq!(ord, INVALID_BYTE), + _ => panic!(), } } @@ -62,7 +63,7 @@ fn test_try_from_vec_u8() { let invalid: Vec = vec![ 0x86, 0x80, - 0x79, // Invalid + INVALID_BYTE, 0x98, ]; match PKString::try_from(invalid) {