|
52 | 52 |
|
53 | 53 | #![stable(feature = "rust1", since = "1.0.0")]
|
54 | 54 |
|
| 55 | +use crate::cmp::Ordering; |
55 | 56 | use crate::ffi::{OsStr, OsString};
|
| 57 | +use crate::io; |
56 | 58 | use crate::sealed::Sealed;
|
57 | 59 | use crate::sys::os_str::Buf;
|
58 | 60 | use crate::sys_common::wtf8::Wtf8Buf;
|
@@ -124,11 +126,99 @@ pub trait OsStrExt: Sealed {
|
124 | 126 | /// ```
|
125 | 127 | #[stable(feature = "rust1", since = "1.0.0")]
|
126 | 128 | fn encode_wide(&self) -> EncodeWide<'_>;
|
| 129 | + |
| 130 | + /// Compares two `OsStr` by using the Windows system implementation. |
| 131 | + /// This performs a case-insensitive comparison of UTF-16 code units using the system case mappings. |
| 132 | + /// The comparison is locale-independent, but exact results may depend on the Windows version, |
| 133 | + /// file system, and system settings. |
| 134 | + /// |
| 135 | + /// This is the correct way to compare various strings on Windows: |
| 136 | + /// environment variable keys, registry keys and resource handle names are all case-insensitive. |
| 137 | + /// Note that this does not include file names or paths; those can be case-sensitive depending on |
| 138 | + /// the system, file system or directory settings. |
| 139 | + /// |
| 140 | + /// Note that this operation requires encoding both strings to UTF-16 and potentially performing system calls. |
| 141 | + /// This operation is thus more computationally expensive than a normal comparison using [`Ord`]. |
| 142 | + /// |
| 143 | + /// # Errors |
| 144 | + /// |
| 145 | + /// This function will return an error in the following situations, but is not limited to just these cases: |
| 146 | + /// - If the string contains any null characters. |
| 147 | + /// |
| 148 | + /// # Examples |
| 149 | + /// ``` |
| 150 | + /// #![feature(windows_case_insensitive)] |
| 151 | + /// |
| 152 | + /// use std::ffi::OsString; |
| 153 | + /// use std::os::windows::prelude::*; |
| 154 | + /// |
| 155 | + /// let list = [ OsString::from("A"), OsString::from("Z"), OsString::from("a") ]; |
| 156 | + /// |
| 157 | + /// let mut sorted = list.clone(); |
| 158 | + /// sorted.sort(); |
| 159 | + /// |
| 160 | + /// let mut sorted_with_system_cmp = list.clone(); |
| 161 | + /// sorted_with_system_cmp.sort_by(|a, b| a.system_cmp(b).unwrap()); |
| 162 | + /// |
| 163 | + /// assert_eq!(sorted, list); // unchanged, since `Z` < `a` |
| 164 | + /// assert_eq!(sorted_with_system_cmp, [ OsString::from("A"), OsString::from("a"), OsString::from("Z") ]); |
| 165 | + /// ``` |
| 166 | + #[unstable(feature = "windows_case_insensitive", issue = "86007")] |
| 167 | + fn system_cmp(&self, other: &Self) -> io::Result<Ordering>; |
| 168 | + |
| 169 | + /// Checks two `OsStr` for equality by using the Windows system implementation. |
| 170 | + /// This performs a case-insensitive comparison of UTF-16 code units using the system case mappings. |
| 171 | + /// The comparison is locale-independent, but exact results may depend on the Windows version, |
| 172 | + /// file system, and system settings. |
| 173 | + /// |
| 174 | + /// This is the correct way to compare various strings on Windows: |
| 175 | + /// environment variable keys, registry keys and resource handle names are all case-insensitive. |
| 176 | + /// Note that this does not include file names or paths; those can be case-sensitive depending on |
| 177 | + /// the system, file system or directory settings. |
| 178 | + /// |
| 179 | + /// Note that this operation requires encoding both strings to UTF-16 and potentially performing system calls. |
| 180 | + /// This operation is thus more computationally expensive than a normal comparison using [`Eq`]. |
| 181 | + /// |
| 182 | + /// # Errors |
| 183 | + /// |
| 184 | + /// This function will return an error in the following situations, but is not limited to just these cases: |
| 185 | + /// - If the string contains any null characters. |
| 186 | + /// |
| 187 | + /// # Examples |
| 188 | + /// ``` |
| 189 | + /// #![feature(windows_case_insensitive)] |
| 190 | + /// |
| 191 | + /// use std::ffi::OsString; |
| 192 | + /// use std::os::windows::prelude::*; |
| 193 | + /// |
| 194 | + /// let a = OsString::from("Path"); |
| 195 | + /// let b = OsString::from("PATH"); |
| 196 | + /// |
| 197 | + /// assert!(a.eq(&b) == false); |
| 198 | + /// assert!(a.system_eq(&b).unwrap() == true); |
| 199 | + #[unstable(feature = "windows_case_insensitive", issue = "86007")] |
| 200 | + fn system_eq(&self, other: &Self) -> io::Result<bool>; |
127 | 201 | }
|
128 | 202 |
|
129 | 203 | #[stable(feature = "rust1", since = "1.0.0")]
|
130 | 204 | impl OsStrExt for OsStr {
|
131 | 205 | fn encode_wide(&self) -> EncodeWide<'_> {
|
132 | 206 | self.as_inner().inner.encode_wide()
|
133 | 207 | }
|
| 208 | + |
| 209 | + fn system_cmp(&self, other: &Self) -> io::Result<Ordering> { |
| 210 | + crate::sys::compare_case_insensitive(self, other) |
| 211 | + } |
| 212 | + |
| 213 | + fn system_eq(&self, other: &Self) -> io::Result<bool> { |
| 214 | + if self.len() == other.len() { |
| 215 | + Ok(crate::sys::compare_case_insensitive(self, other)? == Ordering::Equal) |
| 216 | + } else { |
| 217 | + // The system implementation performs an "ordinal" check, so directly comparing every |
| 218 | + // code unit in the same position in the two strings. As a consequence, two strings |
| 219 | + // with different lengths can never be equal, even if they contain characters that |
| 220 | + // change length when changing case according to Unicode. |
| 221 | + Ok(false) |
| 222 | + } |
| 223 | + } |
134 | 224 | }
|
0 commit comments