Skip to content

Commit

Permalink
Added conversions between HSTRING and OsStr/OsString (#1693)
Browse files Browse the repository at this point in the history
  • Loading branch information
kaivol authored Apr 15, 2022
1 parent 2db1d34 commit 8041194
Show file tree
Hide file tree
Showing 2 changed files with 170 additions and 0 deletions.
121 changes: 121 additions & 0 deletions crates/libs/windows/src/core/hstring.rs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,11 @@ impl HSTRING {
alloc::string::String::from_utf16_lossy(self.as_wide())
}

/// Get the contents of this `HSTRING` as a OsString.
pub fn to_os_string(&self) -> std::ffi::OsString {
std::os::windows::ffi::OsStringExt::from_wide(self.as_wide())
}

/// Clear the contents of the string and free the memory if `self` holds the
/// last reference to the string data.
pub fn clear(&mut self) {
Expand Down Expand Up @@ -164,6 +169,24 @@ impl core::convert::From<&alloc::string::String> for HSTRING {
}
}

impl core::convert::From<&std::ffi::OsStr> for HSTRING {
fn from(value: &std::ffi::OsStr) -> Self {
unsafe { Self::from_wide_iter(std::os::windows::ffi::OsStrExt::encode_wide(value), value.len() as u32) }
}
}

impl core::convert::From<std::ffi::OsString> for HSTRING {
fn from(value: std::ffi::OsString) -> Self {
value.as_os_str().into()
}
}

impl core::convert::From<&std::ffi::OsString> for HSTRING {
fn from(value: &std::ffi::OsString) -> Self {
value.as_os_str().into()
}
}

impl PartialEq for HSTRING {
fn eq(&self, other: &Self) -> bool {
*self.as_wide() == *other.as_wide()
Expand Down Expand Up @@ -242,6 +265,78 @@ impl PartialEq<&HSTRING> for alloc::string::String {
}
}

impl PartialEq<std::ffi::OsString> for HSTRING {
fn eq(&self, other: &std::ffi::OsString) -> bool {
*self == **other
}
}

impl PartialEq<std::ffi::OsString> for &HSTRING {
fn eq(&self, other: &std::ffi::OsString) -> bool {
**self == **other
}
}

impl PartialEq<&std::ffi::OsString> for HSTRING {
fn eq(&self, other: &&std::ffi::OsString) -> bool {
*self == ***other
}
}

impl PartialEq<std::ffi::OsStr> for HSTRING {
fn eq(&self, other: &std::ffi::OsStr) -> bool {
self.as_wide().iter().copied().eq(std::os::windows::ffi::OsStrExt::encode_wide(other))
}
}

impl PartialEq<std::ffi::OsStr> for &HSTRING {
fn eq(&self, other: &std::ffi::OsStr) -> bool {
**self == *other
}
}

impl PartialEq<&std::ffi::OsStr> for HSTRING {
fn eq(&self, other: &&std::ffi::OsStr) -> bool {
*self == **other
}
}

impl PartialEq<HSTRING> for std::ffi::OsStr {
fn eq(&self, other: &HSTRING) -> bool {
*other == *self
}
}

impl PartialEq<HSTRING> for &std::ffi::OsStr {
fn eq(&self, other: &HSTRING) -> bool {
*other == **self
}
}

impl PartialEq<&HSTRING> for std::ffi::OsStr {
fn eq(&self, other: &&HSTRING) -> bool {
**other == *self
}
}

impl PartialEq<HSTRING> for std::ffi::OsString {
fn eq(&self, other: &HSTRING) -> bool {
*other == **self
}
}

impl PartialEq<HSTRING> for &std::ffi::OsString {
fn eq(&self, other: &HSTRING) -> bool {
*other == ***self
}
}

impl PartialEq<&HSTRING> for std::ffi::OsString {
fn eq(&self, other: &&HSTRING) -> bool {
**other == **self
}
}

impl<'a> core::convert::TryFrom<&'a HSTRING> for alloc::string::String {
type Error = alloc::string::FromUtf16Error;

Expand All @@ -258,6 +353,18 @@ impl core::convert::TryFrom<HSTRING> for alloc::string::String {
}
}

impl<'a> core::convert::From<&'a HSTRING> for std::ffi::OsString {
fn from(hstring: &HSTRING) -> Self {
hstring.to_os_string()
}
}

impl core::convert::From<HSTRING> for std::ffi::OsString {
fn from(hstring: HSTRING) -> Self {
Self::from(&hstring)
}
}

#[cfg(feature = "alloc")]
impl<'a> IntoParam<'a, HSTRING> for &str {
fn into_param(self) -> Param<'a, HSTRING> {
Expand All @@ -272,6 +379,20 @@ impl<'a> IntoParam<'a, HSTRING> for alloc::string::String {
}
}

#[cfg(feature = "alloc")]
impl<'a> IntoParam<'a, HSTRING> for &std::ffi::OsStr {
fn into_param(self) -> Param<'a, HSTRING> {
Param::Owned(self.into())
}
}

#[cfg(feature = "alloc")]
impl<'a> IntoParam<'a, HSTRING> for std::ffi::OsString {
fn into_param(self) -> Param<'a, HSTRING> {
Param::Owned(self.into())
}
}

