Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make more of the HSTRING methods const #2078

Merged
merged 4 commits into from Sep 29, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/workflows/build.yml
Expand Up @@ -64,7 +64,7 @@ jobs:
name: Check windows
strategy:
matrix:
rust: [1.59.0, stable, nightly]
rust: [1.64.0, stable, nightly]
runs-on:
- windows-2019
- ubuntu-latest
Expand Down
2 changes: 1 addition & 1 deletion crates/libs/implement/Cargo.toml
Expand Up @@ -6,7 +6,7 @@ edition = "2018"
license = "MIT OR Apache-2.0"
description = "The implement macro for the windows crate"
repository = "https://github.com/microsoft/windows-rs"
rust-version = "1.61"
rust-version = "1.64"

[package.metadata.docs.rs]
default-target = "x86_64-pc-windows-msvc"
Expand Down
2 changes: 1 addition & 1 deletion crates/libs/interface/Cargo.toml
Expand Up @@ -6,7 +6,7 @@ authors = ["Microsoft"]
license = "MIT OR Apache-2.0"
description = "The interface macro for the windows crate"
repository = "https://github.com/microsoft/windows-rs"
rust-version = "1.61"
rust-version = "1.64"

[package.metadata.docs.rs]
default-target = "x86_64-pc-windows-msvc"
Expand Down
2 changes: 1 addition & 1 deletion crates/libs/windows/Cargo.toml
Expand Up @@ -9,7 +9,7 @@ description = "Rust for Windows"
repository = "https://github.com/microsoft/windows-rs"
documentation = "https://microsoft.github.io/windows-docs-rs/"
readme = "../../../docs/readme.md"
rust-version = "1.59"
rust-version = "1.64"

[package.metadata.docs.rs]
default-target = "x86_64-pc-windows-msvc"
Expand Down
60 changes: 35 additions & 25 deletions crates/libs/windows/src/core/strings/hstring.rs
Expand Up @@ -3,44 +3,43 @@ use super::*;
/// A WinRT string ([HSTRING](https://docs.microsoft.com/en-us/windows/win32/winrt/hstring))
/// is reference-counted and immutable.
#[repr(transparent)]
pub struct HSTRING(*mut Header);
pub struct HSTRING(Option<std::ptr::NonNull<Header>>);

