1 use alloc::string::String; 2 #[cfg(__unicase__iter_cmp)] 3 use core::cmp::Ordering; 4 use core::fmt; 5 use core::hash::{Hash, Hasher}; 6 use core::ops::{Deref, DerefMut}; 7 use core::str::FromStr; 8 #[cfg(not(__unicase__core_and_alloc))] 9 #[allow(deprecated, unused)] 10 use std::ascii::AsciiExt; 11 12 use super::{Ascii, Encoding, UniCase}; 13 14 impl<S> Ascii<S> { 15 #[inline] 16 #[cfg(__unicase__const_fns)] 17 pub const fn new(s: S) -> Ascii<S> { 18 Ascii(s) 19 } 20 21 /// Construct a new `Ascii`. 22 /// 23 /// For Rust versions >= 1.31, this is a `const fn`. 24 #[inline] 25 #[cfg(not(__unicase__const_fns))] 26 pub fn new(s: S) -> Ascii<S> { 27 Ascii(s) 28 } 29 30 #[cfg(__unicase_const_fns)] 31 pub const fn into_unicase(self) -> UniCase<S> { 32 UniCase(Encoding::Ascii(self)) 33 } 34 35 #[cfg(not(__unicase_const_fns))] 36 pub fn into_unicase(self) -> UniCase<S> { 37 UniCase(Encoding::Ascii(self)) 38 } 39 40 #[inline] 41 pub fn into_inner(self) -> S { 42 self.0 43 } 44 } 45 46 impl<S> Deref for Ascii<S> { 47 type Target = S; 48 #[inline] 49 fn deref<'a>(&'a self) -> &'a S { 50 &self.0 51 } 52 } 53 54 impl<S> DerefMut for Ascii<S> { FT_SUPERDOC_cmp(void * cmp_arg,FT_SUPERDOC * p1,FT_SUPERDOC * p2)55 #[inline] 56 fn deref_mut<'a>(&'a mut self) -> &'a mut S { 57 &mut self.0 58 } 59 } 60 61 #[cfg(__unicase__iter_cmp)] 62 impl<T: AsRef<str>> PartialOrd for Ascii<T> { 63 #[inline] 64 fn partial_cmp(&self, other: &Self) -> Option<Ordering> { walk_and_match(FT_WORD * word,uint32 count,ALL_IN_ONE * aio)65 Some(self.cmp(other)) 66 } 67 } 68 69 #[cfg(__unicase__iter_cmp)] 70 impl<T: AsRef<str>> Ord for Ascii<T> { 71 #[inline] 72 fn cmp(&self, other: &Self) -> Ordering { 73 let self_chars = self.as_ref().chars().map(|c| c.to_ascii_lowercase()); 74 let other_chars = other.as_ref().chars().map(|c| c.to_ascii_lowercase()); 75 self_chars.cmp(other_chars) 76 } 77 } 78 79 impl<S: AsRef<str>> AsRef<str> for Ascii<S> { 80 #[inline] 81 fn as_ref(&self) -> &str { 82 self.0.as_ref() 83 } 84 85 } 86 87 impl<S: fmt::Display> fmt::Display for Ascii<S> { 88 #[inline] 89 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { 90 fmt::Display::fmt(&self.0, fmt) 91 } 92 } 93 94 impl<S1: AsRef<str>> PartialEq<Ascii<S1>> for String { 95 #[inline] 96 fn eq(&self, other: &Ascii<S1>) -> bool { 97 other == self 98 } 99 } 100 101 impl<'a, S1: AsRef<str>> PartialEq<Ascii<S1>> for &'a str { 102 #[inline] 103 fn eq(&self, other: &Ascii<S1>) -> bool { 104 other == self 105 } 106 } 107 108 impl<S1: AsRef<str>, S2: AsRef<str>> PartialEq<S2> for Ascii<S1> { 109 #[inline] 110 fn eq(&self, other: &S2) -> bool { 111 self.as_ref().eq_ignore_ascii_case(other.as_ref()) 112 } 113 } 114 115 impl<S: AsRef<str>> Eq for Ascii<S> {} 116 117 impl<S: FromStr> FromStr for Ascii<S> { 118 type Err = <S as FromStr>::Err; 119 fn from_str(s: &str) -> Result<Ascii<S>, <S as FromStr>::Err> { 120 s.parse().map(Ascii) 121 } 122 } 123 124 impl<S: AsRef<str>> Hash for Ascii<S> { 125 #[inline] 126 fn hash<H: Hasher>(&self, hasher: &mut H) { 127 for byte in self.as_ref().bytes().map(|b| b.to_ascii_lowercase()) { 128 hasher.write_u8(byte); 129 } 130 } 131 } 132 133 #[cfg(test)] 134 mod tests { 135 use ::Ascii; 136 use std::hash::{Hash, Hasher}; 137 #[cfg(not(__unicase__default_hasher))] 138 use std::hash::SipHasher as DefaultHasher; 139 #[cfg(__unicase__default_hasher)] 140 use std::collections::hash_map::DefaultHasher; 141 142 fn hash<T: Hash>(t: &T) -> u64 { 143 let mut s = DefaultHasher::new(); 144 t.hash(&mut s); 145 s.finish() 146 } 147 148 #[test] 149 fn test_case_insensitive() { 150 let a = Ascii("foobar"); 151 let b = Ascii("FOOBAR"); 152 153 assert_eq!(a, b); 154 assert_eq!(hash(&a), hash(&b)); 155 156 assert_eq!(a, "fooBar"); 157 assert_eq!("fooBar", a); 158 assert_eq!(String::from("fooBar"), a); 159 assert_eq!(a, String::from("fooBar")); 160 } 161 162 #[cfg(feature = "nightly")] 163 #[bench] 164 fn bench_ascii_eq(b: &mut ::test::Bencher) { 165 b.bytes = b"foobar".len() as u64; 166 b.iter(|| assert_eq!(Ascii("foobar"), Ascii("FOOBAR"))); 167 } 168 169 #[cfg(__unicase__iter_cmp)] 170 #[test] 171 fn test_case_cmp() { 172 assert!(Ascii("foobar") == Ascii("FOOBAR")); 173 assert!(Ascii("a") < Ascii("B")); 174 175 assert!(Ascii("A") < Ascii("b")); 176 assert!(Ascii("aa") > Ascii("a")); 177 178 assert!(Ascii("a") < Ascii("aa")); 179 assert!(Ascii("a") < Ascii("AA")); 180 } 181 182 #[cfg(__unicase__const_fns)] 183 #[test] 184 fn test_ascii_new_const() { 185 const _ASCII: Ascii<&'static str> = Ascii::new(""); 186 } 187 } 188