diff --git a/models/src/bio.rs b/models/src/bio.rs index 9e29181..06516f0 100644 --- a/models/src/bio.rs +++ b/models/src/bio.rs @@ -9,7 +9,7 @@ pub struct Biography(pub VarriableCharArray); impl Model for Biography { fn new(buffer: &[u8]) -> Self { - Self(VarriableCharArray(buffer.to_vec())) + Self(VarriableCharArray(buffer.into())) } fn create_as_rc(buffer: &[u8]) -> Rc { diff --git a/models/src/common/varriable_char_array.rs b/models/src/common/varriable_char_array.rs index a3b5d46..2381e29 100644 --- a/models/src/common/varriable_char_array.rs +++ b/models/src/common/varriable_char_array.rs @@ -1,11 +1,12 @@ -use std::fmt::{Debug, Display}; +use std::{ + fmt::{Debug, Display}, + rc::Rc, +}; use serde::{Serialize, Serializer}; -pub const DEFAULT: &VarriableCharArray = &VarriableCharArray(vec![]); - #[derive(PartialEq, Eq)] -pub struct VarriableCharArray(pub Vec); +pub struct VarriableCharArray(pub Rc<[u8]>); impl Display for VarriableCharArray { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { @@ -27,11 +28,10 @@ impl Debug for VarriableCharArray { impl From<&str> for VarriableCharArray { fn from(value: &str) -> Self { - Self(value.as_bytes().to_vec()) + Self(value.as_bytes().into()) } } -// TODO: Make this less expensive impl Clone for VarriableCharArray { fn clone(&self) -> Self { Self(self.0.clone()) @@ -46,3 +46,17 @@ impl Serialize for VarriableCharArray { serializer.collect_str(&format!("{}", self)) } } + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn strips_nulls_and_returns() { + let from = "BALDUR\0"; + let expected = "BALDUR"; + assert_eq!( + VarriableCharArray(from.as_bytes().into()).to_string(), + expected + ) + } +} diff --git a/models/src/ids.rs b/models/src/ids.rs index dfbcc00..6819b3a 100644 --- a/models/src/ids.rs +++ b/models/src/ids.rs @@ -4,9 +4,7 @@ use serde::Serialize; use crate::{ common::{ - fixed_char_array::FixedCharSlice, - header::Header, - varriable_char_array::{VarriableCharArray, DEFAULT}, + fixed_char_array::FixedCharSlice, header::Header, varriable_char_array::VarriableCharArray, }, model::Model, resources::utils::row_parser, @@ -30,12 +28,18 @@ impl Model for Ids { fn new(buffer: &[u8]) -> Self { let (headers, mut end) = row_parser(buffer, 0); - let signature = headers.first().unwrap_or(DEFAULT); - let header = Header { - signature: FixedCharSlice::<3>::try_from(signature).unwrap_or_default(), - version: FixedCharSlice::<4>::try_from(headers.last().unwrap_or(signature)) - .unwrap_or_default(), + let signature = if let Some(_) = headers.first() { + FixedCharSlice::<3>::from(&buffer[0..3]) + } else { + FixedCharSlice::<3>::default() }; + let version = match headers.last() { + Some(x) if FixedCharSlice::<4>::try_from(x).is_ok() => { + FixedCharSlice::<4>::try_from(x).unwrap() + } + _ => FixedCharSlice::<4>::from(signature.0.as_ref()), + }; + let header = Header { signature, version }; let mut data_entries = vec![]; while end < buffer.len() { diff --git a/models/src/key.rs b/models/src/key.rs index fd98e61..3b700bd 100644 --- a/models/src/key.rs +++ b/models/src/key.rs @@ -76,7 +76,7 @@ impl BiffIndex { let end = start + usize::try_from(header.file_name_length).unwrap_or(0); buffer.get(start..end).map(|buff| BiffIndex { header: *header, - name: VarriableCharArray(buff.to_vec()), + name: VarriableCharArray(buff.into()), }) } } diff --git a/models/src/resources/utils.rs b/models/src/resources/utils.rs index 5a74e61..113eaac 100644 --- a/models/src/resources/utils.rs +++ b/models/src/resources/utils.rs @@ -1,6 +1,8 @@ use std::{ mem::{size_of, ManuallyDrop}, - ptr, vec, + ptr, + rc::Rc, + vec, }; use crate::common::varriable_char_array::VarriableCharArray; @@ -41,18 +43,23 @@ const CARRAGE_RETURN: u8 = 0xD; const NEW_LINE: u8 = 0xA; pub fn dumb_row_parser(buffer: &[u8]) -> Vec { - buffer - .iter() - .fold(vec![], |mut acc: Vec, x: &u8| { - match x { - x if x == &NEW_LINE || x == &CARRAGE_RETURN => { - acc.push(VarriableCharArray(vec![32])) - } - x if acc.last().is_some() => acc.last_mut().unwrap().0.push(*x), - _ => acc.push(VarriableCharArray(vec![*x])), + let mut acc = vec![]; + let mut pos = 0; + for (i, x) in buffer.iter().enumerate() { + if x == &NEW_LINE || x == &CARRAGE_RETURN { + if pos < i { + acc.push(VarriableCharArray(buffer.get(pos..i).unwrap().into())) } - acc - }) + acc.push(VarriableCharArray(Rc::new([32]))); + pos = i; + } + } + if pos < buffer.len() { + acc.push(VarriableCharArray( + buffer.get(pos..buffer.len()).unwrap().into(), + )) + } + acc } pub fn row_parser(buffer: &[u8], row_start: usize) -> (Vec, usize) { @@ -70,7 +77,7 @@ pub fn row_parser(buffer: &[u8], row_start: usize) -> (Vec, if buff.is_empty() { return None; } - Some(VarriableCharArray(buff.to_vec())) + Some(VarriableCharArray(buff.into())) }) .collect(); diff --git a/models/src/tlk.rs b/models/src/tlk.rs index ffeac64..821822a 100644 --- a/models/src/tlk.rs +++ b/models/src/tlk.rs @@ -79,7 +79,7 @@ impl TLKDataEntry { + usize::try_from(entry.offset_of_this_string_relative_to_the_strings_section) .unwrap_or(0); let buff_end = buff_start + usize::try_from(entry.length_of_this_string).unwrap_or(0); - let strings = VarriableCharArray(buffer.get(buff_start..buff_end).unwrap().to_vec()); + let strings = VarriableCharArray(buffer.get(buff_start..buff_end).unwrap().into()); TLKDataEntry { entry: *entry, diff --git a/models/src/twoda.rs b/models/src/twoda.rs index 25f7e9b..a866785 100644 --- a/models/src/twoda.rs +++ b/models/src/twoda.rs @@ -6,7 +6,7 @@ use serde::Serialize; use crate::common::fixed_char_array::FixedCharSlice; use crate::common::header::Header; -use crate::common::varriable_char_array::{VarriableCharArray, DEFAULT}; +use crate::common::varriable_char_array::VarriableCharArray; use crate::model::Model; use crate::resources::utils::row_parser; use crate::tlk::Lookup; @@ -46,13 +46,22 @@ impl Model for TwoDA { } end = row_end; } + + let signature = if let Some(_) = headers.first() { + FixedCharSlice::<3>::from(&buffer[0..3]) + } else { + FixedCharSlice::<3>::default() + }; + let version = match headers.last() { + Some(x) if FixedCharSlice::<4>::try_from(x).is_ok() => { + FixedCharSlice::<4>::try_from(x).unwrap() + } + _ => FixedCharSlice::<4>::from(signature.0.as_ref()), + }; + let header = Header { signature, version }; + Self { - header: Header { - signature: FixedCharSlice::<3>::try_from(headers.first().unwrap_or(DEFAULT)) - .unwrap_or_else(|_| "2DA".into()), - version: FixedCharSlice::<4>::try_from(headers.last().unwrap_or(DEFAULT)) - .unwrap_or_default(), - }, + header, default_value: default_values.first().unwrap().clone(), data_entries: DataEntry { data_entry_headers, @@ -73,8 +82,6 @@ impl Model for TwoDA { #[cfg(test)] mod tests { - use crate::common::varriable_char_array::DEFAULT; - use super::*; use std::{ fs::File, @@ -102,12 +109,12 @@ mod tests { item.data_entries .data_entry_headers .first() - .unwrap_or(DEFAULT) + .unwrap() .to_string(), "VALUE" ); let last_values = item.data_entries.values.last().unwrap(); - assert_eq!(last_values.first().unwrap_or(DEFAULT).to_string(), "SHAMAN"); - assert_eq!(last_values.last().unwrap_or(DEFAULT).to_string(), "-1"); + assert_eq!(last_values.first().unwrap().to_string(), "SHAMAN"); + assert_eq!(last_values.last().unwrap().to_string(), "-1"); } }