Something went wrong. Try again.
we (web engine): Experimental web browser project to understand the limits of Claude
Something went wrong. Try again.
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274//! Small-string optimization: inline storage for strings up to 22 bytes.//!//! `CompactString` avoids heap allocation for short strings (class names, IDs,//! short attribute values). Strings longer than 22 bytes fall back to a regular//! `String`. The enum representation is safe Rust (no `unsafe`).
use std::fmt;use std::hash::{Hash, Hasher};
/// Maximum number of bytes that can be stored inline.const INLINE_CAP: usize = 22;
/// A string that stores short values inline (up to 22 bytes) and falls back/// to heap allocation for longer strings.#[derive(Clone)]pub enum CompactString { /// Strings up to 22 bytes stored inline (no heap allocation). Inline { len: u8, data: [u8; INLINE_CAP] }, /// Longer strings stored on the heap. Heap(String),}
impl CompactString { /// Create a new `CompactString` from a `&str`. pub fn new(s: &str) -> Self { if s.len() <= INLINE_CAP { let mut data = [0u8; INLINE_CAP]; data[..s.len()].copy_from_slice(s.as_bytes()); CompactString::Inline { len: s.len() as u8, data, } } else { CompactString::Heap(s.to_string()) } }
/// Borrow the string contents as a `&str`. pub fn as_str(&self) -> &str { match self { CompactString::Inline { len, data } => { let bytes = &data[..*len as usize]; // Safety: we only ever store valid UTF-8 (from &str input). // This is guaranteed by construction — new() only accepts &str. std::str::from_utf8(bytes).expect("CompactString: invalid UTF-8") } CompactString::Heap(s) => s.as_str(), } }
/// Returns true if the string is stored inline. pub fn is_inline(&self) -> bool { matches!(self, CompactString::Inline { .. }) }
/// Length in bytes. pub fn len(&self) -> usize { match self { CompactString::Inline { len, .. } => *len as usize, CompactString::Heap(s) => s.len(), } }
/// Returns true if the string is empty. pub fn is_empty(&self) -> bool { self.len() == 0 }
/// Estimated heap bytes used (0 for inline strings). pub fn heap_bytes(&self) -> usize { match self { CompactString::Inline { .. } => 0, CompactString::Heap(s) => s.capacity(), } }}
impl Default for CompactString { fn default() -> Self { CompactString::Inline { len: 0, data: [0; INLINE_CAP], } }}
impl From<&str> for CompactString { fn from(s: &str) -> Self { CompactString::new(s) }}
impl From<String> for CompactString { fn from(s: String) -> Self { if s.len() <= INLINE_CAP { CompactString::new(&s) } else { CompactString::Heap(s) } }}
impl AsRef<str> for CompactString { fn as_ref(&self) -> &str { self.as_str() }}
impl std::ops::Deref for CompactString { type Target = str; fn deref(&self) -> &str { self.as_str() }}
impl fmt::Debug for CompactString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { fmt::Debug::fmt(self.as_str(), f) }}
impl fmt::Display for CompactString { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str(self.as_str()) }}
impl PartialEq for CompactString { fn eq(&self, other: &Self) -> bool { self.as_str() == other.as_str() }}
impl Eq for CompactString {}
impl PartialEq<str> for CompactString { fn eq(&self, other: &str) -> bool { self.as_str() == other }}
impl PartialEq<&str> for CompactString { fn eq(&self, other: &&str) -> bool { self.as_str() == *other }}
impl PartialEq<String> for CompactString { fn eq(&self, other: &String) -> bool { self.as_str() == other.as_str() }}
impl PartialOrd for CompactString { fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> { Some(self.cmp(other)) }}
impl Ord for CompactString { fn cmp(&self, other: &Self) -> std::cmp::Ordering { self.as_str().cmp(other.as_str()) }}
impl Hash for CompactString { fn hash<H: Hasher>(&self, state: &mut H) { self.as_str().hash(state); }}
#[cfg(test)]mod tests { use super::*;
#[test] fn short_string_is_inline() { let s = CompactString::new("div"); assert!(s.is_inline()); assert_eq!(s.as_str(), "div"); assert_eq!(s.len(), 3); assert_eq!(s.heap_bytes(), 0); }
#[test] fn exactly_22_bytes_is_inline() { let s = CompactString::new("abcdefghijklmnopqrstuv"); // 22 chars assert!(s.is_inline()); assert_eq!(s.as_str(), "abcdefghijklmnopqrstuv"); }
#[test] fn long_string_is_heap() { let s = CompactString::new("abcdefghijklmnopqrstuvw"); // 23 chars assert!(!s.is_inline()); assert_eq!(s.as_str(), "abcdefghijklmnopqrstuvw"); assert!(s.heap_bytes() > 0); }
#[test] fn empty_string() { let s = CompactString::new(""); assert!(s.is_inline()); assert!(s.is_empty()); assert_eq!(s.len(), 0); }
#[test] fn equality() { let a = CompactString::new("hello"); let b = CompactString::new("hello"); let c = CompactString::new("world"); assert_eq!(a, b); assert_ne!(a, c); assert_eq!(a, "hello"); }
#[test] fn from_string() { let s = CompactString::from("short".to_string()); assert!(s.is_inline());
let long = "a".repeat(30); let s = CompactString::from(long.clone()); assert!(!s.is_inline()); assert_eq!(s.as_str(), long); }
#[test] fn clone_preserves_variant() { let a = CompactString::new("inline"); let b = a.clone(); assert!(b.is_inline()); assert_eq!(a, b); }
#[test] fn display_and_debug() { let s = CompactString::new("test"); assert_eq!(format!("{s}"), "test"); assert_eq!(format!("{s:?}"), "\"test\""); }
#[test] fn default_is_empty() { let s = CompactString::default(); assert!(s.is_empty()); assert!(s.is_inline()); }
#[test] fn hash_matches_str() { use std::collections::hash_map::DefaultHasher;
let text = "hello"; let cs = CompactString::new(text);
let mut h1 = DefaultHasher::new(); cs.hash(&mut h1);
let mut h2 = DefaultHasher::new(); text.hash(&mut h2);
assert_eq!(h1.finish(), h2.finish()); }
#[test] fn deref_to_str() { let s = CompactString::new("slice me"); assert!(s.starts_with("slice")); assert!(s.ends_with("me")); }}