1/// A UTF-8-encoded fixed string
2///
3/// **NOTE:** To support dynamic values (i.e. `String`), enable the `string`
4/// feature
5#[derive(Default, Clone, Eq, PartialEq, PartialOrd, Ord, Hash)]
6pub struct Str {
7 name: Inner,
8}
9
10impl Str {
11 #[cfg(feature = "string")]
12 pub(crate) fn from_string(name: std::string::String) -> Self {
13 Self {
14 name: Inner::from_string(name),
15 }
16 }
17
18 #[cfg(feature = "string")]
19 pub(crate) fn from_ref(name: &str) -> Self {
20 Self {
21 name: Inner::from_ref(name),
22 }
23 }
24
25 pub(crate) fn from_static_ref(name: &'static str) -> Self {
26 Self {
27 name: Inner::from_static_ref(name),
28 }
29 }
30
31 pub(crate) fn into_inner(self) -> Inner {
32 self.name
33 }
34
35 /// Get the raw string of the `Str`
36 pub fn as_str(&self) -> &str {
37 self.name.as_str()
38 }
39}
40
41impl From<&'_ Str> for Str {
42 fn from(id: &'_ Str) -> Self {
43 id.clone()
44 }
45}
46
47#[cfg(feature = "string")]
48impl From<std::string::String> for Str {
49 fn from(name: std::string::String) -> Self {
50 Self::from_string(name)
51 }
52}
53
54#[cfg(feature = "string")]
55impl From<&'_ std::string::String> for Str {
56 fn from(name: &'_ std::string::String) -> Self {
57 Self::from_ref(name.as_str())
58 }
59}
60
61impl From<&'static str> for Str {
62 fn from(name: &'static str) -> Self {
63 Self::from_static_ref(name)
64 }
65}
66
67impl From<&'_ &'static str> for Str {
68 fn from(name: &'_ &'static str) -> Self {
69 Self::from_static_ref(name)
70 }
71}
72
73impl From<Str> for String {
74 fn from(name: Str) -> Self {
75 name.name.into_string()
76 }
77}
78
79impl From<Str> for Vec<u8> {
80 fn from(name: Str) -> Self {
81 String::from(name).into()
82 }
83}
84
85impl From<Str> for std::ffi::OsString {
86 fn from(name: Str) -> Self {
87 String::from(name).into()
88 }
89}
90
91impl From<Str> for std::path::PathBuf {
92 fn from(name: Str) -> Self {
93 String::from(name).into()
94 }
95}
96
97impl std::fmt::Display for Str {
98 #[inline]
99 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
100 std::fmt::Display::fmt(self.as_str(), f)
101 }
102}
103
104impl std::fmt::Debug for Str {
105 #[inline]
106 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
107 std::fmt::Debug::fmt(self.as_str(), f)
108 }
109}
110
111impl std::ops::Deref for Str {
112 type Target = str;
113
114 #[inline]
115 fn deref(&self) -> &str {
116 self.as_str()
117 }
118}
119
120impl AsRef<str> for Str {
121 #[inline]
122 fn as_ref(&self) -> &str {
123 self.as_str()
124 }
125}
126
127impl AsRef<[u8]> for Str {
128 #[inline]
129 fn as_ref(&self) -> &[u8] {
130 self.as_bytes()
131 }
132}
133
134impl AsRef<std::ffi::OsStr> for Str {
135 #[inline]
136 fn as_ref(&self) -> &std::ffi::OsStr {
137 (**self).as_ref()
138 }
139}
140
141impl AsRef<std::path::Path> for Str {
142 #[inline]
143 fn as_ref(&self) -> &std::path::Path {
144 std::path::Path::new(self)
145 }
146}
147
148impl std::borrow::Borrow<str> for Str {
149 #[inline]
150 fn borrow(&self) -> &str {
151 self.as_str()
152 }
153}
154
155impl PartialEq<str> for Str {
156 #[inline]
157 fn eq(&self, other: &str) -> bool {
158 PartialEq::eq(self.as_str(), other)
159 }
160}
161impl PartialEq<Str> for str {
162 #[inline]
163 fn eq(&self, other: &Str) -> bool {
164 PartialEq::eq(self, other.as_str())
165 }
166}
167
168impl PartialEq<&'_ str> for Str {
169 #[inline]
170 fn eq(&self, other: &&str) -> bool {
171 PartialEq::eq(self.as_str(), *other)
172 }
173}
174impl PartialEq<Str> for &'_ str {
175 #[inline]
176 fn eq(&self, other: &Str) -> bool {
177 PartialEq::eq(*self, other.as_str())
178 }
179}
180
181impl PartialEq<std::ffi::OsStr> for Str {
182 #[inline]
183 fn eq(&self, other: &std::ffi::OsStr) -> bool {
184 PartialEq::eq(self.as_str(), other)
185 }
186}
187impl PartialEq<Str> for std::ffi::OsStr {
188 #[inline]
189 fn eq(&self, other: &Str) -> bool {
190 PartialEq::eq(self, other.as_str())
191 }
192}
193
194impl PartialEq<&'_ std::ffi::OsStr> for Str {
195 #[inline]
196 fn eq(&self, other: &&std::ffi::OsStr) -> bool {
197 PartialEq::eq(self.as_str(), *other)
198 }
199}
200impl PartialEq<Str> for &'_ std::ffi::OsStr {
201 #[inline]
202 fn eq(&self, other: &Str) -> bool {
203 PartialEq::eq(*self, other.as_str())
204 }
205}
206
207impl PartialEq<std::string::String> for Str {
208 #[inline]
209 fn eq(&self, other: &std::string::String) -> bool {
210 PartialEq::eq(self.as_str(), other.as_str())
211 }
212}
213impl PartialEq<Str> for std::string::String {
214 #[inline]
215 fn eq(&self, other: &Str) -> bool {
216 PartialEq::eq(self.as_str(), other.as_str())
217 }
218}
219
220#[cfg(feature = "string")]
221pub(crate) mod inner {
222 #[derive(Clone)]
223 pub(crate) enum Inner {
224 Static(&'static str),
225 Owned(Box<str>),
226 }
227
228 impl Inner {
229 pub(crate) fn from_string(name: std::string::String) -> Self {
230 Self::Owned(name.into_boxed_str())
231 }
232
233 pub(crate) fn from_ref(name: &str) -> Self {
234 Self::Owned(Box::from(name))
235 }
236
237 pub(crate) fn from_static_ref(name: &'static str) -> Self {
238 Self::Static(name)
239 }
240
241 pub(crate) fn as_str(&self) -> &str {
242 match self {
243 Self::Static(s) => s,
244 Self::Owned(s) => s.as_ref(),
245 }
246 }
247
248 pub(crate) fn into_string(self) -> String {
249 match self {
250 Self::Static(s) => s.to_owned(),
251 Self::Owned(s) => s.into(),
252 }
253 }
254 }
255}
256
257#[cfg(not(feature = "string"))]
258pub(crate) mod inner {
259 #[derive(Clone)]
260 pub(crate) struct Inner(pub(crate) &'static str);
261
262 impl Inner {
263 pub(crate) fn from_static_ref(name: &'static str) -> Self {
264 Self(name)
265 }
266
267 pub(crate) fn as_str(&self) -> &str {
268 self.0
269 }
270
271 pub(crate) fn into_string(self) -> String {
272 self.as_str().to_owned()
273 }
274 }
275}
276
277pub(crate) use inner::Inner;
278
279impl Default for Inner {
280 fn default() -> Self {
281 Self::from_static_ref("")
282 }
283}
284
285impl PartialEq for Inner {
286 fn eq(&self, other: &Inner) -> bool {
287 self.as_str() == other.as_str()
288 }
289}
290
291impl PartialOrd for Inner {
292 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
293 Some(self.cmp(other))
294 }
295}
296
297impl Ord for Inner {
298 fn cmp(&self, other: &Inner) -> std::cmp::Ordering {
299 self.as_str().cmp(other.as_str())
300 }
301}
302
303impl Eq for Inner {}
304
305impl std::hash::Hash for Inner {
306 #[inline]
307 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
308 self.as_str().hash(state);
309 }
310}
311