Skip to content

Commit

Permalink
Add non-Windows support for PWSTR and PCWSTR (microsoft#3004)
Browse files Browse the repository at this point in the history
  • Loading branch information
tyilo authored and mati865 committed Jun 15, 2024
1 parent 1849aae commit 1c5df28
Show file tree
Hide file tree
Showing 4 changed files with 59 additions and 9 deletions.
2 changes: 0 additions & 2 deletions crates/libs/core/src/strings/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,6 @@ use super::*;
extern "C" {
#[doc(hidden)]
pub fn strlen(s: PCSTR) -> usize;
#[doc(hidden)]
pub fn wcslen(s: PCWSTR) -> usize;
}

/// An internal helper for decoding an iterator of chars and displaying them
Expand Down
40 changes: 38 additions & 2 deletions crates/libs/core/src/strings/pcwstr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,50 @@ impl PCWSTR {
self.0.is_null()
}

/// String length without the trailing 0
///
/// # Safety
///
/// The `PCWSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
pub unsafe fn len(&self) -> usize {
#[cfg(windows)]
let len = {
extern "C" {
fn wcslen(s: *const u16) -> usize;
}
wcslen(self.0)
};

#[cfg(not(windows))]
let len = {
let mut len = 0;
let mut ptr = self.0;
while ptr.read() != 0 {
len += 1;
ptr = ptr.add(1);
}
len
};

len
}

/// Returns `true` if the string length is zero, and `false` otherwise.
///
/// # Safety
///
/// The `PCWSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
pub unsafe fn is_empty(&self) -> bool {
self.len() == 0
}

/// String data without the trailing 0
///
/// # Safety
///
/// The `PCWSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
pub unsafe fn as_wide(&self) -> &[u16] {
let len = wcslen(*self);
std::slice::from_raw_parts(self.0, len)
std::slice::from_raw_parts(self.0, self.len())
}

/// Copy the `PCWSTR` into a Rust `String`.
Expand Down
21 changes: 19 additions & 2 deletions crates/libs/core/src/strings/pwstr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,14 +26,31 @@ impl PWSTR {
self.0.is_null()
}

/// String length without the trailing 0
///
/// # Safety
///
/// The `PWSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
pub unsafe fn len(&self) -> usize {
PCWSTR(self.0).len()
}

/// Returns `true` if the string length is zero, and `false` otherwise.
///
/// # Safety
///
/// The `PWSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
pub unsafe fn is_empty(&self) -> bool {
self.len() == 0
}

/// String data without the trailing 0.
///
/// # Safety
///
/// The `PWSTR`'s pointer needs to be valid for reads up until and including the next `\0`.
pub unsafe fn as_wide(&self) -> &[u16] {
let len = wcslen(PCWSTR::from_raw(self.0));
std::slice::from_raw_parts(self.0, len)
std::slice::from_raw_parts(self.0, self.len())
}

/// Copy the `PWSTR` into a Rust `String`.
Expand Down
5 changes: 2 additions & 3 deletions crates/tests/linux/tests/strings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,7 @@ fn test() {
let s: PCSTR = s!("hello world");
assert_eq!(s.to_string().unwrap(), "hello world");

// TODO: https://github.com/microsoft/windows-rs/pull/3004 should enable the following test.
// let w: PCWSTR = w!("wide world");
// assert_eq!(w.to_string().unwrap(), "wide world");
let w: PCWSTR = w!("wide world");
assert_eq!(w.to_string().unwrap(), "wide world");
}
}

0 comments on commit 1c5df28

Please sign in to comment.