Skip to content

Commit

Permalink
Make more of the HSTRING methods const (#2078)
Browse files Browse the repository at this point in the history
  • Loading branch information
kennykerr committed Sep 29, 2022
1 parent e067fab commit 85ae672
Show file tree
Hide file tree
Showing 9 changed files with 44 additions and 33 deletions.
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
58 changes: 34 additions & 24 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::ptr::NonNull::new(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() {
Self(std::ptr::NonNull::new(header.duplicate()))
} else {
Self::new()
}

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

Expand All @@ -118,12 +126,14 @@ impl Drop for HSTRING {
return;
}

unsafe {
let header = std::mem::replace(&mut self.0, std::ptr::null_mut());
if let Some(header) = self.0.take() {
// 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);
unsafe {
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

0 comments on commit 85ae672

Please sign in to comment.