impl HSTRING {
/// Create an empty `HSTRING`.
///
/// This function does not allocate memory.
pub const fn new() -> Self {
Self(std::ptr::null_mut())
Self(None)
}

/// Returns `true` if the string is empty.
pub fn is_empty(&self) -> bool {
pub const fn is_empty(&self) -> bool {
// An empty HSTRING is represented by a null pointer.
self.0.is_null()
self.0.is_none()
}

/// Returns the length of the string.
pub fn len(&self) -> usize {
if self.is_empty() {
return 0;
pub const fn len(&self) -> usize {
if let Some(header) = self.get_header() {
header.len as usize
} else {
0
}

unsafe { (*self.0).len as usize }
}

/// Get the string as 16-bit wide characters (wchars).
pub fn as_wide(&self) -> &[u16] {
pub const fn as_wide(&self) -> &[u16] {
unsafe { std::slice::from_raw_parts(self.as_ptr(), self.len()) }
}

/// Returns a raw pointer to the `HSTRING` buffer.
pub fn as_ptr(&self) -> *const u16 {
if self.is_empty() {
pub const fn as_ptr(&self) -> *const u16 {
if let Some(header) = self.get_header() {
header.data
} else {
const EMPTY: [u16; 1] = [0];
EMPTY.as_ptr()
} else {
let header = self.0;
unsafe { (*header).data }
}
}

Expand Down Expand Up @@ -80,7 +79,16 @@ impl HSTRING {

// Write a 0 byte to the end of the buffer.
std::ptr::write((*ptr).data.offset((*ptr).len as isize), 0);
Self(ptr)
Self(std::mem::transmute(ptr))
}

const fn get_header(&self) -> Option<&Header> {
if let Some(header) = &self.0 {
// TODO: this can be replaced with `as_ref` in future: https://github.com/rust-lang/rust/issues/91822
unsafe { Some(&*(header.as_ptr() as *const Header)) }
} else {
None
}
}
}

Expand All @@ -104,11 +112,11 @@ impl Default for HSTRING {

impl Clone for HSTRING {
fn clone(&self) -> Self {
if self.is_empty() {
return Self::new();
if let Some(header) = self.get_header() {
unsafe { Self(std::mem::transmute(header.duplicate())) }
kennykerr marked this conversation as resolved.
Show resolved Hide resolved
} else {
Self::new()
}

unsafe { Self((*self.0).duplicate()) }
}
}

Expand All @@ -119,11 +127,13 @@ impl Drop for HSTRING {
}

unsafe {
let header = std::mem::replace(&mut self.0, std::ptr::null_mut());
// REFERENCE_FLAG indicates a string backed by static or stack memory that is
// thus not reference-counted and does not need to be freed.
if (*header).flags & REFERENCE_FLAG == 0 && (*header).count.release() == 0 {
heap_free(header as *mut std::ffi::c_void);
if let Some(header) = self.0.take() {
kennykerr marked this conversation as resolved.
Show resolved Hide resolved
// REFERENCE_FLAG indicates a string backed by static or stack memory that is
// thus not reference-counted and does not need to be freed.
let header = header.as_ref();
if header.flags & REFERENCE_FLAG == 0 && header.count.release() == 0 {
heap_free(header as *const _ as *mut _);
}
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions crates/libs/windows/src/core/weak_ref_count.rs
Expand Up @@ -13,11 +13,11 @@ impl WeakRefCount {
}

pub fn add_ref(&self) -> u32 {
self.0.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |count_or_pointer| (!is_weak_ref(count_or_pointer)).then(|| count_or_pointer + 1)).map(|u| u as u32 + 1).unwrap_or_else(|pointer| unsafe { TearOff::decode(pointer).strong_count.add_ref() })
self.0.fetch_update(Ordering::Relaxed, Ordering::Relaxed, |count_or_pointer| (!is_weak_ref(count_or_pointer)).then_some(count_or_pointer + 1)).map(|u| u as u32 + 1).unwrap_or_else(|pointer| unsafe { TearOff::decode(pointer).strong_count.add_ref() })
}

pub fn release(&self) -> u32 {
self.0.fetch_update(Ordering::Release, Ordering::Relaxed, |count_or_pointer| (!is_weak_ref(count_or_pointer)).then(|| count_or_pointer - 1)).map(|u| u as u32 - 1).unwrap_or_else(|pointer| unsafe {
self.0.fetch_update(Ordering::Release, Ordering::Relaxed, |count_or_pointer| (!is_weak_ref(count_or_pointer)).then_some(count_or_pointer - 1)).map(|u| u as u32 - 1).unwrap_or_else(|pointer| unsafe {
let tear_off = TearOff::decode(pointer);
let remaining = tear_off.strong_count.release();

Expand Down Expand Up @@ -214,7 +214,7 @@ impl TearOff {
.fetch_update(Ordering::Acquire, Ordering::Relaxed, |count| {
// Attempt to acquire a strong reference count to stabilize the object for the duration
// of the `QueryInterface` call.
(count != 0).then(|| count + 1)
(count != 0).then_some(count + 1)
})
.map(|_| {
// Let the object respond to the upgrade query.
Expand Down
1 change: 1 addition & 0 deletions crates/tests/core/tests/hstring.rs
Expand Up @@ -3,6 +3,7 @@ use windows::core::*;

#[test]
fn hstring_works() {
assert_eq!(std::mem::size_of::<HSTRING>(), std::mem::size_of::<usize>());
let empty = HSTRING::new();
assert!(empty.is_empty());
assert!(empty.is_empty());
Expand Down
2 changes: 1 addition & 1 deletion crates/tools/windows/src/main.rs
Expand Up @@ -47,7 +47,7 @@ description = "Rust for Windows"
repository = "https://github.com/microsoft/windows-rs"
documentation = "https://microsoft.github.io/windows-docs-rs/"
readme = "../../../docs/readme.md"
rust-version = "1.59"
rust-version = "1.64"

[package.metadata.docs.rs]
default-target = "x86_64-pc-windows-msvc"
Expand Down
2 changes: 1 addition & 1 deletion crates/tools/yml/src/main.rs
Expand Up @@ -215,7 +215,7 @@ jobs:
name: Check windows
strategy:
matrix:
rust: [1.59.0, stable, nightly]
rust: [1.64.0, stable, nightly]
runs-on:
- windows-2019
- ubuntu-latest
Expand Down