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][crate::_features]
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        self.as_os_str().partial_cmp(other.as_os_str())
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