clap_builder/builder/
os_str.rs

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