Skip to content

Commit a200c01

Browse files
committed
Document how Windows compares environment variables
1 parent 8345538 commit a200c01

File tree

1 file changed

+22
-3
lines changed

1 file changed

+22
-3
lines changed

library/std/src/sys/windows/process.rs

+22-3
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,26 @@ pub struct EnvKey {
4646
utf16: Vec<u16>,
4747
}
4848

49-
// Windows environment variables preserve their case but comparisons use
50-
// simplified case folding. So we call `CompareStringOrdinal` to get the OS to
51-
// perform the comparison.
49+
// Comparing Windows environment variable keys[1] are behaviourally the
50+
// composition of two operations[2]:
51+
//
52+
// 1. Case-fold both strings. This is done using a language-independent
53+
// uppercase mapping that's unique to Windows (albeit based on data from an
54+
// older Unicode spec). It only operates on individual UTF-16 code units so
55+
// surrogates are left unchanged. This uppercase mapping can potentially change
56+
// between Windows versions.
57+
//
58+
// 2. Perform an ordinal comparison of the strings. A comparison using ordinal
59+
// is just a comparison based on the numerical value of each UTF-16 code unit[3].
60+
//
61+
// Because the case-folding mapping is unique to Windows and not guaranteed to
62+
// be stable, we ask the OS to compare the strings for us. This is done by
63+
// calling `CompareStringOrdinal`[4] with `bIgnoreCase` set to `TRUE`.
64+
//
65+
// [1] https://docs.microsoft.com/en-us/dotnet/standard/base-types/best-practices-strings#choosing-a-stringcomparison-member-for-your-method-call
66+
// [2] https://docs.microsoft.com/en-us/dotnet/standard/base-types/best-practices-strings#stringtoupper-and-stringtolower
67+
// [3] https://docs.microsoft.com/en-us/dotnet/api/system.stringcomparison?view=net-5.0#System_StringComparison_Ordinal
68+
// [4] https://docs.microsoft.com/en-us/windows/win32/api/stringapiset/nf-stringapiset-comparestringordinal
5269
impl Ord for EnvKey {
5370
fn cmp(&self, other: &Self) -> cmp::Ordering {
5471
unsafe {
@@ -84,6 +101,8 @@ impl PartialEq for EnvKey {
84101
}
85102
}
86103

104+
// Environment variable keys should preserve their original case even though
105+
// they are compared using a caseless string mapping.
87106
impl From<OsString> for EnvKey {
88107
fn from(k: OsString) -> Self {
89108
EnvKey { utf16: k.encode_wide().collect(), os_string: k }

0 commit comments

Comments
 (0)