use std::borrow::Borrow; use std::fmt; use std::hash::{Hash, Hasher}; use std::ops::{Add, Deref}; use crate::Str; pub type ArcStr = std::sync::Arc; /// Used to hold an immutable string. /// /// It can construct as a const (by AtomicStr::ever). #[derive(Debug, Clone, Eq)] pub enum AtomicStr { Arc(ArcStr), Static(&'static str), } // unsafe impl Sync for AtomicStr {} impl PartialEq for AtomicStr { #[inline] fn eq(&self, other: &AtomicStr) -> bool { self[..] == other[..] } } impl Add<&str> for AtomicStr { type Output = AtomicStr; #[inline] fn add(self, other: &str) -> AtomicStr { AtomicStr::from(&format!("{self}{other}")) } } impl Hash for AtomicStr { fn hash(&self, state: &mut H) { match self { AtomicStr::Arc(s) => (s[..]).hash(state), AtomicStr::Static(s) => s.hash(state), } } } impl fmt::Display for AtomicStr { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match self { AtomicStr::Arc(s) => write!(f, "{s}"), AtomicStr::Static(s) => write!(f, "{s}"), } } } // &'static str -> &strになってしまわないように // あえて`impl> From for AtomicStr { ... }`はしない impl From<&'static str> for AtomicStr { #[inline] fn from(s: &'static str) -> Self { AtomicStr::ever(s) } } impl From<&String> for AtomicStr { #[inline] fn from(s: &String) -> Self { AtomicStr::Arc((s[..]).into()) } } impl From for AtomicStr { #[inline] fn from(s: String) -> Self { AtomicStr::Arc((s[..]).into()) } } impl From<&ArcStr> for AtomicStr { #[inline] fn from(s: &ArcStr) -> Self { AtomicStr::Arc(s.clone()) } } impl From for AtomicStr { #[inline] fn from(s: ArcStr) -> Self { AtomicStr::Arc(s) } } impl From<&AtomicStr> for AtomicStr { #[inline] fn from(s: &AtomicStr) -> Self { match s { AtomicStr::Arc(s) => AtomicStr::Arc(s.clone()), AtomicStr::Static(s) => AtomicStr::Static(s), } } } impl From for AtomicStr { #[inline] fn from(s: Str) -> Self { match s { Str::Rc(s) => AtomicStr::Arc((&s[..]).into()), Str::Static(s) => AtomicStr::Static(s), } } } impl From<&Str> for AtomicStr { #[inline] fn from(s: &Str) -> Self { match s { Str::Rc(s) => AtomicStr::Arc((&s[..]).into()), Str::Static(s) => AtomicStr::Static(s), } } } impl Deref for AtomicStr { type Target = str; fn deref(&self) -> &Self::Target { self.borrow() } } impl Borrow for AtomicStr { #[inline] fn borrow(&self) -> &str { match self { AtomicStr::Arc(s) => s.borrow(), AtomicStr::Static(s) => s, } } } impl AsRef for AtomicStr { fn as_ref(&self) -> &str { self.borrow() } } impl AtomicStr { pub const fn ever(s: &'static str) -> Self { AtomicStr::Static(s) } pub fn arc(s: &str) -> Self { AtomicStr::Arc(s.into()) } pub fn into_rc(self) -> ArcStr { match self { AtomicStr::Arc(s) => s, AtomicStr::Static(s) => ArcStr::from(s), } } pub fn is_uppercase(&self) -> bool { self.chars() .next() .map(|c| c.is_uppercase()) .unwrap_or(false) } }