const REFERENCE_FLAG: u32 = 1;

#[repr(C)]
Expand Down
49 changes: 49 additions & 0 deletions crates/tests/core/tests/hstrings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,16 @@ fn from_empty_string() {
assert!(format!("{}", h).is_empty());
}

#[test]
fn from_os_string_string() {
let wide_data = &[0xD834, 0xDD1E, 0x006d, 0x0075, 0xD800, 0x0069, 0x0063];
use std::os::windows::prelude::OsStringExt;
let o = std::ffi::OsString::from_wide(wide_data);
let h = StringType::from(o);
let d = StringType::from_wide(wide_data);
assert_eq!(h, d);
}

#[test]
fn hstring_to_string() {
let h = StringType::from("test");
Expand All @@ -78,6 +88,16 @@ fn hstring_to_string_lossy() {
assert_eq!(s, "𝄞mu�ic");
}

#[test]
fn hstring_to_os_string() {
// 𝄞mu<invalid>ic
let wide_data = &[0xD834, 0xDD1E, 0x006d, 0x0075, 0xD800, 0x0069, 0x0063];
let h = StringType::from_wide(wide_data);
let s = h.to_os_string();
use std::os::windows::prelude::OsStringExt;
assert_eq!(s, std::ffi::OsString::from_wide(wide_data));
}

#[test]
fn hstring_equality_combinations() {
let h = StringType::from("test");
Expand All @@ -104,3 +124,32 @@ fn hstring_equality_combinations() {
assert_eq!(ss, h);
assert_eq!(ss, &h);
}

#[test]
fn hstring_osstring_equality_combinations() {
let wide_data = &[0xD834, 0xDD1E, 0x006d, 0x0075, 0xD800, 0x0069, 0x0063];
let h = StringType::from_wide(wide_data);
use std::os::windows::prelude::OsStringExt;
let s = std::ffi::OsString::from_wide(wide_data);
let ss = s.as_os_str();

assert_eq!(h, s);
assert_eq!(&h, s);
assert_eq!(h, &s);
assert_eq!(&h, &s);

assert_eq!(s, h);
assert_eq!(s, &h);
assert_eq!(&s, h);
assert_eq!(&s, &h);

assert_eq!(h, *ss);
assert_eq!(&h, *ss);
assert_eq!(h, ss);
assert_eq!(&h, ss);

assert_eq!(*ss, h);
assert_eq!(*ss, &h);
assert_eq!(ss, h);
assert_eq!(ss, &h);
}

0 comments on commit 8041194

Please sign in to comment.