use alloc::string::String; #[cfg(__unicase__iter_cmp)] use core::cmp::Ordering; use core::fmt; use core::hash::{Hash, Hasher}; use core::ops::{Deref, DerefMut}; use core::str::FromStr; #[cfg(not(__unicase__core_and_alloc))] #[allow(deprecated, unused)] use std::ascii::AsciiExt; use super::{Ascii, Encoding, UniCase}; impl Ascii { #[inline] #[cfg(__unicase__const_fns)] pub const fn new(s: S) -> Ascii { Ascii(s) } /// Construct a new `Ascii`. /// /// For Rust versions >= 1.31, this is a `const fn`. #[inline] #[cfg(not(__unicase__const_fns))] pub fn new(s: S) -> Ascii { Ascii(s) } #[cfg(__unicase_const_fns)] pub const fn into_unicase(self) -> UniCase { UniCase(Encoding::Ascii(self)) } #[cfg(not(__unicase_const_fns))] pub fn into_unicase(self) -> UniCase { UniCase(Encoding::Ascii(self)) } #[inline] pub fn into_inner(self) -> S { self.0 } } impl Deref for Ascii { type Target = S; #[inline] fn deref<'a>(&'a self) -> &'a S { &self.0 } } impl DerefMut for Ascii { #[inline] fn deref_mut<'a>(&'a mut self) -> &'a mut S { &mut self.0 } } #[cfg(__unicase__iter_cmp)] impl> PartialOrd for Ascii { #[inline] fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } } #[cfg(__unicase__iter_cmp)] impl> Ord for Ascii { #[inline] fn cmp(&self, other: &Self) -> Ordering { let self_chars = self.as_ref().chars().map(|c| c.to_ascii_lowercase()); let other_chars = other.as_ref().chars().map(|c| c.to_ascii_lowercase()); self_chars.cmp(other_chars) } } impl> AsRef for Ascii { #[inline] fn as_ref(&self) -> &str { self.0.as_ref() } } impl fmt::Display for Ascii { #[inline] fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { fmt::Display::fmt(&self.0, fmt) } } impl> PartialEq> for String { #[inline] fn eq(&self, other: &Ascii) -> bool { other == self } } impl<'a, S1: AsRef> PartialEq> for &'a str { #[inline] fn eq(&self, other: &Ascii) -> bool { other == self } } impl, S2: AsRef> PartialEq for Ascii { #[inline] fn eq(&self, other: &S2) -> bool { self.as_ref().eq_ignore_ascii_case(other.as_ref()) } } impl> Eq for Ascii {} impl FromStr for Ascii { type Err = ::Err; fn from_str(s: &str) -> Result, ::Err> { s.parse().map(Ascii) } } impl> Hash for Ascii { #[inline] fn hash(&self, hasher: &mut H) { for byte in self.as_ref().bytes().map(|b| b.to_ascii_lowercase()) { hasher.write_u8(byte); } } } #[cfg(test)] mod tests { #[cfg(__unicase__default_hasher)] use std::collections::hash_map::DefaultHasher; #[cfg(not(__unicase__default_hasher))] use std::hash::SipHasher as DefaultHasher; use std::hash::{Hash, Hasher}; use Ascii; fn hash(t: &T) -> u64 { let mut s = DefaultHasher::new(); t.hash(&mut s); s.finish() } #[test] fn test_case_insensitive() { let a = Ascii("foobar"); let b = Ascii("FOOBAR"); assert_eq!(a, b); assert_eq!(hash(&a), hash(&b)); assert_eq!(a, "fooBar"); assert_eq!("fooBar", a); assert_eq!(String::from("fooBar"), a); assert_eq!(a, String::from("fooBar")); } #[cfg(feature = "nightly")] #[bench] fn bench_ascii_eq(b: &mut ::test::Bencher) { b.bytes = b"foobar".len() as u64; b.iter(|| assert_eq!(Ascii("foobar"), Ascii("FOOBAR"))); } #[cfg(__unicase__iter_cmp)] #[test] fn test_case_cmp() { assert!(Ascii("foobar") == Ascii("FOOBAR")); assert!(Ascii("a") < Ascii("B")); assert!(Ascii("A") < Ascii("b")); assert!(Ascii("aa") > Ascii("a")); assert!(Ascii("a") < Ascii("aa")); assert!(Ascii("a") < Ascii("AA")); } #[cfg(__unicase__const_fns)] #[test] fn test_ascii_new_const() { const _ASCII: Ascii<&'static str> = Ascii::new(""); } }