unicase/
ascii.rs

1use alloc::string::String;
2#[cfg(__unicase__iter_cmp)]
3use core::cmp::Ordering;
4use core::fmt;
5use core::hash::{Hash, Hasher};
6use core::ops::{Deref, DerefMut};
7use core::str::FromStr;
8#[cfg(not(__unicase__core_and_alloc))]
9#[allow(deprecated, unused)]
10use std::ascii::AsciiExt;
11
12use super::{Ascii, Encoding, UniCase};
13
14impl<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
46impl<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
54impl<S> DerefMut for Ascii<S> {
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)]
62impl<T: AsRef<str>> PartialOrd for Ascii<T> {
63    #[inline]
64    fn partial_cmp(&self, other: &Self) -> Option<Ordering> {
65        Some(self.cmp(other))
66    }
67}
68
69#[cfg(__unicase__iter_cmp)]
70impl<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
79impl<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
87impl<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
94impl<S1: AsRef<str>> PartialEq<Ascii<S1>> for String {
95    #[inline]
96    fn eq(&self, other: &Ascii<S1>) -> bool {
97        other == self
98    }
99}
100
101impl<'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
108impl<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
115impl<S: AsRef<str>> Eq for Ascii<S> {}
116
117impl<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
124impl<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)]
134mod 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}