1 use 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)]
8 pub struct OsStr {
9     name: Inner,
10 }
11 
12 impl OsStr {
13     #[cfg(feature = "string")]
from_string(name: std::ffi::OsString) -> Self14     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")]
from_ref(name: &std::ffi::OsStr) -> Self21     pub(crate) fn from_ref(name: &std::ffi::OsStr) -> Self {
22         Self {
23             name: Inner::from_ref(name),
24         }
25     }
26 
from_static_ref(name: &'static std::ffi::OsStr) -> Self27     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`
as_os_str(&self) -> &std::ffi::OsStr34     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`
to_os_string(&self) -> std::ffi::OsString39     pub fn to_os_string(&self) -> std::ffi::OsString {
40         self.as_os_str().to_owned()
41     }
42 }
43 
44 impl From<&'_ OsStr> for OsStr {
from(id: &'_ OsStr) -> Self45     fn from(id: &'_ OsStr) -> Self {
46         id.clone()
47     }
48 }
49 
50 #[cfg(feature = "string")]
51 impl From<Str> for OsStr {
from(id: Str) -> Self52     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"))]
61 impl From<Str> for OsStr {
from(id: Str) -> Self62     fn from(id: Str) -> Self {
63         Self::from_static_ref(std::ffi::OsStr::new(id.into_inner().0))
64     }
65 }
66 
67 impl From<&'_ Str> for OsStr {
from(id: &'_ Str) -> Self68     fn from(id: &'_ Str) -> Self {
69         id.clone().into()
70     }
71 }
72 
73 #[cfg(feature = "string")]
74 impl From<std::ffi::OsString> for OsStr {
from(name: std::ffi::OsString) -> Self75     fn from(name: std::ffi::OsString) -> Self {
76         Self::from_string(name)
77     }
78 }
79 
80 #[cfg(feature = "string")]
81 impl From<&'_ std::ffi::OsString> for OsStr {
from(name: &'_ std::ffi::OsString) -> Self82     fn from(name: &'_ std::ffi::OsString) -> Self {
83         Self::from_ref(name.as_os_str())
84     }
85 }
86 
87 #[cfg(feature = "string")]
88 impl From<std::string::String> for OsStr {
from(name: std::string::String) -> Self89     fn from(name: std::string::String) -> Self {
90         Self::from_string(name.into())
91     }
92 }
93 
94 #[cfg(feature = "string")]
95 impl From<&'_ std::string::String> for OsStr {
from(name: &'_ std::string::String) -> Self96     fn from(name: &'_ std::string::String) -> Self {
97         Self::from_ref(name.as_str().as_ref())
98     }
99 }
100 
101 impl From<&'static std::ffi::OsStr> for OsStr {
from(name: &'static std::ffi::OsStr) -> Self102     fn from(name: &'static std::ffi::OsStr) -> Self {
103         Self::from_static_ref(name)
104     }
105 }
106 
107 impl From<&'_ &'static std::ffi::OsStr> for OsStr {
from(name: &'_ &'static std::ffi::OsStr) -> Self108     fn from(name: &'_ &'static std::ffi::OsStr) -> Self {
109         Self::from_static_ref(name)
110     }
111 }
112 
113 impl From<&'static str> for OsStr {
from(name: &'static str) -> Self114     fn from(name: &'static str) -> Self {
115         Self::from_static_ref(name.as_ref())
116     }
117 }
118 
119 impl From<&'_ &'static str> for OsStr {
from(name: &'_ &'static str) -> Self120     fn from(name: &'_ &'static str) -> Self {
121         Self::from_static_ref((*name).as_ref())
122     }
123 }
124 
125 impl From<OsStr> for std::ffi::OsString {
from(name: OsStr) -> Self126     fn from(name: OsStr) -> Self {
127         name.name.into_os_string()
128     }
129 }
130 
131 impl From<OsStr> for std::path::PathBuf {
from(name: OsStr) -> Self132     fn from(name: OsStr) -> Self {
133         std::ffi::OsString::from(name).into()
134     }
135 }
136 
137 impl std::fmt::Debug for OsStr {
138     #[inline]
fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result139     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
140         std::fmt::Debug::fmt(self.as_os_str(), f)
141     }
142 }
143 
144 impl std::ops::Deref for OsStr {
145     type Target = std::ffi::OsStr;
146 
147     #[inline]
deref(&self) -> &std::ffi::OsStr148     fn deref(&self) -> &std::ffi::OsStr {
149         self.as_os_str()
150     }
151 }
152 
153 impl AsRef<std::ffi::OsStr> for OsStr {
154     #[inline]
as_ref(&self) -> &std::ffi::OsStr155     fn as_ref(&self) -> &std::ffi::OsStr {
156         self.as_os_str()
157     }
158 }
159 
160 impl AsRef<std::path::Path> for OsStr {
161     #[inline]
as_ref(&self) -> &std::path::Path162     fn as_ref(&self) -> &std::path::Path {
163         std::path::Path::new(self)
164     }
165 }
166 
167 impl std::borrow::Borrow<std::ffi::OsStr> for OsStr {
168     #[inline]
borrow(&self) -> &std::ffi::OsStr169     fn borrow(&self) -> &std::ffi::OsStr {
170         self.as_os_str()
171     }
172 }
173 
174 impl PartialEq<str> for OsStr {
175     #[inline]
eq(&self, other: &str) -> bool176     fn eq(&self, other: &str) -> bool {
177         PartialEq::eq(self.as_os_str(), other)
178     }
179 }
180 impl PartialEq<OsStr> for str {
181     #[inline]
eq(&self, other: &OsStr) -> bool182     fn eq(&self, other: &OsStr) -> bool {
183         PartialEq::eq(self, other.as_os_str())
184     }
185 }
186 
187 impl PartialEq<&'_ str> for OsStr {
188     #[inline]
eq(&self, other: &&str) -> bool189     fn eq(&self, other: &&str) -> bool {
190         PartialEq::eq(self.as_os_str(), *other)
191     }
192 }
193 impl PartialEq<OsStr> for &'_ str {
194     #[inline]
eq(&self, other: &OsStr) -> bool195     fn eq(&self, other: &OsStr) -> bool {
196         PartialEq::eq(*self, other.as_os_str())
197     }
198 }
199 
200 impl PartialEq<&'_ std::ffi::OsStr> for OsStr {
201     #[inline]
eq(&self, other: &&std::ffi::OsStr) -> bool202     fn eq(&self, other: &&std::ffi::OsStr) -> bool {
203         PartialEq::eq(self.as_os_str(), *other)
204     }
205 }
206 impl PartialEq<OsStr> for &'_ std::ffi::OsStr {
207     #[inline]
eq(&self, other: &OsStr) -> bool208     fn eq(&self, other: &OsStr) -> bool {
209         PartialEq::eq(*self, other.as_os_str())
210     }
211 }
212 
213 impl PartialEq<std::string::String> for OsStr {
214     #[inline]
eq(&self, other: &std::string::String) -> bool215     fn eq(&self, other: &std::string::String) -> bool {
216         PartialEq::eq(self.as_os_str(), other.as_str())
217     }
218 }
219 impl PartialEq<OsStr> for std::string::String {
220     #[inline]
eq(&self, other: &OsStr) -> bool221     fn eq(&self, other: &OsStr) -> bool {
222         PartialEq::eq(self.as_str(), other.as_os_str())
223     }
224 }
225 
226 impl PartialEq<std::ffi::OsString> for OsStr {
227     #[inline]
eq(&self, other: &std::ffi::OsString) -> bool228     fn eq(&self, other: &std::ffi::OsString) -> bool {
229         PartialEq::eq(self.as_os_str(), other.as_os_str())
230     }
231 }
232 impl PartialEq<OsStr> for std::ffi::OsString {
233     #[inline]
eq(&self, other: &OsStr) -> bool234     fn eq(&self, other: &OsStr) -> bool {
235         PartialEq::eq(self.as_os_str(), other.as_os_str())
236     }
237 }
238 
239 #[cfg(feature = "string")]
240 pub(crate) mod inner {
241     #[derive(Clone)]
242     pub(crate) enum Inner {
243         Static(&'static std::ffi::OsStr),
244         Owned(Box<std::ffi::OsStr>),
245     }
246 
247     impl Inner {
from_string(name: std::ffi::OsString) -> Self248         pub(crate) fn from_string(name: std::ffi::OsString) -> Self {
249             Self::Owned(name.into_boxed_os_str())
250         }
251 
from_ref(name: &std::ffi::OsStr) -> Self252         pub(crate) fn from_ref(name: &std::ffi::OsStr) -> Self {
253             Self::Owned(Box::from(name))
254         }
255 
from_static_ref(name: &'static std::ffi::OsStr) -> Self256         pub(crate) fn from_static_ref(name: &'static std::ffi::OsStr) -> Self {
257             Self::Static(name)
258         }
259 
as_os_str(&self) -> &std::ffi::OsStr260         pub(crate) fn as_os_str(&self) -> &std::ffi::OsStr {
261             match self {
262                 Self::Static(s) => s,
263                 Self::Owned(s) => s.as_ref(),
264             }
265         }
266 
into_os_string(self) -> std::ffi::OsString267         pub(crate) fn into_os_string(self) -> std::ffi::OsString {
268             self.as_os_str().to_owned()
269         }
270     }
271 }
272 
273 #[cfg(not(feature = "string"))]
274 pub(crate) mod inner {
275     #[derive(Clone)]
276     pub(crate) struct Inner(&'static std::ffi::OsStr);
277 
278     impl Inner {
from_static_ref(name: &'static std::ffi::OsStr) -> Self279         pub(crate) fn from_static_ref(name: &'static std::ffi::OsStr) -> Self {
280             Self(name)
281         }
282 
as_os_str(&self) -> &std::ffi::OsStr283         pub(crate) fn as_os_str(&self) -> &std::ffi::OsStr {
284             self.0
285         }
286 
into_os_string(self) -> std::ffi::OsString287         pub(crate) fn into_os_string(self) -> std::ffi::OsString {
288             self.as_os_str().to_owned()
289         }
290     }
291 }
292 
293 pub(crate) use inner::Inner;
294 
295 impl Default for Inner {
default() -> Self296     fn default() -> Self {
297         Self::from_static_ref(std::ffi::OsStr::new(""))
298     }
299 }
300 
301 impl PartialEq for Inner {
eq(&self, other: &Inner) -> bool302     fn eq(&self, other: &Inner) -> bool {
303         self.as_os_str() == other.as_os_str()
304     }
305 }
306 
307 impl PartialOrd for Inner {
partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering>308     fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
309         Some(self.cmp(other))
310     }
311 }
312 
313 impl Ord for Inner {
cmp(&self, other: &Inner) -> std::cmp::Ordering314     fn cmp(&self, other: &Inner) -> std::cmp::Ordering {
315         self.as_os_str().cmp(other.as_os_str())
316     }
317 }
318 
319 impl Eq for Inner {}
320 
321 impl std::hash::Hash for Inner {
322     #[inline]
hash<H: std::hash::Hasher>(&self, state: &mut H)323     fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
324         self.as_os_str().hash(state);
325     }
326 }
327