Skip to content

Commit

Permalink
Add WinRT noexcept support (#3070)
Browse files Browse the repository at this point in the history
  • Loading branch information
kennykerr authored Jun 7, 2024
1 parent 7d94387 commit 21d17ab
Show file tree
Hide file tree
Showing 15 changed files with 1,142 additions and 64 deletions.
2 changes: 2 additions & 0 deletions .github/workflows/clippy.yml
Original file line number Diff line number Diff line change
Expand Up @@ -208,6 +208,8 @@ jobs:
run: cargo clippy -p test_msrv
- name: Clippy test_no_use
run: cargo clippy -p test_no_use
- name: Clippy test_noexcept
run: cargo clippy -p test_noexcept
- name: Clippy test_not_dll
run: cargo clippy -p test_not_dll
- name: Clippy test_query_signature
Expand Down
6 changes: 4 additions & 2 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
Expand Up @@ -234,6 +234,8 @@ jobs:
run: cargo test -p test_msrv --target ${{ matrix.target }} ${{ matrix.etc }}
- name: Test test_no_use
run: cargo test -p test_no_use --target ${{ matrix.target }} ${{ matrix.etc }}
- name: Test test_noexcept
run: cargo test -p test_noexcept --target ${{ matrix.target }} ${{ matrix.etc }}
- name: Test test_not_dll
run: cargo test -p test_not_dll --target ${{ matrix.target }} ${{ matrix.etc }}
- name: Test test_query_signature
Expand All @@ -256,10 +258,10 @@ jobs:
run: cargo test -p test_riddle --target ${{ matrix.target }} ${{ matrix.etc }}
- name: Test test_standalone
run: cargo test -p test_standalone --target ${{ matrix.target }} ${{ matrix.etc }}
- name: Test test_string_param
run: cargo test -p test_string_param --target ${{ matrix.target }} ${{ matrix.etc }}
- name: Clean
run: cargo clean
- name: Test test_string_param
run: cargo test -p test_string_param --target ${{ matrix.target }} ${{ matrix.etc }}
- name: Test test_structs
run: cargo test -p test_structs --target ${{ matrix.target }} ${{ matrix.etc }}
- name: Test test_sys
Expand Down
4 changes: 4 additions & 0 deletions crates/libs/bindgen/src/metadata.rs
Original file line number Diff line number Diff line change
Expand Up @@ -475,6 +475,10 @@ fn method_def_last_error(row: MethodDef) -> bool {
}
}

pub fn method_def_is_noexcept(method: MethodDef) -> bool {
method.has_attribute("NoExceptionAttribute")
}

