From 21282238ed68cf337aa37b16aa714630552c4168 Mon Sep 17 00:00:00 2001 From: Christopher Sardegna Date: Wed, 16 Sep 2026 16:37:00 -0700 Subject: [PATCH 1/6] Add `SharedString` struct for managing shared strings in deserialization --- src/models/shared_string.rs | 128 ++++++++++++++++++++++++++++++++++++ 1 file changed, 128 insertions(+) create mode 100644 src/models/shared_string.rs diff --git a/src/models/shared_string.rs b/src/models/shared_string.rs new file mode 100644 index 0000000..2703c8e --- /dev/null +++ b/src/models/shared_string.rs @@ -0,0 +1,128 @@ +//! One entry in the shared-string table, and why an entry needs two views. + +use crate::{ + error::Result, + models::types::{Type, TypeEntry}, +}; + +/// One entry in the deserializer's shared-string table. +/// +/// `NSArchiver` writes each string into the stream once, as a literal, and +/// refers to it by index thereafter. Type descriptors, class names, +/// selectors, and `char *` values all go through this one table, so the index +/// space is shared among all of them. This matters because a single entry can +/// play more than one role: `NSValue` writes its `objCType` as a `char *` +/// value, then types the payload that follows with a reference to that same +/// string. The first use wants the text; the second wants it parsed as a +/// descriptor. +/// +/// To accomplish this, every entry keeps its text, and the descriptor view is +/// parsed at most once. A descriptor literal is parsed at registration, since +/// the deserializer is about to read values with it. A name or value is not, +/// since a class name is never a valid descriptor and parsing it would fail; +/// its view is parsed only if a descriptor reference later resolves to it. +/// This means an entry never changes meaning: the text is always there, and a +/// parsed view, once present, is exactly what the text says. +/// +/// Equality compares the text alone. The parsed view is a cache of the text, +/// so two entries with the same text are the same string whether or not +/// either has been used as a descriptor yet. +#[derive(Clone)] +pub struct SharedString<'a> { + /// The text, borrowed from the stream. + pub text: &'a str, + /// The descriptor view, once something has needed it. + parsed: Option, +} + +impl<'a> SharedString<'a> { + /// A freshly registered string, with no descriptor view yet. + #[must_use] + pub const fn new(text: &'a str) -> Self { + Self { text, parsed: None } + } + + /// The descriptor view, parsing the text the first time it is asked for. + /// + /// `max_slots` is the number of stream bytes that follow the descriptor. + /// Since every slot reads at least one byte, an array that expands past + /// that count cannot be satisfied by the stream, and the parser rejects it + /// before allocating for it. + pub fn descriptor(&mut self, max_slots: usize) -> Result<&TypeEntry> { + if self.parsed.is_none() { + self.parsed = Some(Type::parse_descriptor(self.text, max_slots)?); + } + Ok(self.parsed.as_ref().expect("set above")) + } + + /// The descriptor view, if something has already parsed it. + #[must_use] + pub fn parsed(&self) -> Option<&TypeEntry> { + self.parsed.as_ref() + } +} + +impl PartialEq for SharedString<'_> { + fn eq(&self, other: &Self) -> bool { + self.text == other.text + } +} + +impl PartialEq for SharedString<'_> { + fn eq(&self, other: &str) -> bool { + self.text == other + } +} + +impl PartialEq<&str> for SharedString<'_> { + fn eq(&self, other: &&str) -> bool { + self.text == *other + } +} + +impl core::fmt::Debug for SharedString<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{:?}", self.text)?; + if let Some(parsed) = &self.parsed { + write!(f, " ({parsed:?})")?; + } + Ok(()) + } +} + +impl core::fmt::Display for SharedString<'_> { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + f.write_str(self.text) + } +} + +#[cfg(test)] +mod tests { + use super::SharedString; + use crate::models::types::{Type, TypeEntry}; + + /// The table is plain data: no interior mutability, so it stays `Sync`. + #[test] + fn shared_string_is_send_and_sync() { + fn assert_send_sync() {} + assert_send_sync::>(); + } + + #[test] + fn descriptor_parses_once_and_equality_ignores_it() { + let mut entry = SharedString::new("iI"); + assert_eq!(entry.parsed(), None); + assert_eq!( + entry.descriptor(8).unwrap(), + &TypeEntry::Many(alloc::vec![Type::SignedInt, Type::UnsignedInt]) + ); + assert!(entry.parsed().is_some()); + assert_eq!(entry, SharedString::new("iI")); + assert_eq!(entry, "iI"); + assert_ne!(entry, SharedString::new("iC")); + // A name is never a valid descriptor; the failure is not cached. + let mut name = SharedString::new("NSString"); + assert!(name.descriptor(8).is_err()); + assert_eq!(name.parsed(), None); + } +} From 2fd95008ba3376994d988ac0363613627d562a06 Mon Sep 17 00:00:00 2001 From: Christopher Sardegna Date: Wed, 16 Sep 2026 16:38:07 -0700 Subject: [PATCH 2/6] Refactor documentation for CString and Class name reference; update OutputData enum comment for clarity --- src/models/archived.rs | 12 +++++++----- src/models/class.rs | 2 +- src/models/mod.rs | 1 + src/models/output_data.rs | 2 +- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/src/models/archived.rs b/src/models/archived.rs index 3770c21..7778d71 100644 --- a/src/models/archived.rs +++ b/src/models/archived.rs @@ -139,10 +139,12 @@ pub enum Archived<'a> { /// comes before the ones it inherits from. To preserve the order, we reserve the first slot to store the actual object's data /// and then later add it back to the right place. Placeholder, - /// A `char *` value represented by a shared-string index. During decoding, - /// allocate one object-table slot per distinct pointer and store the string - /// index in that slot. Look up the text in the - /// [`type_table`](crate::deserializer::typedstream::TypedStreamDeserializer::type_table); - /// reuse that entry for descriptors and class names. + /// A `char *` value. `NSArchiver` shares C strings by pointer identity + /// through the object table, so each distinct pointer takes one slot here + /// and a repeated pointer is written as a reference to that slot. The text + /// itself is shared separately, through the + /// [`string_table`](crate::deserializer::typedstream::TypedStreamDeserializer::string_table), + /// which this index names. This means two pointers with the same text get + /// two slots but one string. CString(usize), } diff --git a/src/models/class.rs b/src/models/class.rs index bdf5176..674dacf 100644 --- a/src/models/class.rs +++ b/src/models/class.rs @@ -3,7 +3,7 @@ /// Represents a class stored in a `typedstream` #[derive(Debug, Clone, PartialEq, Eq)] pub struct Class { - /// A reference to the class name stored in the [`type_table`](crate::deserializer::typedstream::TypedStreamDeserializer::type_table) + /// A reference to the class name stored in the [`string_table`](crate::deserializer::typedstream::TypedStreamDeserializer::string_table) pub name_index: usize, /// The encoded version of the class pub version: u64, diff --git a/src/models/mod.rs b/src/models/mod.rs index 9f2b68c..cd5591c 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -3,4 +3,5 @@ pub mod archived; pub mod class; pub mod output_data; +pub mod shared_string; pub mod types; diff --git a/src/models/output_data.rs b/src/models/output_data.rs index 0f66444..2e7cc3a 100644 --- a/src/models/output_data.rs +++ b/src/models/output_data.rs @@ -3,7 +3,7 @@ /// Rust structures containing data stored in the `typedstream` #[derive(Debug, PartialEq)] pub enum OutputData<'a> { - /// Text data, denoted in the stream by [`Type::String`](crate::models::types::Type::String) + /// Text: a `+` string, a selector, a `char *`, or a class name. String(&'a str), /// Signed integer types are coerced into this container, denoted in the stream by [`Type::SignedInt`](crate::models::types::Type::SignedInt) SignedInteger(i64), From aab95ea3b3b0e8370d9c7403cbb9d1eafd933f73 Mon Sep 17 00:00:00 2001 From: Christopher Sardegna Date: Wed, 16 Sep 2026 16:38:24 -0700 Subject: [PATCH 3/6] Refactor `PropertyGroup` and `PropertyIterator` to use `SharedString` instead of `TypeEntry` for string management --- src/deserializer/iter.rs | 33 ++++++++++++++------------------- 1 file changed, 14 insertions(+), 19 deletions(-) diff --git a/src/deserializer/iter.rs b/src/deserializer/iter.rs index f002fb7..98dcdf5 100644 --- a/src/deserializer/iter.rs +++ b/src/deserializer/iter.rs @@ -8,7 +8,7 @@ use crate::models::{ archived::{Archived, DataGroup, ObjectData}, class::Class, output_data::OutputData, - types::{Type, TypeEntry}, + shared_string::SharedString, }; /// A single resolved property from an [`Archived::Object`]. @@ -18,7 +18,7 @@ pub enum Property<'a, 'b> { Object { /// The class of the object class: &'a Class, - /// The name of the class, typically a string from the type table + /// The name of the class, its entry in the string table name: &'a str, /// An iterator over the properties of this object data: PropertyIterator<'a, 'b>, @@ -43,7 +43,7 @@ pub enum Property<'a, 'b> { pub struct PropertyGroup<'a, 'b> { items: &'b [OutputData<'a>], object_table: &'b [Archived<'a>], - type_table: &'b [TypeEntry<'a>], + string_table: &'b [SharedString<'a>], } impl<'a, 'b: 'a> PropertyGroup<'a, 'b> { @@ -83,10 +83,10 @@ impl<'a, 'b: 'a> PropertyGroup<'a, 'b> { } /// Resolve a single stored value into a [`Property`]. Object references are - /// resolved against the object/type tables; everything else is a primitive. + /// resolved against the object and string tables; everything else is a primitive. fn resolve(&self, item: &'b OutputData<'a>) -> Property<'a, 'b> { if let OutputData::Object(idx) = item - && let Some(object) = object_property(self.object_table, self.type_table, *idx) + && let Some(object) = object_property(self.object_table, self.string_table, *idx) { return object; } @@ -99,7 +99,7 @@ impl<'a, 'b: 'a> PropertyGroup<'a, 'b> { /// [`PropertyGroup`] resolution and the deserializer's object/root resolvers. pub(crate) fn object_property<'a, 'b: 'a>( object_table: &'b [Archived<'a>], - type_table: &'b [TypeEntry<'a>], + string_table: &'b [SharedString<'a>], index: usize, ) -> Option> { let Some(Archived::Object { class: cls, .. }) = object_table.get(index) else { @@ -108,15 +108,10 @@ pub(crate) fn object_property<'a, 'b: 'a>( let Some(Archived::Class(cls)) = object_table.get(*cls) else { return None; }; - let data = PropertyIterator::new(object_table, type_table, index)?; - let name = type_table + let data = PropertyIterator::new(object_table, string_table, index)?; + let name = string_table .get(cls.name_index) - .and_then(|types| types.first()) - .and_then(|t| match t { - Type::String(name) => Some(*name), - _ => None, - }) - .unwrap_or("Unknown Class"); + .map_or("Unknown Class", |entry| entry.text); Some(Property::Object { class: cls, name, @@ -183,7 +178,7 @@ impl<'a, 'b: 'a> ExactSizeIterator for PropertyGroupIter<'a, 'b> {} /// An iterator that resolves the top-level properties of a single [`Archived::Object`]. /// /// This iterator will yield `Property` items, which can be either nested objects or primitive values. -/// It is created from an `Archived` object and its associated type table. +/// It is created from an `Archived` object and its associated string table. /// /// It is designed to traverse the properties of an object, allowing you to access nested objects and their properties recursively. /// @@ -209,7 +204,7 @@ impl<'a, 'b: 'a> ExactSizeIterator for PropertyGroupIter<'a, 'b> {} #[derive(Debug, Clone)] pub struct PropertyIterator<'a, 'b> { object_table: &'b [Archived<'a>], - type_table: &'b [TypeEntry<'a>], + string_table: &'b [SharedString<'a>], groups: GroupSource<'a, 'b>, } @@ -227,7 +222,7 @@ enum GroupSource<'a, 'b> { impl<'a, 'b> PropertyIterator<'a, 'b> { pub(crate) fn new( object_table: &'b [Archived<'a>], - type_table: &'b [TypeEntry<'a>], + string_table: &'b [SharedString<'a>], root_object_index: usize, ) -> Option { let root_object = object_table.get(root_object_index)?; @@ -244,7 +239,7 @@ impl<'a, 'b> PropertyIterator<'a, 'b> { Some(Self { object_table, - type_table, + string_table, groups, }) } @@ -347,7 +342,7 @@ impl<'a, 'b: 'a> Iterator for PropertyIterator<'a, 'b> { Some(Property::Group(PropertyGroup { items, object_table: self.object_table, - type_table: self.type_table, + string_table: self.string_table, })) } } From dfcac732b03f8f2fd439d50cd873e1545f01efa2 Mon Sep 17 00:00:00 2001 From: Christopher Sardegna Date: Wed, 16 Sep 2026 16:40:52 -0700 Subject: [PATCH 4/6] Refactor `TypedStreamDeserializer` to replace `type_table` and `strings` with `string_table` for improved shared string management --- src/deserializer/typedstream.rs | 144 +++++++++++++++++--------------- 1 file changed, 75 insertions(+), 69 deletions(-) diff --git a/src/deserializer/typedstream.rs b/src/deserializer/typedstream.rs index 23dc890..f581fdf 100644 --- a/src/deserializer/typedstream.rs +++ b/src/deserializer/typedstream.rs @@ -20,7 +20,8 @@ use crate::{ archived::{Archived, DataGroup, ObjectData}, class::Class, output_data::OutputData, - types::{Type, TypeEntry}, + shared_string::SharedString, + types::Type, }, }; @@ -37,18 +38,13 @@ pub struct TypedStreamDeserializer<'a> { pub data: &'a [u8], /// The current index we are at in the stream pub(crate) position: usize, - /// The shared-string table, with descriptor literals stored as parsed types. - /// - /// Shared-string layout: literal once, index thereafter. Entry kinds: - /// type descriptors, class names, selectors, and `char *` values. Register - /// names and values as [`Type::String`]; parse an entry in place before - /// using it as a descriptor. Keep every entry's original text available - /// through [`shared_string`](Self::shared_string). - pub type_table: Vec>, - /// Text for each [`type_table`](Self::type_table) entry, by index. Keep both - /// vectors aligned by routing every registration through - /// [`register_string`](Self::register_string). - pub(crate) strings: Vec<&'a str>, + /// The shared-string table. `NSArchiver` writes every string once and + /// refers to it by index afterward, and type descriptors, class names, + /// selectors, and `char *` values all share that one index space. This + /// means a reference byte in the stream is an index here, whatever kind of + /// string it names; see [`SharedString`] for how one entry serves as both + /// text and descriptor. + pub string_table: Vec>, /// As we parse the `typedstream`, build a table of seen [`Archived`] data to reference in the future pub object_table: Vec>, } @@ -72,8 +68,7 @@ impl<'a> TypedStreamDeserializer<'a> { Self { data, position: 0, - type_table: Vec::new(), - strings: Vec::new(), + string_table: Vec::new(), object_table: Vec::new(), } } @@ -122,9 +117,8 @@ impl<'a> TypedStreamDeserializer<'a> { // distinct-object-heavy streams); the object table is the only one that // grows large, so the others stay tight. let estimated_size = self.data.len(); - let strings = (estimated_size / 64).clamp(16, 256); - self.type_table.reserve(strings); - self.strings.reserve(strings); + self.string_table + .reserve((estimated_size / 64).clamp(16, 256)); self.object_table .reserve((estimated_size / 16).clamp(32, 8192)); @@ -173,7 +167,7 @@ impl<'a> TypedStreamDeserializer<'a> { self.object_table.len(), )); } - PropertyIterator::new(&self.object_table, &self.type_table, root_object_index) + PropertyIterator::new(&self.object_table, &self.string_table, root_object_index) .ok_or(TypedStreamError::InvalidObject) } @@ -207,7 +201,7 @@ impl<'a> TypedStreamDeserializer<'a> { self.object_table.len(), )); } - object_property(&self.object_table, &self.type_table, object_index) + object_property(&self.object_table, &self.string_table, object_index) .ok_or(TypedStreamError::InvalidObject) } @@ -259,12 +253,12 @@ impl<'a> TypedStreamDeserializer<'a> { START => { let string_data = read_string(&self.data[self.position..])?; self.position += string_data.bytes_consumed; - Ok(self.register_string(string_data.value, None)) + Ok(self.register_string(string_data.value)) } EMPTY => Err(TypedStreamError::EmptyString), ptr => { let index = read_pointer(&ptr)?.value as usize; - if index < self.strings.len() { + if index < self.string_table.len() { Ok(index) } else { Err(TypedStreamError::InvalidPointer(index as u8)) @@ -273,8 +267,8 @@ impl<'a> TypedStreamDeserializer<'a> { } } - /// Returns the text of shared-string entry `index`: a type descriptor, class - /// name, selector, or `char *` value. + /// The text of shared-string entry `index`, whichever kind of string it is: + /// a type descriptor, a class name, a selector, or a `char *` value. /// /// # Examples /// @@ -287,21 +281,20 @@ impl<'a> TypedStreamDeserializer<'a> { /// ``` #[must_use] pub fn shared_string(&self, index: usize) -> Option<&'a str> { - debug_assert_eq!(self.strings.len(), self.type_table.len()); - self.strings.get(index).copied() + self.string_table.get(index).map(|entry| entry.text) } - /// Appends a shared string to both tables and returns its index. Route every - /// registration through this function so the tables remain aligned. - /// - /// `parsed`: the descriptor view for a descriptor literal. For a name or - /// value, omit parsed types; parse the entry only for descriptor use. - fn register_string(&mut self, text: &'a str, parsed: Option>) -> usize { - self.type_table - .push(parsed.unwrap_or(TypeEntry::One(Type::new_string(text)))); - self.strings.push(text); - debug_assert_eq!(self.strings.len(), self.type_table.len()); - self.strings.len() - 1 + /// Appends a shared string and returns its index. Every registration comes + /// through here, so the table grows in exactly the order `NSArchiver` + /// assigned indices. + /// + /// The entry starts as plain text. Whoever uses it as a descriptor parses + /// it then: `read_type` immediately for a literal, and on the first + /// reference for a name or `char *` value. + fn register_string(&mut self, text: &'a str) -> usize { + let index = self.string_table.len(); + self.string_table.push(SharedString::new(text)); + index } /// Reads a class from the stream, handling nested class definitions. @@ -408,7 +401,7 @@ impl<'a> TypedStreamDeserializer<'a> { } /// Reads numeric types (signed, unsigned, float, double) and returns the corresponding `OutputData` - fn read_number(&mut self, ty: Type<'a>) -> Result> { + fn read_number(&mut self, ty: Type) -> Result> { match ty { Type::SignedInt => { let signed_int = read_signed_int(&self.data[self.position..])?; @@ -436,7 +429,7 @@ impl<'a> TypedStreamDeserializer<'a> { /// Decodes one slot of a descriptor into one [`OutputData`] value. #[inline] - fn read_value(&mut self, ty: Type<'a>) -> Result> { + fn read_value(&mut self, ty: Type) -> Result> { match ty { Type::Utf8String => { let str_data = read_string(&self.data[self.position..])?; @@ -451,8 +444,6 @@ impl<'a> TypedStreamDeserializer<'a> { None => OutputData::Null, }) } - // Parse every string-table entry in `read_type` before passing it to `read_types` - Type::String(_) => Err(TypedStreamError::InvalidObject), Type::Array(length) => { let array_data = read_exact_bytes(&self.data[self.position..], length)?; self.position += length; @@ -465,7 +456,7 @@ impl<'a> TypedStreamDeserializer<'a> { return Ok(OutputData::Null); } let index = self.read_string()?; - Ok(OutputData::String(self.strings[index])) + Ok(OutputData::String(self.string_table[index].text)) } // Track C strings by pointer identity through the object table: // allocate a slot on `START`, store the shared-string index, and @@ -475,13 +466,13 @@ impl<'a> TypedStreamDeserializer<'a> { START => { let index = self.read_string()?; self.object_table.push(Archived::CString(index)); - Ok(OutputData::String(self.strings[index])) + Ok(OutputData::String(self.string_table[index].text)) } ptr => { let slot = read_pointer(&ptr)?.value as usize; match self.object_table.get(slot) { Some(Archived::CString(index)) => { - Ok(OutputData::String(self.strings[*index])) + Ok(OutputData::String(self.string_table[*index].text)) } _ => Err(TypedStreamError::InvalidPointer(slot as u8)), } @@ -503,17 +494,28 @@ impl<'a> TypedStreamDeserializer<'a> { /// Reads one value per slot of the descriptor at `types_index` into a /// single data group. fn read_types(&mut self, types_index: usize) -> Result> { - let len = self.type_table[types_index].len(); + // `read_type` parsed the entry before handing over its index; `Type` is + // `Copy`, so each slot is fetched without holding the table borrow. + let slot = |ts: &Self, i: usize| -> Result { + let parsed = ts.string_table[types_index] + .parsed() + .ok_or(TypedStreamError::InvalidObject)?; + Ok(parsed[i]) + }; + let len = self.string_table[types_index] + .parsed() + .ok_or(TypedStreamError::InvalidObject)? + .len(); // Common case: a single descriptor decodes to a single value with no Vec. if len == 1 { - let ty = self.type_table[types_index][0]; + let ty = slot(self, 0)?; return Ok(DataGroup::One(self.read_value(ty)?)); } let mut out_v = Vec::with_capacity(len); for i in 0..len { - let ty = self.type_table[types_index][i]; + let ty = slot(self, i)?; out_v.push(self.read_value(ty)?); } Ok(DataGroup::Values(out_v)) @@ -521,34 +523,37 @@ impl<'a> TypedStreamDeserializer<'a> { /// Reads a type descriptor: a literal, registered as a new shared string, or /// a reference to an existing one. Returns its index in - /// [`type_table`](Self::type_table), or `None` at an [`END`]/[`EMPTY`] marker + /// [`string_table`](Self::string_table), or `None` at an [`END`]/[`EMPTY`] marker /// where a descriptor was optional. /// - /// Descriptor-reference case: a name or `char *` value already in the - /// referenced entry. For `NSValue`'s `objCType`, parse that entry in place, - /// then use its text to decode the following value. Keep the text in - /// [`strings`](Self::strings). + /// A reference may resolve to an entry that was registered as a name or + /// `char *` value rather than as a descriptor. `NSValue` does exactly this: + /// it writes its `objCType` as a `char *`, then references that same string + /// as the descriptor for the value that follows. Since the entry keeps its + /// text, the deserializer parses the descriptor view on that first use and + /// the entry serves both roles from then on. fn read_type(&mut self) -> Result> { - match *self.consume_current_byte()? { + let index = match *self.consume_current_byte()? { START => { - let literal = Type::read_new_type(&self.data[self.position..])?; + let literal = read_string(&self.data[self.position..])?; self.position += literal.bytes_consumed; - let (text, entry) = literal.value; - Ok(Some(self.register_string(text, Some(entry)))) + self.register_string(literal.value) } - END | EMPTY => Ok(None), + END | EMPTY => return Ok(None), ptr => { let index = read_pointer(&ptr)?.value as usize; - if index >= self.type_table.len() { + if index >= self.string_table.len() { return Err(TypedStreamError::InvalidPointer(index as u8)); } - if let Some(Type::String(text)) = self.type_table[index].first() { - let remaining = self.data.len() - self.position; - self.type_table[index] = Type::parse_descriptor(text, remaining)?; - } - Ok(Some(index)) + index } - } + }; + // A literal is parsed here, before any value is read with it, so a + // malformed descriptor fails at its own bytes. A reference to a name or + // `char *` value is parsed here too, on this first use as a descriptor. + let remaining = self.data.len() - self.position; + self.string_table[index].descriptor(remaining)?; + Ok(Some(index)) } } @@ -765,10 +770,7 @@ mod group_tests { let Archived::Class(class) = &ts.object_table[*class_idx] else { panic!("`#` must reference a class entry"); }; - assert_eq!( - ts.type_table[class.name_index].first(), - Some(&Type::String("Foo")) - ); + assert_eq!(ts.string_table[class.name_index].text, "Foo"); assert_eq!(class.version, 2); assert_eq!(class.parent_index, None); assert_eq!(ts.position, bytes.len()); @@ -912,7 +914,11 @@ mod group_tests { // descriptor references it, while preserving the original text for // `shared_string`. assert_eq!(ts.shared_string(3), Some("q")); - assert_eq!(ts.type_table[3], TypeEntry::One(Type::SignedInt)); + assert_eq!(ts.string_table[3].text, "q"); + assert_eq!( + ts.string_table[3].parsed(), + Some(&TypeEntry::One(Type::SignedInt)) + ); assert_eq!(ts.object_table[2], Archived::CString(3)); assert_eq!(ts.position, bytes.len()); } From e46cbde627341816bd3df432d01a307e5f34b4eb Mon Sep 17 00:00:00 2001 From: Christopher Sardegna Date: Wed, 16 Sep 2026 16:41:04 -0700 Subject: [PATCH 5/6] Refactor `Type` and `TypeEntry` enums to remove lifetime parameters and simplify type management --- src/models/types.rs | 87 ++++++++++----------------------------------- 1 file changed, 19 insertions(+), 68 deletions(-) diff --git a/src/models/types.rs b/src/models/types.rs index 69af46b..56cd0c9 100644 --- a/src/models/types.rs +++ b/src/models/types.rs @@ -1,15 +1,12 @@ //! Type tags that denote the type of data stored in a `typedstream` -use crate::{ - deserializer::{consumed::Consumed, number::read_unsigned_int, read::read_exact_bytes}, - error::{Result, TypedStreamError}, -}; +use crate::error::{Result, TypedStreamError}; use alloc::vec::Vec; /// Represents primitive types of data that can be stored in a `typedstream` /// /// These type encodings are partially documented [here](https://developer.apple.com/library/archive/documentation/Cocoa/Conceptual/ObjCRuntimeGuide/Articles/ocrtTypeEncodings.html#//apple_ref/doc/uid/TP40008048-CH100-SW1) by Apple. #[derive(Debug, Clone, Copy, PartialEq)] -pub enum Type<'a> { +pub enum Type { /// Encoded string data, usually embedded in an object. Denoted by: /// /// | Hex | UTF-8 | @@ -82,35 +79,13 @@ pub enum Type<'a> { /// |--------|-------| /// | `0x64` | [`d`](https://www.compart.com/en/unicode/U+0064) | Double, - /// Some text we can reuse later, i.e. a class name. - String(&'a str), /// `length` raw bytes: a `char` array, `[Nc]` or `[NC]`. An array of any /// other element type is expanded to `N` copies of the element's types, /// because `NSArchiver` writes each element with its own encoding. Array(usize), } -impl<'a> Type<'a> { - #[inline] - pub(crate) fn new_string(str: &'a str) -> Self { - Self::String(str) - } - - /// Reads a length-prefixed type descriptor literal and returns its text with - /// its slot types. Preserve the text for the shared-string table; use this - /// entry by index when decoding a later `char *` value. - pub(crate) fn read_new_type(data: &'_ [u8]) -> Result)>> { - let type_length = read_unsigned_int(data)?; - let type_bytes = read_exact_bytes( - &data[type_length.bytes_consumed..], - type_length.value as usize, - )?; - let bytes_consumed = type_length.bytes_consumed + type_bytes.len(); - let text = core::str::from_utf8(type_bytes)?; - let entry = Type::parse_descriptor(text, data.len() - bytes_consumed)?; - Ok(Consumed::new((text, entry), bytes_consumed)) - } - +impl Type { /// Parses a type descriptor into its slot types. /// /// Input: an Objective-C type-encoding string. @@ -122,7 +97,7 @@ impl<'a> Type<'a> { /// Use `max_slots` to bound the bytes available after the descriptor. At /// least one byte belongs to each decoded slot; an array that expands past /// this bound is malformed. - pub(crate) fn parse_descriptor(text: &str, max_slots: usize) -> Result> { + pub(crate) fn parse_descriptor(text: &str, max_slots: usize) -> Result { let bytes = text.as_bytes(); // The overwhelming majority of descriptors are a single scalar letter, @@ -167,7 +142,7 @@ impl<'a> Type<'a> { fn parse_one( bytes: &[u8], pos: &mut usize, - out: &mut Vec>, + out: &mut Vec, max_slots: usize, ) -> Result<()> { // Skip method qualifiers (`const`, `in`, `out`, ...) ahead of the type. @@ -258,20 +233,19 @@ impl<'a> Type<'a> { } } -/// One entry in the deserializer's type table. +/// The parsed view of a type descriptor: the types it denotes, in slot order. /// /// A type descriptor usually resolves to a single [`Type`]; storing that inline -/// avoids a heap allocation per entry (the table was previously a -/// `Vec>`). Multi-type descriptors fall back to a [`Vec`]. +/// avoids a heap allocation per entry. Multi-type descriptors fall back to a [`Vec`]. #[derive(Debug, Clone, PartialEq)] -pub enum TypeEntry<'a> { +pub enum TypeEntry { /// A single type, stored inline. - One(Type<'a>), + One(Type), /// Two or more types. - Many(Vec>), + Many(Vec), } -impl<'a> TypeEntry<'a> { +impl TypeEntry { /// The number of types in this entry. #[must_use] pub fn len(&self) -> usize { @@ -289,28 +263,16 @@ impl<'a> TypeEntry<'a> { /// The first type in the entry, if any. #[must_use] - pub fn first(&self) -> Option<&Type<'a>> { + pub fn first(&self) -> Option<&Type> { match self { TypeEntry::One(ty) => Some(ty), TypeEntry::Many(types) => types.first(), } } - - /// Build a [`TypeEntry`] from a list of types, normalizing the single-type - /// case to [`TypeEntry::One`]. Used by tests to express expected type tables - /// in the pre-existing nested style. - #[cfg(test)] - pub(crate) fn from_types(mut types: Vec>) -> Self { - if types.len() == 1 { - TypeEntry::One(types.pop().unwrap()) - } else { - TypeEntry::Many(types) - } - } } -impl<'a> core::ops::Index for TypeEntry<'a> { - type Output = Type<'a>; +impl core::ops::Index for TypeEntry { + type Output = Type; fn index(&self, index: usize) -> &Self::Output { match self { @@ -330,24 +292,13 @@ mod type_encoding_tests { use super::{Type, TypeEntry}; use crate::error::TypedStreamError; - /// Parses a bare encoding string as a length-prefixed descriptor followed by - /// `remaining` bytes of stream, which bound array expansion. - fn parse_with( - encoding: &str, - remaining: usize, - ) -> Result, TypedStreamError> { - let mut bytes = vec![u8::try_from(encoding.len()).unwrap()]; - bytes.extend_from_slice(encoding.as_bytes()); - bytes.resize(bytes.len() + remaining, 0); - // The parser borrows nothing from the descriptor, so the lifetime is free. - Type::read_new_type(bytes.leak()).map(|c| { - assert_eq!(c.bytes_consumed, encoding.len() + 1); - assert_eq!(c.value.0, encoding); - c.value.1 - }) + /// Parses an encoding string with `remaining` bytes of stream after it, + /// which bound array expansion. + fn parse_with(encoding: &str, remaining: usize) -> Result { + Type::parse_descriptor(encoding, remaining) } - fn parse(encoding: &str) -> Result, TypedStreamError> { + fn parse(encoding: &str) -> Result { parse_with(encoding, 64) } From 586b9656e3146a7ec833a4830484a6d3ae099581 Mon Sep 17 00:00:00 2001 From: Christopher Sardegna Date: Wed, 16 Sep 2026 16:41:21 -0700 Subject: [PATCH 6/6] Simplify test cases for new `SharedString` equality test --- src/lib.rs | 1472 +++++++++++++++++++++++++++------------------------- 1 file changed, 764 insertions(+), 708 deletions(-) diff --git a/src/lib.rs b/src/lib.rs index e4af89c..f849bfc 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -18,6 +18,7 @@ pub use deserializer::{ pub use models::{ archived::{Archived, DataGroup, ObjectData}, output_data::OutputData, + shared_string::SharedString, types::TypeEntry, }; @@ -33,7 +34,6 @@ mod test_typedstream_deserializer { archived::{Archived, DataGroup, ObjectData}, class::Class, output_data::OutputData, - types::{Type, TypeEntry}, }, }; @@ -107,9 +107,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -121,20 +121,20 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSMutableAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSMutableString")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), + let expected_types = [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", ]; let expected_objects = vec![ @@ -217,7 +217,7 @@ mod test_typedstream_deserializer { Archived::CString(9), ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -237,9 +237,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -251,19 +251,19 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::SignedInt]), + let expected_types = [ + "@", + "NSAttributedString", + "NSObject", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", + "q", ]; let expected_objects = vec![ @@ -348,7 +348,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -365,9 +365,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -379,25 +379,25 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSMutableAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSMutableString")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSURL")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSData")]), - TypeEntry::from_types(vec![Type::Array(649)]), + let expected_types = [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", + "q", + "NSURL", + "c", + "NSData", + "[649c]", ]; let expected_objects = vec![ @@ -946,7 +946,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!( typedstream.object_table[..expected_objects.len()], expected_objects @@ -969,9 +969,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -983,23 +983,23 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSMutableData")]), - TypeEntry::from_types(vec![Type::String("NSData")]), - TypeEntry::from_types(vec![Type::Array(635)]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::String("NSURL")]), - TypeEntry::from_types(vec![Type::SignedInt]), + let expected_types = [ + "@", + "NSAttributedString", + "NSObject", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSMutableData", + "NSData", + "[635c]", + "NSNumber", + "NSValue", + "*", + "NSURL", + "c", ]; let expected_objects = vec![ @@ -1192,7 +1192,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -1212,9 +1212,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -1226,25 +1226,25 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSMutableAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSMutableString")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSURL")]), - TypeEntry::from_types(vec![Type::String("NSData")]), - TypeEntry::from_types(vec![Type::Array(675)]), + let expected_types = [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", + "q", + "c", + "NSURL", + "NSData", + "[675c]", ]; let expected_objects = vec![ @@ -1446,7 +1446,7 @@ mod test_typedstream_deserializer { }), ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -1466,9 +1466,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -1480,19 +1480,19 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::SignedInt]), + let expected_types = [ + "@", + "NSAttributedString", + "NSObject", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", + "q", ]; let expected_objects = vec![ @@ -1591,7 +1591,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -1608,9 +1608,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -1622,22 +1622,22 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSMutableAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSMutableString")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::String("NSData")]), - TypeEntry::from_types(vec![Type::Array(904)]), + let expected_types = [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", + "NSData", + "[904c]", ]; let expected_objects = vec![ @@ -1808,7 +1808,7 @@ mod test_typedstream_deserializer { }), ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -1828,9 +1828,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -1842,22 +1842,22 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSMutableAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSMutableString")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::Double]), - TypeEntry::from_types(vec![Type::SignedInt]), + let expected_types = [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", + "d", + "q", ]; let expected_objects = vec![ @@ -2048,7 +2048,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -2068,9 +2068,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -2082,21 +2082,21 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSMutableAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSMutableString")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::SignedInt]), + let expected_types = [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", + "q", ]; let expected_objects = vec![ @@ -2249,7 +2249,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -2266,9 +2266,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -2280,13 +2280,7 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - ]; + let expected_types = ["@", "NSAttributedString", "NSObject", "NSString", "+"]; let expected_objects = vec![ Archived::Object { @@ -2314,7 +2308,7 @@ mod test_typedstream_deserializer { }), ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -2331,9 +2325,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -2345,22 +2339,22 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSMutableAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSMutableString")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::String("NSData")]), - TypeEntry::from_types(vec![Type::Array(535)]), + let expected_types = [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", + "NSData", + "[535c]", ]; let expected_objects = vec![ @@ -2536,7 +2530,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -2556,9 +2550,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -2570,19 +2564,19 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::SignedInt]), + let expected_types = [ + "@", + "NSAttributedString", + "NSObject", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", + "q", ]; let expected_objects = vec![ @@ -2705,7 +2699,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -2722,9 +2716,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -2736,23 +2730,23 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSMutableAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSMutableString")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::String("NSMutableData")]), - TypeEntry::from_types(vec![Type::String("NSData")]), - TypeEntry::from_types(vec![Type::Array(669)]), + let expected_types = [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", + "NSMutableData", + "NSData", + "[669c]", ]; let expected_objects = vec![ @@ -2918,7 +2912,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -2938,9 +2932,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -2952,18 +2946,18 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), + let expected_types = [ + "@", + "NSAttributedString", + "NSObject", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", ]; let expected_objects = vec![ @@ -3048,7 +3042,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -3065,9 +3059,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -3079,23 +3073,23 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSMutableData")]), - TypeEntry::from_types(vec![Type::String("NSData")]), - TypeEntry::from_types(vec![Type::Array(667)]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::String("NSURL")]), - TypeEntry::from_types(vec![Type::SignedInt]), + let expected_types = [ + "@", + "NSAttributedString", + "NSObject", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSMutableData", + "NSData", + "[667c]", + "NSNumber", + "NSValue", + "*", + "NSURL", + "c", ]; let expected_objects = vec![ @@ -3279,7 +3273,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -3299,9 +3293,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -3313,18 +3307,18 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), + let expected_types = [ + "@", + "NSAttributedString", + "NSObject", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", ]; let expected_objects = vec![ @@ -3446,7 +3440,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -3482,9 +3476,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -3496,19 +3490,19 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::SignedInt]), + let expected_types = [ + "@", + "NSAttributedString", + "NSObject", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", + "q", ]; let expected_objects = vec![ @@ -3593,7 +3587,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -3613,9 +3607,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -3627,20 +3621,20 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSMutableAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSMutableString")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), + let expected_types = [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", ]; let expected_objects = vec![ @@ -3725,7 +3719,7 @@ mod test_typedstream_deserializer { Archived::CString(9), ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -3745,9 +3739,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -3759,20 +3753,20 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSMutableAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSMutableString")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), + let expected_types = [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", ]; let expected_objects = vec![ @@ -3881,7 +3875,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -3901,9 +3895,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -3915,21 +3909,21 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSMutableAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSMutableString")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::SignedInt]), + let expected_types = [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", + "q", ]; let expected_objects = vec![ @@ -4568,7 +4562,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -4588,9 +4582,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -4602,20 +4596,20 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSMutableAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSMutableString")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), + let expected_types = [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", ]; let expected_objects = vec![ @@ -4818,7 +4812,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -4838,9 +4832,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -4852,20 +4846,20 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSMutableAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSMutableString")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), + let expected_types = [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", ]; let expected_objects = vec![ @@ -5013,7 +5007,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -5033,9 +5027,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -5047,23 +5041,23 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSMutableAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSMutableString")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSData")]), - TypeEntry::from_types(vec![Type::Array(820)]), + let expected_types = [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", + "q", + "NSData", + "[820c]", ]; let expected_objects = vec![ @@ -5300,7 +5294,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -5320,9 +5314,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -5334,25 +5328,25 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSMutableAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSMutableString")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSURL")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSData")]), - TypeEntry::from_types(vec![Type::Array(649)]), + let expected_types = [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", + "q", + "NSURL", + "c", + "NSData", + "[649c]", ]; let expected_objects = vec![ @@ -5549,7 +5543,7 @@ mod test_typedstream_deserializer { }), ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -5569,9 +5563,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -5583,25 +5577,25 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSMutableAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSMutableString")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSData")]), - TypeEntry::from_types(vec![Type::Array(591)]), - TypeEntry::from_types(vec![Type::String("NSURL")]), + let expected_types = [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", + "q", + "c", + "NSData", + "[591c]", + "NSURL", ]; let expected_objects = vec![ @@ -5813,7 +5807,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -5833,9 +5827,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -5847,19 +5841,19 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::SignedInt]), + let expected_types = [ + "@", + "NSAttributedString", + "NSObject", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", + "q", ]; let expected_objects = vec![ @@ -6100,7 +6094,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -6120,9 +6114,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -6134,18 +6128,18 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), + let expected_types = [ + "@", + "NSAttributedString", + "NSObject", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", ]; let expected_objects = vec![ @@ -6326,7 +6320,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -6346,9 +6340,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -6360,19 +6354,19 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::SignedInt]), + let expected_types = [ + "@", + "NSAttributedString", + "NSObject", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", + "q", ]; let expected_objects = vec![ @@ -6515,7 +6509,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -6535,9 +6529,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -6549,18 +6543,18 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), + let expected_types = [ + "@", + "NSAttributedString", + "NSObject", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", ]; let expected_objects = vec![ @@ -6672,7 +6666,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -6692,9 +6686,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -6706,19 +6700,19 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::SignedInt]), + let expected_types = [ + "@", + "NSAttributedString", + "NSObject", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", + "q", ]; let expected_objects = vec![ @@ -6829,7 +6823,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -6846,9 +6840,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -6860,25 +6854,25 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSMutableAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSMutableString")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSURL")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSData")]), - TypeEntry::from_types(vec![Type::Array(582)]), + let expected_types = [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSURL", + "c", + "NSNumber", + "NSValue", + "*", + "q", + "NSData", + "[582c]", ]; let expected_objects = vec![ @@ -7058,7 +7052,7 @@ mod test_typedstream_deserializer { }), ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -7078,9 +7072,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -7092,26 +7086,26 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSMutableAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSMutableString")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSURL")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSMutableData")]), - TypeEntry::from_types(vec![Type::String("NSData")]), - TypeEntry::from_types(vec![Type::Array(604)]), + let expected_types = [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSURL", + "c", + "NSNumber", + "NSValue", + "*", + "q", + "NSMutableData", + "NSData", + "[604c]", ]; let expected_objects = vec![ @@ -7297,7 +7291,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -7317,9 +7311,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -7331,20 +7325,20 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSMutableAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSMutableString")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), + let expected_types = [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", ]; let expected_objects = vec![ @@ -7427,7 +7421,7 @@ mod test_typedstream_deserializer { Archived::CString(9), ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -7471,9 +7465,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -7485,21 +7479,21 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSMutableData")]), - TypeEntry::from_types(vec![Type::String("NSData")]), - TypeEntry::from_types(vec![Type::Array(1187)]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), + let expected_types = [ + "@", + "NSAttributedString", + "NSObject", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSMutableData", + "NSData", + "[1187c]", + "NSNumber", + "NSValue", + "*", ]; let expected_objects = vec![ @@ -7667,7 +7661,7 @@ mod test_typedstream_deserializer { Archived::CString(7), ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -7687,9 +7681,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -7701,18 +7695,18 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), + let expected_types = [ + "@", + "NSAttributedString", + "NSObject", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", ]; let expected_objects = vec![ @@ -7785,7 +7779,7 @@ mod test_typedstream_deserializer { Archived::CString(7), ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -7805,9 +7799,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -7819,18 +7813,18 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), + let expected_types = [ + "@", + "NSAttributedString", + "NSObject", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", ]; let expected_objects = vec![ @@ -7905,7 +7899,7 @@ mod test_typedstream_deserializer { Archived::CString(7), ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -7925,9 +7919,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -7939,24 +7933,24 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSMutableAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSMutableString")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), - TypeEntry::from_types(vec![Type::String("NSData")]), - TypeEntry::from_types(vec![Type::Array(764)]), - TypeEntry::from_types(vec![Type::Array(748)]), - TypeEntry::from_types(vec![Type::Array(760)]), + let expected_types = [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*", + "NSData", + "[764c]", + "[748c]", + "[760c]", ]; let expected_objects = vec![ @@ -8242,7 +8236,7 @@ mod test_typedstream_deserializer { }, ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -8262,9 +8256,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -8276,22 +8270,22 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSMutableAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSMutableString")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSData")]), - TypeEntry::from_types(vec![Type::Array(754)]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), + let expected_types = [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSData", + "[754c]", + "NSNumber", + "NSValue", + "*", ]; let expected_objects = vec![ @@ -8435,7 +8429,7 @@ mod test_typedstream_deserializer { Archived::CString(9), ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -8455,9 +8449,9 @@ mod test_typedstream_deserializer { println!("Root object: {:x?}", typedstream.object_table[root]); print_resolved(typedstream.resolve_properties(root).unwrap(), 2); - println!("\nFound {:?} types:", typedstream.type_table.len()); + println!("\nFound {:?} types:", typedstream.string_table.len()); typedstream - .type_table + .string_table .iter() .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); @@ -8469,22 +8463,22 @@ mod test_typedstream_deserializer { .enumerate() .for_each(|(idx, item)| println!("\t{idx}: {item:?}")); - let expected_types = vec![ - TypeEntry::from_types(vec![Type::Object]), - TypeEntry::from_types(vec![Type::String("NSMutableAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSAttributedString")]), - TypeEntry::from_types(vec![Type::String("NSObject")]), - TypeEntry::from_types(vec![Type::String("NSMutableString")]), - TypeEntry::from_types(vec![Type::String("NSString")]), - TypeEntry::from_types(vec![Type::Utf8String]), - TypeEntry::from_types(vec![Type::SignedInt, Type::UnsignedInt]), - TypeEntry::from_types(vec![Type::String("NSDictionary")]), - TypeEntry::from_types(vec![Type::SignedInt]), - TypeEntry::from_types(vec![Type::String("NSData")]), - TypeEntry::from_types(vec![Type::Array(664)]), - TypeEntry::from_types(vec![Type::String("NSNumber")]), - TypeEntry::from_types(vec![Type::String("NSValue")]), - TypeEntry::from_types(vec![Type::CString]), + let expected_types = [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSData", + "[664c]", + "NSNumber", + "NSValue", + "*", ]; let expected_objects = vec![ @@ -8626,7 +8620,7 @@ mod test_typedstream_deserializer { Archived::CString(9), ]; - assert_eq!(typedstream.type_table, expected_types); + assert_eq!(typedstream.string_table, expected_types); assert_eq!(typedstream.object_table, expected_objects); } @@ -8654,14 +8648,7 @@ mod test_typedstream_deserializer { ); let class_name = |idx: usize| match &ts.object_table[idx] { - Archived::Class(class) => { - ts.type_table[class.name_index] - .first() - .and_then(|t| match t { - Type::String(name) => Some(*name), - _ => None, - }) - } + Archived::Class(class) => Some(ts.string_table[class.name_index].text), _ => None, }; let Archived::Object { class, .. } = &ts.object_table[root] else { @@ -8809,8 +8796,7 @@ mod test_typedstream_deserializer { panic!("{fixture}: root class is not a class"); }; assert_eq!( - ts.type_table[class.name_index].first(), - Some(&Type::String("NSValue")), + ts.string_table[class.name_index].text, "NSValue", "{fixture}" ); // Expect the `objCType` string first, followed by the members and @@ -8871,4 +8857,74 @@ mod test_typedstream_deserializer { assert!(slots.iter().all(|&i| ts.shared_string(i) == Some("hello"))); assert_eq!(slots[0], slots[1]); } + + /// Which shared strings carry a descriptor view after a parse: descriptor + /// literals eagerly, class names never, and an `NSNumber`'s `objCType` on + /// the reference that types its payload. + #[test] + fn test_shared_string_views() { + use crate::models::{ + shared_string::SharedString, + types::{Type, TypeEntry}, + }; + let typedstream_path = current_dir() + .unwrap() + .as_path() + .join("src/test_data/AttributedBodyTextOnly"); + let mut file = File::open(typedstream_path).unwrap(); + let mut bytes = vec![]; + file.read_to_end(&mut bytes).unwrap(); + let mut ts = TypedStreamDeserializer::new(&bytes); + ts.oxidize().unwrap(); + + let view = |text: &str| -> Option { + let entry = ts.string_table.iter().find(|e| e.text == text).unwrap(); + entry.parsed().cloned() + }; + use Type::{CString, Object, SignedInt, UnsignedInt, Utf8String}; + assert_eq!(view("@"), Some(TypeEntry::One(Object))); + assert_eq!(view("+"), Some(TypeEntry::One(Utf8String))); + assert_eq!(view("*"), Some(TypeEntry::One(CString))); + assert_eq!( + view("iI"), + Some(TypeEntry::Many(vec![SignedInt, UnsignedInt])) + ); + // `i` was first written as the NSNumber's `char *` objCType, then + // referenced as the descriptor of its value. + assert_eq!(view("i"), Some(TypeEntry::One(SignedInt))); + for name in [ + "NSMutableAttributedString", + "NSString", + "NSDictionary", + "NSNumber", + "NSValue", + ] { + assert_eq!( + view(name), + None, + "{name} is a class name, never a descriptor" + ); + } + + // Equality is on text; a parsed view does not distinguish entries. + assert_eq!(ts.string_table[0], SharedString::new("@")); + assert_eq!( + ts.string_table, + [ + "@", + "NSMutableAttributedString", + "NSAttributedString", + "NSObject", + "NSMutableString", + "NSString", + "+", + "iI", + "NSDictionary", + "i", + "NSNumber", + "NSValue", + "*" + ] + ); + } }