pkstrings: Move conversion cost to String away from from creation time

Signed-off-by: Maxime “pep” Buquet <pep@bouah.net>
This commit is contained in:
Maxime “pep” Buquet 2021-11-15 13:16:50 +01:00
parent 1796f08e58
commit 0a3a455b31
Signed by: pep
GPG key ID: DEDA74AEECA9D0F2
3 changed files with 56 additions and 43 deletions

View file

@ -18,4 +18,4 @@ pub mod pkstring;
#[cfg(test)]
mod tests;
pub use pkstring::PKString;
pub use pkstring::{Error, PKString};

View file

@ -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<u8> {
Some(match chr {
cap @ 'A'..='Z' => 0x80 - ('A' as u8) + (*cap as u8),
@ -55,7 +67,7 @@ const fn strtohex(chr: &char) -> Option<u8> {
})
}
const fn hextostr(hex: u8) -> Option<char> {
const fn hextochr(hex: u8) -> Option<char> {
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<u8>);
impl Deref for PKString {
type Target = String;
type Target = Vec<u8>;
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<u8> for PKString {
type Error = Error;
fn try_from(ord: u8) -> Result<PKString, Error> {
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<PKString, Error> {
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, Error> {
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<String> for PKString {
type Error = Error;
fn try_from(data: String) -> Result<PKString, Error> {
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<PKString> for Vec<u8> {
fn from(pkstr: PKString) -> Vec<u8> {
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<PKString> 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
}
}

View file

@ -13,11 +13,12 @@
// You should have received a copy of the GNU Affero General Public License
// along with this program. If not, see <https://www.gnu.org/licenses/>.
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<u8> = vec![
0x86,
0x80,
0x79, // Invalid
INVALID_BYTE,
0x98,
];
match PKString::try_from(invalid) {