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