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