1
#[cfg(feature = "alloc")]
2
use alloc::string::String;
3
use core::borrow::Borrow;
4
use core::hash::Hash;
5
use core::ops::Deref;
6

            
7
/// A string that can be either Owned or Borrowed.
8
///
9
/// This type is similar to the standard library's Cow, but the `Owned` variant
10
/// is only available when the `alloc` or `std` features are enabled.
11
39
#[derive(Debug, Clone)]
12
pub enum AnyStr<'a> {
13
    /// An owned String.
14
    #[cfg(feature = "alloc")]
15
    Owned(String),
16
    /// A borrowed string slice.
17
    Borrowed(&'a str),
18
}
19

            
20
impl<'a> AnyStr<'a> {
21
    /// Returns this string as a `str` reference.
22
    ///
23
    /// This function in general doesn't need to be called, as `AnyStr`
24
    /// implements `AsRef<str>`, `Borrow<str>`, and `Deref<Target = str>`. This
25
    /// allows it to act as if it were a `&str` in most situations.
26
    #[inline]
27
    #[must_use]
28
767
    pub fn as_str(&self) -> &str {
29
767
        match self {
30
            #[cfg(feature = "alloc")]
31
14
            Self::Owned(str) => str,
32
753
            Self::Borrowed(str) => str,
33
        }
34
767
    }
35
}
36

            
37
impl<'a> AsRef<str> for AnyStr<'a> {
38
    #[inline]
39
767
    fn as_ref(&self) -> &str {
40
767
        self.as_str()
41
767
    }
42
}
43

            
44
impl<'a> Borrow<str> for AnyStr<'a> {
45
    #[inline]
46
1
    fn borrow(&self) -> &str {
47
1
        self.as_ref()
48
1
    }
49
}
50

            
51
impl<'a> Eq for AnyStr<'a> {}
52

            
53
impl<'a, 'b> PartialEq<AnyStr<'b>> for AnyStr<'a> {
54
    #[inline]
55
56
    fn eq(&self, other: &AnyStr<'b>) -> bool {
56
56
        self.as_ref() == other.as_ref()
57
56
    }
58
}
59

            
60
impl<'a, 'b> PartialEq<&'b str> for AnyStr<'a> {
61
    #[inline]
62
6
    fn eq(&self, other: &&'b str) -> bool {
63
6
        self == *other
64
6
    }
65
}
66

            
67
impl<'a> PartialEq<str> for AnyStr<'a> {
68
    #[inline]
69
37
    fn eq(&self, other: &str) -> bool {
70
37
        self.as_ref() == other
71
37
    }
72
}
73

            
74
impl<'a, 'b> PartialOrd<AnyStr<'b>> for AnyStr<'a> {
75
    #[inline]
76
1
    fn partial_cmp(&self, other: &AnyStr<'b>) -> Option<core::cmp::Ordering> {
77
1
        self.partial_cmp(other.as_ref())
78
1
    }
79
}
80

            
81
impl<'a, 'b> PartialOrd<&'b str> for AnyStr<'a> {
82
    #[inline]
83
1
    fn partial_cmp(&self, other: &&'b str) -> Option<core::cmp::Ordering> {
84
1
        self.partial_cmp(*other)
85
1
    }
86
}
87
impl<'a> PartialOrd<str> for AnyStr<'a> {
88
    #[inline]
89
2
    fn partial_cmp(&self, other: &str) -> Option<core::cmp::Ordering> {
90
2
        self.as_ref().partial_cmp(other)
91
2
    }
92
}
93

            
94
impl<'a> Deref for AnyStr<'a> {
95
    type Target = str;
96

            
97
    #[inline]
98
234
    fn deref(&self) -> &Self::Target {
99
234
        self.as_ref()
100
234
    }
101
}
102

            
103
impl<'a> Hash for AnyStr<'a> {
104
    #[inline]
105
4
    fn hash<H: core::hash::Hasher>(&self, state: &mut H) {
106
4
        self.as_ref().hash(state);
107
4
    }
108
}
109

            
110
impl<'a> From<&'a str> for AnyStr<'a> {
111
    #[inline]
112
1
    fn from(value: &'a str) -> Self {
113
1
        Self::Borrowed(value)
114
1
    }
115
}
116

            
117
#[cfg(feature = "alloc")]
118
impl<'a> From<String> for AnyStr<'a> {
119
    #[inline]
120
1
    fn from(value: String) -> Self {
121
1
        Self::Owned(value)
122
1
    }
123
}
124

            
125
1
#[test]
126
#[cfg(feature = "std")]
127
1
fn hash() {
128
1
    let mut set = std::collections::HashSet::new();
129
1
    set.insert(AnyStr::from(String::from("hello")));
130
1
    assert!(set.contains(&AnyStr::from("hello")));
131
1
    assert!(set.contains("hello"));
132
1
}
133

            
134
1
#[test]
135
1
fn ord() {
136
1
    assert!(AnyStr::Borrowed("a") < "b");
137
1
    assert!(AnyStr::Borrowed("a") < AnyStr::Borrowed("b"));
138
1
}