clap_builder/builder/
os_str.rs

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
67impl From<&'_ Str> for OsStr {
68    fn from(id: &'_ Str) -> Self {
69        id.clone().into()
70    }
71}
72
73#[cfg(feature = "string")]
74impl From<std::ffi::OsString> for OsStr {
75    fn from(name: std::ffi::OsString) -> Self {
76        Self::from_string(name)
77    }
78}
79
80#[cfg(feature = "string")]
81impl From<&'_ std::ffi::OsString> for OsStr {
82    fn from(name: &'_ std::ffi::OsString) -> Self {
83        Self::from_ref(name.as_os_str())
84    }
85}
86
87#[cfg(feature = "string")]
88impl From<String> for OsStr {
89    fn from(name: String) -> Self {
90        Self::from_string(name.into())
91    }
92}
93
94#[cfg(feature = "string")]
95impl From<&'_ String> for OsStr {
96    fn from(name: &'_ String) -> Self {
97        Self::from_ref(name.as_str().as_ref())
98    }
99}
100
101impl From<&'static std::ffi::OsStr> for OsStr {
102    fn from(name: &'static std::ffi::OsStr) -> Self {
103        Self::from_static_ref(name)
104    }
105}
106
107impl From<&'_ &'static std::ffi::OsStr> for OsStr {
108    fn from(name: &'_ &'static std::ffi::OsStr) -> Self {
109        Self::from_static_ref(name)
110    }
111}
112
113impl From<&'static str> for OsStr {
114    fn from(name: &'static str) -> Self {
115        Self::from_static_ref(name.as_ref())
116    }
117}
118
119impl From<&'_ &'static str> for OsStr {
120    fn from(name: &'_ &'static str) -> Self {
121        Self::from_static_ref((*name).as_ref())
122    }
123}
124
125impl From<OsStr> for std::ffi::OsString {
126    fn from(name: OsStr) -> Self {
127        name.name.into_os_string()
128    }
129}
130
131impl From<OsStr> for std::path::PathBuf {
132    fn from(name: OsStr) -> Self {
133        std::ffi::OsString::from(name).into()
134    }
135}
136
137impl std::fmt::Debug for OsStr {
138    #[inline]
139    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
140        std::fmt::Debug::fmt(self.as_os_str(), f)
141    }
142}
143
144impl std::ops::Deref for OsStr {
145    type Target = std::ffi::OsStr;
146
147    #[inline]
148    fn deref(&self) -> &std::ffi::OsStr {
149        self.as_os_str()
150    }
151}
152
153impl AsRef<std::ffi::OsStr> for OsStr {
154    #[inline]
155    fn as_ref(&self) -> &std::ffi::OsStr {
156        self.as_os_str()
157    }
158}
159
160impl AsRef<std::path::Path> for OsStr {
161    #[inline]
162    fn as_ref(&self) -> &std::path::Path {
163        std::path::Path::new(self)
164    }
165}
166
167impl std::borrow::Borrow<std::ffi::OsStr> for OsStr {
168    #[inline]
169    fn borrow(&self) -> &std::ffi::OsStr {
170        self.as_os_str()
171    }
172}
173
174impl PartialEq<str> for OsStr {
175    #[inline]
176    fn eq(&self, other: &str) -> bool {
177        PartialEq::eq(self.as_os_str(), other)
178    }
179}
180impl PartialEq<OsStr> for str {
181    #[inline]
182    fn eq(&self, other: &OsStr) -> bool {
183        PartialEq::eq(self, other.as_os_str())
184    }
185}
186
187impl PartialEq<&'_ str> for OsStr {
188    #[inline]
189    fn eq(&self, other: &&str) -> bool {
190        PartialEq::eq(self.as_os_str(), *other)
191    }
192}
193impl PartialEq<OsStr> for &'_ str {
194    #[inline]
195    fn eq(&self, other: &OsStr) -> bool {
196        PartialEq::eq(*self, other.as_os_str())
197    }
198}
199
200impl PartialEq<&'_ std::ffi::OsStr> for OsStr {
201    #[inline]
202    fn eq(&self, other: &&std::ffi::OsStr) -> bool {
203        PartialEq::eq(self.as_os_str(), *other)
204    }
205}
206impl PartialEq<OsStr> for &'_ std::ffi::OsStr {
207    #[inline]
208    fn eq(&self, other: &OsStr) -> bool {
209        PartialEq::eq(*self, other.as_os_str())
210    }
211}
212
213impl PartialEq<String> for OsStr {
214    #[inline]
215    fn eq(&self, other: &String) -> bool {
216        PartialEq::eq(self.as_os_str(), other.as_str())
217    }
218}
219impl PartialEq<OsStr> for String {
220    #[inline]
221    fn eq(&self, other: &OsStr) -> bool {
222        PartialEq::eq(self.as_str(), other.as_os_str())
223    }
224}
225
226impl PartialEq<std::ffi::OsString> for OsStr {
227    #[inline]
228    fn eq(&self, other: &std::ffi::OsString) -> bool {
229        PartialEq::eq(self.as_os_str(), other.as_os_str())
230    }
231}
232impl PartialEq<OsStr> for std::ffi::OsString {
233    #[inline]
234    fn eq(&self, other: &OsStr) -> bool {
235        PartialEq::eq(self.as_os_str(), other.as_os_str())
236    }
237}
238
239#[cfg(feature = "string")]
240pub(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 {
248        pub(crate) fn from_string(name: std::ffi::OsString) -> Self {
249            Self::Owned(name.into_boxed_os_str())
250        }
251
252        pub(crate) fn from_ref(name: &std::ffi::OsStr) -> Self {
253            Self::Owned(Box::from(name))
254        }
255
256        pub(crate) fn from_static_ref(name: &'static std::ffi::OsStr) -> Self {
257            Self::Static(name)
258        }
259
260        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
267        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"))]
274pub(crate) mod inner {
275    #[derive(Clone)]
276    pub(crate) struct Inner(&'static std::ffi::OsStr);
277
278    impl Inner {
279        pub(crate) fn from_static_ref(name: &'static std::ffi::OsStr) -> Self {
280            Self(name)
281        }
282
283        pub(crate) fn as_os_str(&self) -> &std::ffi::OsStr {
284            self.0
285        }
286
287        pub(crate) fn into_os_string(self) -> std::ffi::OsString {
288            self.as_os_str().to_owned()
289        }
290    }
291}
292
293pub(crate) use inner::Inner;
294
295impl Default for Inner {
296    fn default() -> Self {
297        Self::from_static_ref(std::ffi::OsStr::new(""))
298    }
299}
300
301impl PartialEq for Inner {
302    fn eq(&self, other: &Inner) -> bool {
303        self.as_os_str() == other.as_os_str()
304    }
305}
306
307impl PartialOrd for Inner {
308    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
309        Some(self.cmp(other))
310    }
311}
312
313impl Ord for Inner {
314    fn cmp(&self, other: &Inner) -> std::cmp::Ordering {
315        self.as_os_str().cmp(other.as_os_str())
316    }
317}
318
319impl Eq for Inner {}
320
321impl std::hash::Hash for Inner {
322    #[inline]
323    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
324        self.as_os_str().hash(state);
325    }
326}