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:
parent
1796f08e58
commit
0a3a455b31
3 changed files with 56 additions and 43 deletions
|
@ -18,4 +18,4 @@ pub mod pkstring;
|
|||
#[cfg(test)]
|
||||
mod tests;
|
||||
|
||||
pub use pkstring::PKString;
|
||||
pub use pkstring::{Error, PKString};
|
||||
|
|
|
@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -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) {
|
||||
|
|
Loading…
Reference in a new issue