use crate::{
error::Result,
models::types::{Type, TypeEntry},
};
#[derive(Clone)]
pub struct SharedString<'a> {
pub text: &'a str,
parsed: Option<TypeEntry>,
}
impl<'a> SharedString<'a> {
#[must_use]
pub const fn new(text: &'a str) -> Self {
Self { text, parsed: None }
}
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"))
}
#[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<str> 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};
#[test]
fn shared_string_is_send_and_sync() {
fn assert_send_sync<T: Send + Sync>() {}
assert_send_sync::<SharedString<'static>>();
}
#[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"));
let mut name = SharedString::new("NSString");
assert!(name.descriptor(8).is_err());
assert_eq!(name.parsed(), None);
}
}