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