pub fn type_is_borrowed(ty: &Type) -> bool {
match ty {
Type::TypeDef(row, _) => !type_def_is_blittable(*row),
Expand Down
151 changes: 113 additions & 38 deletions crates/libs/bindgen/src/rust/winrt_methods.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ pub fn writer(
let features = writer.cfg_features(&cfg);
let args = gen_winrt_abi_args(writer, params);
let params = gen_winrt_params(writer, params);
let noexcept = metadata::method_def_is_noexcept(method);

let return_type_tokens = match &signature.return_type {
metadata::Type::Void => quote! { () },
Expand All @@ -35,6 +36,18 @@ pub fn writer(
}
};

let return_type_tokens = if noexcept {
if metadata::type_is_nullable(&signature.return_type) {
quote! { -> Option<#return_type_tokens> }
} else if signature.return_type == metadata::Type::Void {
quote! {}
} else {
quote! { -> #return_type_tokens }
}
} else {
quote! { -> windows_core::Result<#return_type_tokens> }
};

let return_arg = match &signature.return_type {
metadata::Type::Void => quote! {},
_ => {
Expand All @@ -47,38 +60,68 @@ pub fn writer(
}
};

let vcall = quote! { (windows_core::Interface::vtable(this).#vname)(windows_core::Interface::as_raw(this), #args #return_arg) };

let vcall = match &signature.return_type {
metadata::Type::Void => {
quote! {
(windows_core::Interface::vtable(this).#vname)(windows_core::Interface::as_raw(this), #args).ok()
if noexcept {
quote! {
let hresult__ = #vcall;
debug_assert!(hresult__.0 == 0);
}
} else {
quote! {
#vcall.ok()
}
}
}
_ if signature.return_type.is_winrt_array() => {
quote! {
let mut result__ = core::mem::MaybeUninit::zeroed();
(windows_core::Interface::vtable(this).#vname)(windows_core::Interface::as_raw(this), #args #return_arg)
.map(|| result__.assume_init())
if noexcept {
quote! {
let mut result__ = core::mem::MaybeUninit::zeroed();
let hresult__ = #vcall;
debug_assert!(hresult__.0 == 0);
result__.assume_init()
}
} else {
quote! {
let mut result__ = core::mem::MaybeUninit::zeroed();
#vcall
.map(|| result__.assume_init())
}
}
}
_ => {
let map = if metadata::type_is_blittable(&signature.return_type) {
quote! { map(||result__) }
} else {
quote! { and_then(|| windows_core::Type::from_abi(result__)) }
};

quote! {
if noexcept {
if metadata::type_is_blittable(&signature.return_type) {
quote! {
let mut result__ = core::mem::zeroed();
let hresult__ = #vcall;
debug_assert!(hresult__.0 == 0);
result__ }
} else {
quote! {
let mut result__ = core::mem::zeroed();
let hresult__ = #vcall;
debug_assert!(hresult__.0 == 0);
core::mem::transmute(result__) }
}
} else if metadata::type_is_blittable(&signature.return_type) {
quote! {
let mut result__ = core::mem::zeroed();
(windows_core::Interface::vtable(this).#vname)(windows_core::Interface::as_raw(this), #args #return_arg)
.#map
#vcall
.map(||result__) }
} else {
quote! { let mut result__ = core::mem::zeroed();
#vcall.and_then(|| windows_core::Type::from_abi(result__)) }
}
}
};

match kind {
metadata::InterfaceKind::Default => quote! {
#features
pub fn #name<#generics>(&self, #params) -> windows_core::Result<#return_type_tokens> #where_clause {
pub fn #name<#generics>(&self, #params) #return_type_tokens #where_clause {
let this = self;
unsafe {
#vcall
Expand All @@ -90,7 +133,7 @@ pub fn writer(
| metadata::InterfaceKind::Overridable => {
quote! {
#features
pub fn #name<#generics>(&self, #params) -> windows_core::Result<#return_type_tokens> #where_clause {
pub fn #name<#generics>(&self, #params) #return_type_tokens #where_clause {
let this = &windows_core::Interface::cast::<#interface_name>(self)?;
unsafe {
#vcall
Expand All @@ -101,7 +144,7 @@ pub fn writer(
metadata::InterfaceKind::Static => {
quote! {
#features
pub fn #name<#generics>(#params) -> windows_core::Result<#return_type_tokens> #where_clause {
pub fn #name<#generics>(#params) #return_type_tokens #where_clause {
Self::#interface_name(|this| unsafe { #vcall })
}
}
Expand Down Expand Up @@ -189,31 +232,53 @@ pub fn gen_upcall(
inner: TokenStream,
this: bool,
) -> TokenStream {
let noexcept = metadata::method_def_is_noexcept(sig.def);

let invoke_args = sig
.params
.iter()
.map(|param| gen_winrt_invoke_arg(writer, param));

let this = if this {
quote! { this, }
} else {
quote! {}
};

match &sig.return_type {
metadata::Type::Void => quote! {
#inner(#this #(#invoke_args,)*).into()
},
metadata::Type::Void => {
if noexcept {
quote! {
#inner(#this #(#invoke_args,)*);
windows_core::HRESULT(0)
}
} else {
quote! {
#inner(#this #(#invoke_args,)*).into()
}
}
}
_ if sig.return_type.is_winrt_array() => {
quote! {
match #inner(#this #(#invoke_args,)*) {
Ok(ok__) => {
let (ok_data__, ok_data_len__) = ok__.into_abi();
// use `core::ptr::write` since `result` could be uninitialized
core::ptr::write(result__, ok_data__);
core::ptr::write(result_size__, ok_data_len__);
windows_core::HRESULT(0)
if noexcept {
quote! {
let ok__ = #inner(#this #(#invoke_args,)*);
let (ok_data__, ok_data_len__) = ok__.into_abi();
core::ptr::write(result__, ok_data__);
core::ptr::write(result_size__, ok_data_len__);
windows_core::HRESULT(0)
}
} else {
quote! {
match #inner(#this #(#invoke_args,)*) {
Ok(ok__) => {
let (ok_data__, ok_data_len__) = ok__.into_abi();
// use `core::ptr::write` since `result` could be uninitialized
core::ptr::write(result__, ok_data__);
core::ptr::write(result_size__, ok_data_len__);
windows_core::HRESULT(0)
}
Err(err) => err.into()
}
Err(err) => err.into()
}
}
}
Expand All @@ -224,15 +289,25 @@ pub fn gen_upcall(
quote! { core::mem::forget(ok__); }
};

quote! {
match #inner(#this #(#invoke_args,)*) {
Ok(ok__) => {
// use `core::ptr::write` since `result` could be uninitialized
core::ptr::write(result__, core::mem::transmute_copy(&ok__));
#forget
windows_core::HRESULT(0)
if noexcept {
quote! {
let ok__ = #inner(#this #(#invoke_args,)*);
// use `core::ptr::write` since `result` could be uninitialized
core::ptr::write(result__, core::mem::transmute_copy(&ok__));
#forget
windows_core::HRESULT(0)
}
} else {
quote! {
match #inner(#this #(#invoke_args,)*) {
Ok(ok__) => {
// use `core::ptr::write` since `result` could be uninitialized
core::ptr::write(result__, core::mem::transmute_copy(&ok__));
#forget
windows_core::HRESULT(0)
}
Err(err) => err.into()
}
Err(err) => err.into()
}
}
}
Expand Down
33 changes: 23 additions & 10 deletions crates/libs/bindgen/src/rust/writer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1284,31 +1284,44 @@ impl Writer {
.contains(metadata::TypeAttributes::WindowsRuntime)
{
let is_delegate = def.kind() == metadata::TypeKind::Delegate;
let noexcept = metadata::method_def_is_noexcept(signature.def);

let params = signature
.params
.iter()
.map(|p| self.winrt_produce_type(p, !is_delegate));

let return_type = match &signature.return_type {
metadata::Type::Void => quote! { () },
_ => {
let tokens = self.type_name(&signature.return_type);
let return_type_tokens = if signature.return_type == metadata::Type::Void {
quote! { () }
} else {
let tokens = self.type_name(&signature.return_type);

if signature.return_type.is_winrt_array() {
quote! { windows_core::Array<#tokens> }
} else {
tokens
}
if signature.return_type.is_winrt_array() {
quote! { windows_core::Array<#tokens> }
} else {
tokens
}
};

let return_type_tokens = if noexcept {
if metadata::type_is_nullable(&signature.return_type) {
quote! { -> Option<#return_type_tokens> }
} else if signature.return_type == metadata::Type::Void {
quote! {}
} else {
quote! { -> #return_type_tokens }
}
} else {
quote! { -> windows_core::Result<#return_type_tokens> }
};

let this = if is_delegate {
quote! {}
} else {
quote! { &self, }
};

quote! { (#this #(#params),*) -> windows_core::Result<#return_type> }
quote! { (#this #(#params),*) #return_type_tokens }
} else {
let signature_kind = signature.kind();
let mut params = quote! {};
Expand Down
12 changes: 4 additions & 8 deletions crates/libs/windows/src/Windows/UI/UIAutomation/Core/impl.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
pub trait ICoreAutomationConnectionBoundObjectProvider_Impl: Sized {
fn IsComThreadingRequired(&self) -> windows_core::Result<bool>;
fn IsComThreadingRequired(&self) -> bool;
}
impl windows_core::RuntimeName for ICoreAutomationConnectionBoundObjectProvider {
const NAME: &'static str = "Windows.UI.UIAutomation.Core.ICoreAutomationConnectionBoundObjectProvider";
Expand All @@ -9,13 +9,9 @@ impl ICoreAutomationConnectionBoundObjectProvider_Vtbl {
unsafe extern "system" fn IsComThreadingRequired<Identity: windows_core::IUnknownImpl<Impl = Impl>, Impl: ICoreAutomationConnectionBoundObjectProvider_Impl, const OFFSET: isize>(this: *mut core::ffi::c_void, result__: *mut bool) -> windows_core::HRESULT {
let this = (this as *const *const ()).offset(OFFSET) as *const Identity;
let this = (*this).get_impl();
match ICoreAutomationConnectionBoundObjectProvider_Impl::IsComThreadingRequired(this) {
Ok(ok__) => {
core::ptr::write(result__, core::mem::transmute_copy(&ok__));
windows_core::HRESULT(0)
}
Err(err) => err.into(),
}
let ok__ = ICoreAutomationConnectionBoundObjectProvider_Impl::IsComThreadingRequired(this);
core::ptr::write(result__, core::mem::transmute_copy(&ok__));
windows_core::HRESULT(0)
}
Self {
base__: windows_core::IInspectable_Vtbl::new::<Identity, ICoreAutomationConnectionBoundObjectProvider, OFFSET>(),
Expand Down
6 changes: 4 additions & 2 deletions crates/libs/windows/src/Windows/UI/UIAutomation/Core/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,13 @@ impl core::ops::Deref for ICoreAutomationConnectionBoundObjectProvider {
}
windows_core::imp::interface_hierarchy!(ICoreAutomationConnectionBoundObjectProvider, windows_core::IUnknown, windows_core::IInspectable);
impl ICoreAutomationConnectionBoundObjectProvider {
pub fn IsComThreadingRequired(&self) -> windows_core::Result<bool> {
pub fn IsComThreadingRequired(&self) -> bool {
let this = self;
unsafe {
let mut result__ = core::mem::zeroed();
(windows_core::Interface::vtable(this).IsComThreadingRequired)(windows_core::Interface::as_raw(this), &mut result__).map(|| result__)
let hresult__ = (windows_core::Interface::vtable(this).IsComThreadingRequired)(windows_core::Interface::as_raw(this), &mut result__);
debug_assert!(hresult__.0 == 0);
result__
}
}
}
Expand Down
12 changes: 8 additions & 4 deletions crates/libs/windows/src/Windows/UI/UIAutomation/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,11 +44,13 @@ pub struct IAutomationTextRange_Vtbl {
pub struct AutomationConnection(windows_core::IUnknown);
windows_core::imp::interface_hierarchy!(AutomationConnection, windows_core::IUnknown, windows_core::IInspectable);
impl AutomationConnection {
pub fn IsRemoteSystem(&self) -> windows_core::Result<bool> {
pub fn IsRemoteSystem(&self) -> bool {
let this = self;
unsafe {
let mut result__ = core::mem::zeroed();
(windows_core::Interface::vtable(this).IsRemoteSystem)(windows_core::Interface::as_raw(this), &mut result__).map(|| result__)
let hresult__ = (windows_core::Interface::vtable(this).IsRemoteSystem)(windows_core::Interface::as_raw(this), &mut result__);
debug_assert!(hresult__.0 == 0);
result__
}
}
pub fn AppUserModelId(&self) -> windows_core::Result<windows_core::HSTRING> {
Expand Down Expand Up @@ -108,11 +110,13 @@ unsafe impl Sync for AutomationConnectionBoundObject {}
pub struct AutomationElement(windows_core::IUnknown);
windows_core::imp::interface_hierarchy!(AutomationElement, windows_core::IUnknown, windows_core::IInspectable);
impl AutomationElement {
pub fn IsRemoteSystem(&self) -> windows_core::Result<bool> {
pub fn IsRemoteSystem(&self) -> bool {
let this = self;
unsafe {
let mut result__ = core::mem::zeroed();
(windows_core::Interface::vtable(this).IsRemoteSystem)(windows_core::Interface::as_raw(this), &mut result__).map(|| result__)
let hresult__ = (windows_core::Interface::vtable(this).IsRemoteSystem)(windows_core::Interface::as_raw(this), &mut result__);
debug_assert!(hresult__.0 == 0);
result__
}
}
pub fn AppUserModelId(&self) -> windows_core::Result<windows_core::HSTRING> {
Expand Down
Loading

0 comments on commit 21d17ab

Please sign in to comment.