diff options
Diffstat (limited to 'vendor/windows-bindgen/src/winrt_methods.rs')
-rw-r--r-- | vendor/windows-bindgen/src/winrt_methods.rs | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/vendor/windows-bindgen/src/winrt_methods.rs b/vendor/windows-bindgen/src/winrt_methods.rs new file mode 100644 index 000000000..457f70c38 --- /dev/null +++ b/vendor/windows-bindgen/src/winrt_methods.rs @@ -0,0 +1,258 @@ +use super::*; + +// TODO take Signature instead of MethodDef (wherever MethodDef is found) +pub fn gen( + gen: &Gen, + def: TypeDef, + generic_types: &[Type], + kind: InterfaceKind, + method: MethodDef, + method_names: &mut MethodNames, + virtual_names: &mut MethodNames, +) -> TokenStream { + let signature = gen.reader.method_def_signature(method, generic_types); + let params = &signature.params; + let name = method_names.add(gen, method); + let interface_name = gen.type_def_name(def, generic_types); + let vname = virtual_names.add(gen, method); + let generics = gen.constraint_generics(params); + let where_clause = gen.where_clause(params); + let mut cfg = gen.reader.signature_cfg(&signature); + gen.reader + .type_def_cfg_combine(def, generic_types, &mut cfg); + let doc = gen.cfg_method_doc(&cfg); + let features = gen.cfg_features(&cfg); + let args = gen_winrt_abi_args(gen, params); + let params = gen_winrt_params(gen, params); + + let return_type_tokens = if let Some(return_type) = &signature.return_type { + let tokens = gen.type_name(return_type); + if return_type.is_winrt_array() { + quote! { ::windows::core::Array<#tokens> } + } else { + quote! { #tokens } + } + } else { + quote! { () } + }; + + let return_arg = if let Some(return_type) = &signature.return_type { + if return_type.is_winrt_array() { + let return_type = gen.type_name(return_type); + quote! { ::windows::core::Array::<#return_type>::set_abi_len(::std::mem::transmute(&mut result__)), result__.as_mut_ptr() as *mut _ as _ } + } else { + quote! { &mut result__ } + } + } else { + quote! {} + }; + + let vcall = if let Some(return_type) = &signature.return_type { + if 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) + .and_then(|| result__.assume_init()) + } + } else { + let return_type = gen.type_name(return_type); + quote! { + let mut result__ = ::windows::core::zeroed::<#return_type>(); + (::windows::core::Interface::vtable(this).#vname)(::windows::core::Interface::as_raw(this), #args #return_arg) + .from_abi(result__) + } + } + } else { + quote! { + (::windows::core::Interface::vtable(this).#vname)(::windows::core::Interface::as_raw(this), #args).ok() + } + }; + + match kind { + InterfaceKind::Default => quote! { + #doc + #features + pub fn #name<#generics>(&self, #params) -> ::windows::core::Result<#return_type_tokens> #where_clause { + let this = self; + unsafe { + #vcall + } + } + }, + InterfaceKind::None | InterfaceKind::Base | InterfaceKind::Overridable => { + quote! { + #doc + #features + pub fn #name<#generics>(&self, #params) -> ::windows::core::Result<#return_type_tokens> #where_clause { + let this = &::windows::core::ComInterface::cast::<#interface_name>(self)?; + unsafe { + #vcall + } + } + } + } + InterfaceKind::Static => { + quote! { + #doc + #features + pub fn #name<#generics>(#params) -> ::windows::core::Result<#return_type_tokens> #where_clause { + Self::#interface_name(|this| unsafe { #vcall }) + } + } + } + } +} + +fn gen_winrt_params(gen: &Gen, params: &[SignatureParam]) -> TokenStream { + let mut result = quote! {}; + + let mut generic_params = gen.generic_params(params); + for param in params.iter() { + let name = gen.param_name(param.def); + let kind = gen.type_name(¶m.ty); + let default_type = gen.type_default_name(¶m.ty); + + if gen + .reader + .param_flags(param.def) + .contains(ParamAttributes::INPUT) + { + if param.ty.is_winrt_array() { + result.combine("e! { #name: &[#default_type], }); + } else if gen.reader.signature_param_is_convertible(param) { + let (position, _) = generic_params.next().unwrap(); + let kind: TokenStream = format!("P{position}").into(); + result.combine("e! { #name: #kind, }); + } else if gen.reader.type_is_blittable(¶m.ty) { + result.combine("e! { #name: #kind, }); + } else { + result.combine("e! { #name: &#kind, }); + } + } else if param.ty.is_winrt_array() { + result.combine("e! { #name: &mut [#default_type], }); + } else if param.ty.is_winrt_array_ref() { + result.combine("e! { #name: &mut ::windows::core::Array<#kind>, }); + } else { + result.combine("e! { #name: &mut #default_type, }); + } + } + + result +} + +fn gen_winrt_abi_args(gen: &Gen, params: &[SignatureParam]) -> TokenStream { + let mut tokens = TokenStream::new(); + for param in params { + let name = gen.param_name(param.def); + + let param = if gen + .reader + .param_flags(param.def) + .contains(ParamAttributes::INPUT) + { + if param.ty.is_winrt_array() { + if gen.reader.type_is_blittable(¶m.ty) { + quote! { #name.len() as u32, #name.as_ptr(), } + } else { + quote! { #name.len() as u32, ::core::mem::transmute(#name.as_ptr()), } + } + } else if gen.reader.signature_param_is_failible_param(param) { + quote! { #name.try_into_param()?.abi(), } + } else if gen.reader.signature_param_is_borrowed(param) { + quote! { #name.into_param().abi(), } + } else if gen.reader.type_is_blittable(¶m.ty) { + if param.ty.is_winrt_const_ref() { + quote! { &#name, } + } else { + quote! { #name, } + } + } else { + quote! { ::core::mem::transmute_copy(#name), } + } + } else if param.ty.is_winrt_array() { + if gen.reader.type_is_blittable(¶m.ty) { + quote! { #name.len() as u32, #name.as_mut_ptr(), } + } else { + quote! { #name.len() as u32, ::core::mem::transmute_copy(&#name), } + } + } else if param.ty.is_winrt_array_ref() { + quote! { #name.set_abi_len(), #name as *mut _ as _, } + } else if gen.reader.type_is_blittable(¶m.ty) { + quote! { #name, } + } else { + quote! { #name as *mut _ as _, } + }; + tokens.combine(¶m); + } + tokens +} + +pub fn gen_upcall(gen: &Gen, sig: &Signature, inner: TokenStream) -> TokenStream { + let invoke_args = sig + .params + .iter() + .map(|param| gen_winrt_invoke_arg(gen, param)); + + match &sig.return_type { + Some(return_type) if return_type.is_winrt_array() => { + quote! { + match #inner(#(#invoke_args,)*) { + ::core::result::Result::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) + } + ::core::result::Result::Err(err) => err.into() + } + } + } + Some(_) => { + quote! { + match #inner(#(#invoke_args,)*) { + ::core::result::Result::Ok(ok__) => { + // use `core::ptr::write` since `result` could be uninitialized + ::core::ptr::write(result__, ::core::mem::transmute_copy(&ok__)); + ::core::mem::forget(ok__); + ::windows::core::HRESULT(0) + } + ::core::result::Result::Err(err) => err.into() + } + } + } + None => quote! { + #inner(#(#invoke_args,)*).into() + }, + } +} + +fn gen_winrt_invoke_arg(gen: &Gen, param: &SignatureParam) -> TokenStream { + let name = gen.param_name(param.def); + let abi_size_name: TokenStream = + format!("{}_array_size", gen.reader.param_name(param.def)).into(); + + if gen + .reader + .param_flags(param.def) + .contains(ParamAttributes::INPUT) + { + if param.ty.is_winrt_array() { + quote! { ::core::slice::from_raw_parts(::core::mem::transmute_copy(&#name), #abi_size_name as _) } + } else if gen.reader.type_is_primitive(¶m.ty) { + quote! { #name } + } else if param.ty.is_winrt_const_ref() { + quote! { ::core::mem::transmute_copy(&#name) } + } else if gen.reader.type_is_nullable(¶m.ty) { + quote! { ::windows::core::from_raw_borrowed(&#name) } + } else { + quote! { ::core::mem::transmute(&#name) } + } + } else if param.ty.is_winrt_array() { + quote! { ::core::slice::from_raw_parts_mut(::core::mem::transmute_copy(&#name), #abi_size_name as _) } + } else if param.ty.is_winrt_array_ref() { + quote! { ::windows::core::ArrayProxy::from_raw_parts(::core::mem::transmute_copy(&#name), #abi_size_name).as_array() } + } else { + quote! { ::core::mem::transmute_copy(&#name) } + } +} |