Skip to content

Commit 8392bd3

Browse files
committed
Add os::windows::ffi::OsStrExt::system_cmp and system_eq
1 parent 3bc4d2b commit 8392bd3

File tree

1 file changed

+90
-0
lines changed
  • library/std/src/os/windows

1 file changed

+90
-0
lines changed

Diff for: library/std/src/os/windows/ffi.rs

+90
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,9 @@
5252
5353
#![stable(feature = "rust1", since = "1.0.0")]
5454

55+
use crate::cmp::Ordering;
5556
use crate::ffi::{OsStr, OsString};
57+
use crate::io;
5658
use crate::sealed::Sealed;
5759
use crate::sys::os_str::Buf;
5860
use crate::sys_common::wtf8::Wtf8Buf;
@@ -124,11 +126,99 @@ pub trait OsStrExt: Sealed {
124126
/// ```
125127
#[stable(feature = "rust1", since = "1.0.0")]
126128
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>;
127201
}
128202

129203
#[stable(feature = "rust1", since = "1.0.0")]
130204
impl OsStrExt for OsStr {
131205
fn encode_wide(&self) -> EncodeWide<'_> {
132206
self.as_inner().inner.encode_wide()
133207
}
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+
}
134224
}

0 commit comments

Comments
 (0)