1use std::{2 borrow::Cow,3 cell::RefCell,4 convert::TryFrom,5 fmt::{self, Display},6 hash::{BuildHasherDefault, Hash, Hasher},7 ops::Deref,8 rc::Rc,9 str::Utf8Error,10};1112use gcmodule::Trace;13use rustc_hash::FxHashMap;14use serde::{Deserialize, Serialize};1516#[derive(Clone, PartialOrd, Ord, Eq)]17pub struct IStr(Rc<str>);18impl Trace for IStr {19 fn is_type_tracked() -> bool {20 false21 }22}2324impl Deref for IStr {25 type Target = str;2627 fn deref(&self) -> &Self::Target {28 &self.029 }30}3132impl PartialEq for IStr {33 fn eq(&self, other: &Self) -> bool {34 35 Rc::ptr_eq(&self.0, &other.0)36 }37}3839impl PartialEq<str> for IStr {40 fn eq(&self, other: &str) -> bool {41 &self.0 as &str == other42 }43}4445impl Hash for IStr {46 fn hash<H: Hasher>(&self, state: &mut H) {47 state.write_usize(Rc::as_ptr(&self.0) as *const () as usize)48 }49}5051impl Drop for IStr {52 fn drop(&mut self) {53 54 if Rc::strong_count(&self.0) <= 2 {55 let _result = STR_POOL.try_with(|pool| pool.borrow_mut().remove(&self.0));56 }57 }58}5960impl fmt::Debug for IStr {61 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {62 write!(f, "{:?}", &self.0)63 }64}6566impl Display for IStr {67 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {68 f.write_str(&self.0)69 }70}7172thread_local! {73 static STR_POOL: RefCell<FxHashMap<Rc<str>, ()>> = RefCell::new(FxHashMap::with_capacity_and_hasher(200, BuildHasherDefault::default()));74}7576impl From<&str> for IStr {77 fn from(str: &str) -> Self {78 IStr(STR_POOL.with(|pool| {79 let mut pool = pool.borrow_mut();80 if let Some((k, _)) = pool.get_key_value(str) {81 k.clone()82 } else {83 let rc: Rc<str> = str.into();84 pool.insert(rc.clone(), ());85 rc86 }87 }))88 }89}9091impl TryFrom<&[u8]> for IStr {92 type Error = Utf8Error;9394 fn try_from(value: &[u8]) -> Result<Self, Self::Error> {95 let str = std::str::from_utf8(value)?;96 Ok(str.into())97 }98}99100impl From<String> for IStr {101 fn from(str: String) -> Self {102 (&str as &str).into()103 }104}105106impl<'i> From<Cow<'i, str>> for IStr {107 fn from(c: Cow<'i, str>) -> Self {108 (&c as &str).into()109 }110}111112impl Serialize for IStr {113 fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>114 where115 S: serde::Serializer,116 {117 (&self.0 as &str).serialize(serializer)118 }119}120121impl<'de> Deserialize<'de> for IStr {122 fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>123 where124 D: serde::Deserializer<'de>,125 {126 let s = <&str>::deserialize(deserializer)?;127 Ok(s.into())128 }129}