diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 18:31:36 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 18:31:36 +0000 |
commit | e02c5b5930c2c9ba3e5423fe12e2ef0155017297 (patch) | |
tree | fd60ebbbb5299e16e5fca8c773ddb74f764760db /vendor/windows-bindgen/src | |
parent | Adding debian version 1.73.0+dfsg1-1. (diff) | |
download | rustc-e02c5b5930c2c9ba3e5423fe12e2ef0155017297.tar.xz rustc-e02c5b5930c2c9ba3e5423fe12e2ef0155017297.zip |
Merging upstream version 1.74.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/windows-bindgen/src')
77 files changed, 7973 insertions, 3131 deletions
diff --git a/vendor/windows-bindgen/src/args.rs b/vendor/windows-bindgen/src/args.rs new file mode 100644 index 000000000..74b2c6ed7 --- /dev/null +++ b/vendor/windows-bindgen/src/args.rs @@ -0,0 +1,45 @@ +use crate::Result; + +pub fn expand<I, S>(args: I) -> Result<Vec<String>> +where + I: IntoIterator<Item = S>, + S: AsRef<str>, +{ + let mut result = vec![]; + from_iter(&mut result, args)?; + Ok(result) +} + +fn from_string(result: &mut Vec<String>, value: &str) -> Result<()> { + let value = if let Some((value, _)) = value.split_once('#') { value } else { value }; + + from_iter(result, value.split_whitespace().map(|arg| arg.to_string()))?; + Ok(()) +} + +fn from_iter<I, S>(result: &mut Vec<String>, args: I) -> Result<()> +where + I: IntoIterator<Item = S>, + S: AsRef<str>, +{ + let mut expand = false; + + for arg in args.into_iter().map(|arg| arg.as_ref().to_string()) { + if arg.starts_with('-') { + expand = false; + } + if expand { + for args in crate::read_file_lines(&arg)? { + if !args.starts_with("//") { + from_string(result, &args)?; + } + } + } else if arg == "--etc" { + expand = true; + } else { + result.push(arg); + } + } + + Ok(()) +} diff --git a/vendor/windows-bindgen/src/classes.rs b/vendor/windows-bindgen/src/classes.rs deleted file mode 100644 index 3cdf50006..000000000 --- a/vendor/windows-bindgen/src/classes.rs +++ /dev/null @@ -1,215 +0,0 @@ -use super::*; - -pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream { - if gen.sys { - if gen.reader.type_def_has_default_interface(def) { - let name = to_ident(gen.reader.type_def_name(def)); - quote! { - pub type #name = *mut ::core::ffi::c_void; - } - } else { - quote! {} - } - } else { - gen_class(gen, def) - } -} - -fn gen_class(gen: &Gen, def: TypeDef) -> TokenStream { - if gen.reader.type_def_extends(def) == TypeName::Attribute { - return TokenStream::new(); - } - - let name = to_ident(gen.reader.type_def_name(def)); - let interfaces = gen - .reader - .type_interfaces(&Type::TypeDef((def, Vec::new()))); - let mut methods = quote! {}; - let mut method_names = MethodNames::new(); - - let cfg = gen.reader.type_def_cfg(def, &[]); - let doc = gen.cfg_doc(&cfg); - let features = gen.cfg_features(&cfg); - - for interface in &interfaces { - if let Type::TypeDef((def, generics)) = &interface.ty { - let mut virtual_names = MethodNames::new(); - - for method in gen.reader.type_def_methods(*def) { - methods.combine(&winrt_methods::gen( - gen, - *def, - generics, - interface.kind, - method, - &mut method_names, - &mut virtual_names, - )); - } - } - } - - let factories = interfaces.iter().filter_map(|interface| match interface.kind { - InterfaceKind::Static => { - if let Type::TypeDef((def, generics)) = &interface.ty { - if gen.reader.type_def_methods(*def).next().is_some() { - let interface_type = gen.type_name(&interface.ty); - let features = gen.cfg_features(&gen.reader.type_def_cfg(*def, generics)); - - let hidden = if gen.doc { - quote! { #[doc(hidden)] } - } else { - quote! {} - }; - - return Some(quote! { - #hidden - #features - pub fn #interface_type<R, F: FnOnce(&#interface_type) -> ::windows::core::Result<R>>( - callback: F, - ) -> ::windows::core::Result<R> { - static SHARED: ::windows::imp::FactoryCache<#name, #interface_type> = - ::windows::imp::FactoryCache::new(); - SHARED.call(callback) - } - }); - } - } - None - } - _ => None, - }); - - if gen.reader.type_def_has_default_interface(def) { - let new = if gen.reader.type_def_has_default_constructor(def) { - quote! { - pub fn new() -> ::windows::core::Result<Self> { - Self::IActivationFactory(|f| f.ActivateInstance::<Self>()) - } - fn IActivationFactory<R, F: FnOnce(&::windows::imp::IGenericFactory) -> ::windows::core::Result<R>>( - callback: F, - ) -> ::windows::core::Result<R> { - static SHARED: ::windows::imp::FactoryCache<#name, ::windows::imp::IGenericFactory> = - ::windows::imp::FactoryCache::new(); - SHARED.call(callback) - } - } - } else { - quote! {} - }; - - let mut tokens = quote! { - #doc - #features - #[repr(transparent)] - pub struct #name(::windows::core::IUnknown); - #features - impl #name { - #new - #methods - #(#factories)* - } - }; - - tokens.combine(&gen.interface_core_traits( - def, - &[], - &name, - &TokenStream::new(), - &TokenStream::new(), - &features, - )); - tokens.combine(&gen.interface_winrt_trait( - def, - &[], - &name, - &TokenStream::new(), - &TokenStream::new(), - &features, - )); - tokens.combine(&gen.interface_trait(def, &[], &name, &TokenStream::new(), &features, true)); - tokens.combine(&gen.runtime_name_trait(def, &[], &name, &TokenStream::new(), &features)); - tokens.combine(&gen.async_get( - def, - &[], - &name, - &TokenStream::new(), - &TokenStream::new(), - &features, - )); - tokens.combine(&iterators::gen( - gen, - def, - &[], - &name, - &TokenStream::new(), - &TokenStream::new(), - &cfg, - )); - tokens.combine(&gen_conversions(gen, def, &name, &interfaces, &cfg)); - tokens.combine(&gen.agile(def, &name, &TokenStream::new(), &features)); - tokens - } else { - let mut tokens = quote! { - #doc - #features - pub struct #name; - #features - impl #name { - #methods - #(#factories)* - } - }; - - tokens.combine(&gen.runtime_name_trait(def, &[], &name, &TokenStream::new(), &features)); - tokens - } -} - -fn gen_conversions( - gen: &Gen, - def: TypeDef, - name: &TokenStream, - interfaces: &[Interface], - cfg: &Cfg, -) -> TokenStream { - let features = gen.cfg_features(cfg); - let mut tokens = quote! { - #features - ::windows::imp::interface_hierarchy!(#name, ::windows::core::IUnknown, ::windows::core::IInspectable); - }; - - for interface in interfaces { - if gen.reader.type_is_exclusive(&interface.ty) { - continue; - } - - if interface.kind != InterfaceKind::Default - && interface.kind != InterfaceKind::None - && interface.kind != InterfaceKind::Base - { - continue; - } - - let into = gen.type_name(&interface.ty); - // TODO: simplify - maybe provide + operator? - let features = gen.cfg_features(&cfg.union(&gen.reader.type_cfg(&interface.ty))); - - tokens.combine("e! { - #features - impl ::windows::core::CanTryInto<#into> for #name {} - }); - } - - for def in gen.reader.type_def_bases(def) { - let into = gen.type_def_name(def, &[]); - let features = gen.cfg_features(&cfg.union(&gen.reader.type_def_cfg(def, &[]))); - - tokens.combine("e! { - #features - impl ::windows::core::CanTryInto<#into> for #name {} - }); - } - - tokens -} diff --git a/vendor/windows-bindgen/src/com_methods.rs b/vendor/windows-bindgen/src/com_methods.rs deleted file mode 100644 index cb59b9d64..000000000 --- a/vendor/windows-bindgen/src/com_methods.rs +++ /dev/null @@ -1,238 +0,0 @@ -use super::*; - -pub fn gen( - gen: &Gen, - def: TypeDef, - kind: InterfaceKind, - method: MethodDef, - method_names: &mut MethodNames, - virtual_names: &mut MethodNames, - base_count: usize, -) -> TokenStream { - let signature = gen.reader.method_def_signature(method, &[]); - let name = method_names.add(gen, method); - let vname = virtual_names.add(gen, method); - let generics = gen.constraint_generics(&signature.params); - let where_clause = gen.where_clause(&signature.params); - let mut cfg = gen.reader.signature_cfg(&signature); - cfg.add_feature(gen.reader.type_def_namespace(def)); - let doc = gen.cfg_method_doc(&cfg); - let features = gen.cfg_features(&cfg); - - if kind == InterfaceKind::None { - return quote! {}; - } - - let mut bases = quote! {}; - - for _ in 0..base_count { - bases.combine("e! { .base__ }); - } - - let kind = gen.reader.signature_kind(&signature); - match kind { - SignatureKind::Query(_) => { - let args = gen.win32_args(&signature.params, kind); - let params = gen.win32_params(&signature.params, kind); - let generics = expand_generics(generics, quote!(T)); - let where_clause = - expand_where_clause(where_clause, quote!(T: ::windows::core::ComInterface)); - - quote! { - #doc - #features - pub unsafe fn #name<#generics>(&self, #params) -> ::windows::core::Result<T> #where_clause { - let mut result__ = ::std::ptr::null_mut(); - (::windows::core::Interface::vtable(self)#bases.#vname)(::windows::core::Interface::as_raw(self), #args).from_abi(result__) - } - } - } - SignatureKind::QueryOptional(_) => { - let args = gen.win32_args(&signature.params, kind); - let params = gen.win32_params(&signature.params, kind); - let generics = expand_generics(generics, quote!(T)); - let where_clause = - expand_where_clause(where_clause, quote!(T: ::windows::core::ComInterface)); - - quote! { - #doc - #features - pub unsafe fn #name<#generics>(&self, #params result__: *mut ::core::option::Option<T>) -> ::windows::core::Result<()> #where_clause { - (::windows::core::Interface::vtable(self)#bases.#vname)(::windows::core::Interface::as_raw(self), #args).ok() - } - } - } - SignatureKind::ResultValue => { - let args = gen.win32_args(&signature.params, kind); - let params = gen.win32_params(&signature.params, kind); - let return_type = signature.params[signature.params.len() - 1].ty.deref(); - let return_type = gen.type_name(&return_type); - - quote! { - #doc - #features - pub unsafe fn #name<#generics>(&self, #params) -> ::windows::core::Result<#return_type> #where_clause { - let mut result__ = ::windows::core::zeroed::<#return_type>(); - (::windows::core::Interface::vtable(self)#bases.#vname)(::windows::core::Interface::as_raw(self), #args).from_abi(result__) - } - } - } - SignatureKind::ResultVoid => { - let args = gen.win32_args(&signature.params, kind); - let params = gen.win32_params(&signature.params, kind); - - quote! { - #doc - #features - pub unsafe fn #name<#generics>(&self, #params) -> ::windows::core::Result<()> #where_clause { - (::windows::core::Interface::vtable(self)#bases.#vname)(::windows::core::Interface::as_raw(self), #args).ok() - } - } - } - SignatureKind::ReturnValue => { - let args = gen.win32_args(&signature.params, kind); - let params = gen.win32_params(&signature.params, kind); - let return_type = signature.params[signature.params.len() - 1].ty.deref(); - let is_nullable = gen.reader.type_is_nullable(&return_type); - let return_type = gen.type_name(&return_type); - - if is_nullable { - quote! { - #doc - #features - pub unsafe fn #name<#generics>(&self, #params) -> ::windows::core::Result<#return_type> #where_clause { - let mut result__ = ::windows::core::zeroed::<#return_type>(); - (::windows::core::Interface::vtable(self)#bases.#vname)(::windows::core::Interface::as_raw(self), #args); - ::windows::core::from_abi(result__) - } - } - } else { - quote! { - #doc - #features - pub unsafe fn #name<#generics>(&self, #params) -> #return_type #where_clause { - let mut result__ = ::windows::core::zeroed::<#return_type>(); - (::windows::core::Interface::vtable(self)#bases.#vname)(::windows::core::Interface::as_raw(self), #args); - ::std::mem::transmute(result__) - } - } - } - } - SignatureKind::ReturnStruct => { - let args = gen.win32_args(&signature.params, kind); - let params = gen.win32_params(&signature.params, kind); - let return_type = gen.type_name(&signature.return_type.unwrap()); - - quote! { - #doc - #features - pub unsafe fn #name<#generics>(&self, #params) -> #return_type #where_clause { - let mut result__: #return_type = ::core::mem::zeroed(); - (::windows::core::Interface::vtable(self)#bases.#vname)(::windows::core::Interface::as_raw(self), &mut result__, #args); - result__ - } - } - } - SignatureKind::PreserveSig => { - let args = gen.win32_args(&signature.params, kind); - let params = gen.win32_params(&signature.params, kind); - let return_type = gen.return_sig(&signature); - - quote! { - #doc - #features - pub unsafe fn #name<#generics>(&self, #params) #return_type #where_clause { - (::windows::core::Interface::vtable(self)#bases.#vname)(::windows::core::Interface::as_raw(self), #args) - } - } - } - SignatureKind::ReturnVoid => { - let args = gen.win32_args(&signature.params, kind); - let params = gen.win32_params(&signature.params, kind); - - quote! { - #doc - #features - pub unsafe fn #name<#generics>(&self, #params) #where_clause { - (::windows::core::Interface::vtable(self)#bases.#vname)(::windows::core::Interface::as_raw(self), #args) - } - } - } - } -} - -pub fn gen_upcall(gen: &Gen, sig: &Signature, inner: TokenStream) -> TokenStream { - match gen.reader.signature_kind(sig) { - SignatureKind::ResultValue => { - let invoke_args = sig.params[..sig.params.len() - 1] - .iter() - .map(|param| gen_win32_invoke_arg(gen, param)); - - let result = gen.param_name(sig.params[sig.params.len() - 1].def); - - quote! { - match #inner(#(#invoke_args,)*) { - ::core::result::Result::Ok(ok__) => { - // use `core::ptr::write` since the result could be uninitialized - ::core::ptr::write(#result, ::core::mem::transmute(ok__)); - ::windows::core::HRESULT(0) - } - ::core::result::Result::Err(err) => err.into() - } - } - } - SignatureKind::Query(_) | SignatureKind::QueryOptional(_) | SignatureKind::ResultVoid => { - let invoke_args = sig - .params - .iter() - .map(|param| gen_win32_invoke_arg(gen, param)); - - quote! { - #inner(#(#invoke_args,)*).into() - } - } - SignatureKind::ReturnStruct => { - let invoke_args = sig - .params - .iter() - .map(|param| gen_win32_invoke_arg(gen, param)); - - quote! { - *result__ = #inner(#(#invoke_args,)*) - } - } - _ => { - let invoke_args = sig - .params - .iter() - .map(|param| gen_win32_invoke_arg(gen, param)); - - quote! { - #inner(#(#invoke_args,)*) - } - } - } -} - -fn gen_win32_invoke_arg(gen: &Gen, param: &SignatureParam) -> TokenStream { - let name = gen.param_name(param.def); - - if gen - .reader - .param_flags(param.def) - .contains(ParamAttributes::INPUT) - && gen.reader.type_is_nullable(¶m.ty) - { - quote! { ::windows::core::from_raw_borrowed(&#name) } - } else if (!param.ty.is_pointer() && gen.reader.type_is_nullable(¶m.ty)) - || (gen - .reader - .param_flags(param.def) - .contains(ParamAttributes::INPUT) - && !gen.reader.type_is_primitive(¶m.ty)) - { - quote! { ::core::mem::transmute(&#name) } - } else { - quote! { ::core::mem::transmute_copy(&#name) } - } -} diff --git a/vendor/windows-bindgen/src/delegates.rs b/vendor/windows-bindgen/src/delegates.rs deleted file mode 100644 index a68719c81..000000000 --- a/vendor/windows-bindgen/src/delegates.rs +++ /dev/null @@ -1,181 +0,0 @@ -use super::*; - -pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream { - if gen - .reader - .type_def_flags(def) - .contains(TypeAttributes::WINRT) - { - gen_delegate(gen, def) - } else { - gen_callback(gen, def) - } -} - -fn gen_callback(gen: &Gen, def: TypeDef) -> TokenStream { - let name = to_ident(gen.reader.type_def_name(def)); - - let method = gen.reader.type_def_invoke_method(def); - let signature = gen.reader.method_def_signature(method, &[]); - let return_type = gen.return_sig(&signature); - let cfg = gen.reader.type_def_cfg(def, &[]); - let doc = gen.cfg_doc(&cfg); - let features = gen.cfg_features(&cfg); - - let params = signature.params.iter().map(|p| { - let name = gen.param_name(p.def); - let tokens = gen.type_default_name(&p.ty); - quote! { #name: #tokens } - }); - - quote! { - #doc - #features - pub type #name = ::core::option::Option<unsafe extern "system" fn(#(#params),*) #return_type>; - } -} - -fn gen_delegate(gen: &Gen, def: TypeDef) -> TokenStream { - if gen.sys { - let name = to_ident(gen.reader.type_def_name(def)); - quote! { - pub type #name = *mut ::core::ffi::c_void; - } - } else { - gen_win_delegate(gen, def) - } -} - -fn gen_win_delegate(gen: &Gen, def: TypeDef) -> TokenStream { - let name = to_ident(gen.reader.type_def_name(def)); - let vtbl = name.join("_Vtbl"); - let boxed = name.join("Box"); - - let generics: &Vec<Type> = &gen.reader.type_def_generics(def).collect(); - let phantoms = gen.generic_phantoms(generics); - let named_phantoms = gen.generic_named_phantoms(generics); - let constraints = gen.generic_constraints(generics); - let generic_names = gen.generic_names(generics); - - let ident = gen.type_def_name(def, generics); - - let method = gen.reader.type_def_invoke_method(def); - let signature = gen.reader.method_def_signature(method, generics); - let fn_constraint = gen_fn_constraint(gen, def, &signature); - - let cfg = gen.reader.type_def_cfg(def, generics); - let doc = gen.cfg_doc(&cfg); - let features = gen.cfg_features(&cfg); - - let vtbl_signature = gen.vtbl_signature(def, generics, &signature); - let invoke = winrt_methods::gen( - gen, - def, - generics, - InterfaceKind::Default, - method, - &mut MethodNames::new(), - &mut MethodNames::new(), - ); - let invoke_upcall = winrt_methods::gen_upcall(gen, &signature, quote! { ((*this).invoke) }); - - let mut tokens = quote! { - #doc - #features - #[repr(transparent)] - pub struct #ident(pub ::windows::core::IUnknown, #phantoms) where #constraints; - #features - impl<#constraints> #ident { - pub fn new<#fn_constraint>(invoke: F) -> Self { - let com = #boxed::<#generic_names F> { - vtable: &#boxed::<#generic_names F>::VTABLE, - count: ::windows::imp::RefCount::new(1), - invoke, - }; - unsafe { - ::core::mem::transmute(::std::boxed::Box::new(com)) - } - } - #invoke - } - #features - #[repr(C)] - struct #boxed<#generic_names #fn_constraint> where #constraints { - vtable: *const #vtbl<#generic_names>, - invoke: F, - count: ::windows::imp::RefCount, - } - #features - impl<#constraints #fn_constraint> #boxed<#generic_names F> { - const VTABLE: #vtbl<#generic_names> = #vtbl::<#generic_names>{ - base__: ::windows::core::IUnknown_Vtbl{QueryInterface: Self::QueryInterface, AddRef: Self::AddRef, Release: Self::Release}, - Invoke: Self::Invoke, - #(#named_phantoms)* - }; - unsafe extern "system" fn QueryInterface(this: *mut ::core::ffi::c_void, iid: &::windows::core::GUID, interface: *mut *const ::core::ffi::c_void) -> ::windows::core::HRESULT { - let this = this as *mut *mut ::core::ffi::c_void as *mut Self; - - *interface = if iid == &<#ident as ::windows::core::ComInterface>::IID || - iid == &<::windows::core::IUnknown as ::windows::core::ComInterface>::IID || - iid == &<::windows::imp::IAgileObject as ::windows::core::ComInterface>::IID { - &mut (*this).vtable as *mut _ as _ - } else { - ::core::ptr::null_mut() - }; - - // TODO: implement IMarshal - - if (*interface).is_null() { - ::windows::core::HRESULT(-2147467262) // E_NOINTERFACE - } else { - (*this).count.add_ref(); - ::windows::core::HRESULT(0) - } - } - unsafe extern "system" fn AddRef(this: *mut ::core::ffi::c_void) -> u32 { - let this = this as *mut *mut ::core::ffi::c_void as *mut Self; - (*this).count.add_ref() - } - unsafe extern "system" fn Release(this: *mut ::core::ffi::c_void) -> u32 { - let this = this as *mut *mut ::core::ffi::c_void as *mut Self; - let remaining = (*this).count.release(); - - if remaining == 0 { - let _ = ::std::boxed::Box::from_raw(this); - } - - remaining - } - unsafe extern "system" fn Invoke #vtbl_signature { - let this = this as *mut *mut ::core::ffi::c_void as *mut Self; - #invoke_upcall - } - } - }; - - tokens.combine(&gen.interface_core_traits( - def, - generics, - &ident, - &constraints, - &phantoms, - &features, - )); - tokens.combine(&gen.interface_trait(def, generics, &ident, &constraints, &features, true)); - tokens.combine(&gen.interface_winrt_trait( - def, - generics, - &ident, - &constraints, - &phantoms, - &features, - )); - tokens.combine(&gen.interface_vtbl(def, generics, &ident, &constraints, &features)); - tokens -} - -fn gen_fn_constraint(gen: &Gen, def: TypeDef, signature: &Signature) -> TokenStream { - let signature = gen.impl_signature(def, signature); - - quote! { F: FnMut #signature + ::core::marker::Send + 'static } -} diff --git a/vendor/windows-bindgen/src/error.rs b/vendor/windows-bindgen/src/error.rs new file mode 100644 index 000000000..6d783d084 --- /dev/null +++ b/vendor/windows-bindgen/src/error.rs @@ -0,0 +1,55 @@ +pub type Result<T> = std::result::Result<T, Error>; + +#[derive(Default, Debug)] +pub struct Error { + message: String, + path: String, + span: Option<(usize, usize)>, +} + +impl std::error::Error for Error {} + +impl From<Error> for std::io::Error { + fn from(error: Error) -> Self { + std::io::Error::new(std::io::ErrorKind::Other, error.message.as_str()) + } +} + +impl From<syn::Error> for Error { + fn from(error: syn::Error) -> Self { + let start = error.span().start(); + Self { message: error.to_string(), span: Some((start.line, start.column)), ..Self::default() } + } +} + +impl std::fmt::Display for Error { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + writeln!(fmt, "error: {}", self.message)?; + if !self.path.is_empty() { + if let Some((line, column)) = self.span { + writeln!(fmt, " --> {}:{line}:{column}", self.path)?; + } else { + writeln!(fmt, " --> {}", self.path)?; + } + } + Ok(()) + } +} + +impl Error { + pub(crate) fn new(message: &str) -> Self { + Self { message: message.to_string(), ..Self::default() } + } + + pub(crate) fn with_path(self, path: &str) -> Self { + Self { path: path.to_string(), ..self } + } + + // pub(crate) fn with_span(self, span: proc_macro2::Span) -> Self { + // let start = span.start(); + // Self { + // span: Some((start.line, start.column)), + // ..self + // } + // } +} diff --git a/vendor/windows-bindgen/src/extensions/mod.rs b/vendor/windows-bindgen/src/extensions/mod.rs deleted file mode 100644 index 9b0b6942e..000000000 --- a/vendor/windows-bindgen/src/extensions/mod.rs +++ /dev/null @@ -1,57 +0,0 @@ -use super::*; - -pub fn gen_mod(gen: &Gen, namespace: &str) -> TokenStream { - if namespace == "Windows.Win32.UI.WindowsAndMessaging" { - return include_str!("mod/Win32/UI/WindowsAndMessaging/WindowLong.rs").into(); - } - - if gen.sys { - return "".into(); - } - - match namespace { - "Windows.Foundation.Numerics" => concat!( - include_str!("mod/Foundation/Numerics/Matrix3x2.rs"), - include_str!("mod/Foundation/Numerics/Matrix4x4.rs"), - include_str!("mod/Foundation/Numerics/Vector2.rs"), - include_str!("mod/Foundation/Numerics/Vector3.rs"), - include_str!("mod/Foundation/Numerics/Vector4.rs"), - ), - "Windows.Foundation" => concat!( - include_str!("mod/Foundation/IInspectable.rs"), - include_str!("mod/Foundation/PropertyValue.rs"), - include_str!("mod/Foundation/TimeSpan.rs"), - ), - "Windows.Win32.Foundation" => concat!( - include_str!("mod/Win32/Foundation/BOOL.rs"), - include_str!("mod/Win32/Foundation/BOOLEAN.rs"), - include_str!("mod/Win32/Foundation/NTSTATUS.rs"), - include_str!("mod/Win32/Foundation/VARIANT_BOOL.rs"), - include_str!("mod/Win32/Foundation/WIN32_ERROR.rs"), - ), - "Windows.Win32.Networking.WinSock" => concat!( - include_str!("mod/Win32/Networking/WinSock/IN_ADDR.rs"), - include_str!("mod/Win32/Networking/WinSock/IN6_ADDR.rs"), - include_str!("mod/Win32/Networking/WinSock/SOCKADDR_IN.rs"), - include_str!("mod/Win32/Networking/WinSock/SOCKADDR_IN6.rs"), - include_str!("mod/Win32/Networking/WinSock/SOCKADDR_INET.rs"), - ), - "Windows.Win32.UI.WindowsAndMessaging" => { - include_str!("mod/Win32/UI/WindowsAndMessaging/WindowLong.rs") - } - _ => "", - } - .into() -} - -pub fn gen_impl(namespace: &str) -> TokenStream { - match namespace { - "Windows.Foundation.Collections" => concat!( - include_str!("impl/Foundation/Collections/Iterable.rs"), - include_str!("impl/Foundation/Collections/MapView.rs"), - include_str!("impl/Foundation/Collections/VectorView.rs"), - ), - _ => "", - } - .into() -} diff --git a/vendor/windows-bindgen/src/extensions/mod/Foundation/IInspectable.rs b/vendor/windows-bindgen/src/extensions/mod/Foundation/IInspectable.rs deleted file mode 100644 index c8ddabdbb..000000000 --- a/vendor/windows-bindgen/src/extensions/mod/Foundation/IInspectable.rs +++ /dev/null @@ -1,13 +0,0 @@ -impl std::fmt::Debug for windows::core::IInspectable { - fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - // Attempts to retrieve the string representation of the object via the - // IStringable interface. If that fails, it will use the canonical type - // name to give some idea of what the object represents. - let name = - <windows::core::IInspectable as windows::core::ComInterface>::cast::<IStringable>(self) - .and_then(|s| s.ToString()) - .or_else(|_| self.GetRuntimeClassName()) - .unwrap_or_default(); - write!(f, "\"{}\"", name) - } -} diff --git a/vendor/windows-bindgen/src/extensions/mod/Foundation/PropertyValue.rs b/vendor/windows-bindgen/src/extensions/mod/Foundation/PropertyValue.rs deleted file mode 100644 index d9a1f113e..000000000 --- a/vendor/windows-bindgen/src/extensions/mod/Foundation/PropertyValue.rs +++ /dev/null @@ -1,71 +0,0 @@ -macro_rules! primitive_boxed_type { - ($(($t:ty, $m:ident)),+) => { - $(impl std::convert::TryFrom<$t> for windows::core::IInspectable { - type Error = windows::core::Error; - fn try_from(value: $t) -> windows::core::Result<Self> { - PropertyValue::$m(value) - } - } - impl std::convert::TryFrom<windows::core::IInspectable> for $t { - type Error = windows::core::Error; - fn try_from(value: windows::core::IInspectable) -> windows::core::Result<Self> { - <windows::core::IInspectable as windows::core::ComInterface>::cast::<IReference<$t>>(&value)?.Value() - } - } - impl std::convert::TryFrom<&windows::core::IInspectable> for $t { - type Error = windows::core::Error; - fn try_from(value: &windows::core::IInspectable) -> windows::core::Result<Self> { - <windows::core::IInspectable as windows::core::ComInterface>::cast::<IReference<$t>>(value)?.Value() - } - })* - }; -} -primitive_boxed_type! { - (bool, CreateBoolean), - (u8, CreateUInt8), - (i16, CreateInt16), - (u16, CreateUInt16), - (i32, CreateInt32), - (u32, CreateUInt32), - (i64, CreateInt64), - (u64, CreateUInt64), - (f32, CreateSingle), - (f64, CreateDouble) -} -impl std::convert::TryFrom<&str> for windows::core::IInspectable { - type Error = windows::core::Error; - fn try_from(value: &str) -> windows::core::Result<Self> { - let value: windows::core::HSTRING = value.into(); - PropertyValue::CreateString(&value) - } -} -impl std::convert::TryFrom<windows::core::HSTRING> for windows::core::IInspectable { - type Error = windows::core::Error; - fn try_from(value: windows::core::HSTRING) -> windows::core::Result<Self> { - PropertyValue::CreateString(&value) - } -} -impl std::convert::TryFrom<&windows::core::HSTRING> for windows::core::IInspectable { - type Error = windows::core::Error; - fn try_from(value: &windows::core::HSTRING) -> windows::core::Result<Self> { - PropertyValue::CreateString(value) - } -} -impl std::convert::TryFrom<windows::core::IInspectable> for windows::core::HSTRING { - type Error = windows::core::Error; - fn try_from(value: windows::core::IInspectable) -> windows::core::Result<Self> { - <windows::core::IInspectable as windows::core::ComInterface>::cast::< - IReference<windows::core::HSTRING>, - >(&value)? - .Value() - } -} -impl std::convert::TryFrom<&windows::core::IInspectable> for windows::core::HSTRING { - type Error = windows::core::Error; - fn try_from(value: &windows::core::IInspectable) -> windows::core::Result<Self> { - <windows::core::IInspectable as windows::core::ComInterface>::cast::< - IReference<windows::core::HSTRING>, - >(value)? - .Value() - } -} diff --git a/vendor/windows-bindgen/src/extensions/mod/Win32/Foundation/NTSTATUS.rs b/vendor/windows-bindgen/src/extensions/mod/Win32/Foundation/NTSTATUS.rs deleted file mode 100644 index 66d77db19..000000000 --- a/vendor/windows-bindgen/src/extensions/mod/Win32/Foundation/NTSTATUS.rs +++ /dev/null @@ -1,32 +0,0 @@ -impl NTSTATUS { - #[inline] - pub const fn is_ok(self) -> bool { - self.0 >= 0 - } - #[inline] - pub const fn is_err(self) -> bool { - !self.is_ok() - } - #[inline] - pub const fn to_hresult(self) -> ::windows::core::HRESULT { - ::windows::core::HRESULT(self.0 | 0x1000_0000) - } - #[inline] - pub const fn ok(self) -> ::windows::core::Result<()> { - if self.is_ok() { - Ok(()) - } else { - Err(::windows::core::Error { code: self.to_hresult(), info: None }) - } - } -} -impl ::core::convert::From<NTSTATUS> for ::windows::core::HRESULT { - fn from(value: NTSTATUS) -> Self { - value.to_hresult() - } -} -impl ::core::convert::From<NTSTATUS> for ::windows::core::Error { - fn from(value: NTSTATUS) -> Self { - Self { code: value.to_hresult(), info: None } - } -} diff --git a/vendor/windows-bindgen/src/functions.rs b/vendor/windows-bindgen/src/functions.rs deleted file mode 100644 index f5ec866bb..000000000 --- a/vendor/windows-bindgen/src/functions.rs +++ /dev/null @@ -1,285 +0,0 @@ -use super::*; - -pub fn gen(gen: &Gen, def: MethodDef) -> TokenStream { - if gen.sys { - gen_sys_function(gen, def) - } else { - gen_win_function(gen, def) - } -} - -fn gen_sys_function(gen: &Gen, def: MethodDef) -> TokenStream { - let signature = gen.reader.method_def_signature(def, &[]); - let cfg = gen.reader.signature_cfg(&signature); - let mut tokens = gen.cfg_features(&cfg); - tokens.combine(&gen_link(gen, &signature, &cfg)); - tokens -} - -fn gen_win_function(gen: &Gen, def: MethodDef) -> TokenStream { - let name = to_ident(gen.reader.method_def_name(def)); - let signature = gen.reader.method_def_signature(def, &[]); - let generics = gen.constraint_generics(&signature.params); - let where_clause = gen.where_clause(&signature.params); - let abi_return_type = gen.return_sig(&signature); - let cfg = gen.reader.signature_cfg(&signature); - let doc = gen.cfg_doc(&cfg); - let features = gen.cfg_features(&cfg); - let link = gen_link(gen, &signature, &cfg); - - let kind = gen.reader.signature_kind(&signature); - match kind { - SignatureKind::Query(_) => { - let args = gen.win32_args(&signature.params, kind); - let params = gen.win32_params(&signature.params, kind); - let generics = expand_generics(generics, quote!(T)); - let where_clause = - expand_where_clause(where_clause, quote!(T: ::windows::core::ComInterface)); - - quote! { - #doc - #features - #[inline] - pub unsafe fn #name<#generics>(#params) -> ::windows::core::Result<T> #where_clause { - #link - let mut result__ = ::std::ptr::null_mut(); - #name(#args).from_abi(result__) - } - } - } - SignatureKind::QueryOptional(_) => { - let args = gen.win32_args(&signature.params, kind); - let params = gen.win32_params(&signature.params, kind); - let generics = expand_generics(generics, quote!(T)); - let where_clause = - expand_where_clause(where_clause, quote!(T: ::windows::core::ComInterface)); - - quote! { - #doc - #features - #[inline] - pub unsafe fn #name<#generics>(#params result__: *mut ::core::option::Option<T>) -> ::windows::core::Result<()> #where_clause { - #link - #name(#args).ok() - } - } - } - SignatureKind::ResultValue => { - let args = gen.win32_args(&signature.params, kind); - let params = gen.win32_params(&signature.params, kind); - let return_type = signature.params[signature.params.len() - 1].ty.deref(); - let return_type = gen.type_name(&return_type); - - quote! { - #doc - #features - #[inline] - pub unsafe fn #name<#generics>(#params) -> ::windows::core::Result<#return_type> #where_clause { - #link - let mut result__ = ::windows::core::zeroed::<#return_type>(); - #name(#args).from_abi(result__) - } - } - } - SignatureKind::ResultVoid => { - let args = gen.win32_args(&signature.params, kind); - let params = gen.win32_params(&signature.params, kind); - - quote! { - #doc - #features - #[inline] - pub unsafe fn #name<#generics>(#params) -> ::windows::core::Result<()> #where_clause { - #link - #name(#args).ok() - } - } - } - SignatureKind::ReturnValue => { - let args = gen.win32_args(&signature.params, kind); - let params = gen.win32_params(&signature.params, kind); - let return_type = signature.params[signature.params.len() - 1].ty.deref(); - let is_nullable = gen.reader.type_is_nullable(&return_type); - let return_type = gen.type_name(&return_type); - - if is_nullable { - quote! { - #doc - #features - #[inline] - pub unsafe fn #name<#generics>(#params) -> ::windows::core::Result<#return_type> #where_clause { - #link - let mut result__ = ::windows::core::zeroed::<#return_type>(); - #name(#args); - ::windows::core::from_abi(result__.assume_init()) - } - } - } else { - quote! { - #doc - #features - #[inline] - pub unsafe fn #name<#generics>(#params) -> #return_type #where_clause { - #link - let mut result__ = ::windows::core::zeroed::<#return_type>(); - #name(#args); - ::std::mem::transmute(result__) - } - } - } - } - SignatureKind::ReturnStruct | SignatureKind::PreserveSig => { - if handle_last_error(gen, def, &signature) { - let args = gen.win32_args(&signature.params, kind); - let params = gen.win32_params(&signature.params, kind); - let return_type = gen.type_name(&signature.return_type.unwrap()); - - quote! { - #doc - #features - #[inline] - pub unsafe fn #name<#generics>(#params) -> ::windows::core::Result<#return_type> #where_clause { - #link - let result__ = #name(#args); - ::windows::imp::then(!result__.is_invalid(), ||result__).ok_or_else(::windows::core::Error::from_win32) - } - } - } else { - let args = gen.win32_args(&signature.params, kind); - let params = gen.win32_params(&signature.params, kind); - - quote! { - #doc - #features - #[inline] - pub unsafe fn #name<#generics>(#params) #abi_return_type #where_clause { - #link - #name(#args) - } - } - } - } - SignatureKind::ReturnVoid => { - let args = gen.win32_args(&signature.params, kind); - let params = gen.win32_params(&signature.params, kind); - let does_not_return = does_not_return(gen, def); - - quote! { - #doc - #features - #[inline] - pub unsafe fn #name<#generics>(#params) #does_not_return #where_clause { - #link - #name(#args) - } - } - } - } -} - -fn gen_link(gen: &Gen, signature: &Signature, cfg: &Cfg) -> TokenStream { - let name = gen.reader.method_def_name(signature.def); - let ident = to_ident(name); - let library = gen.reader.method_def_module_name(signature.def); - let abi = gen.reader.method_def_extern_abi(signature.def); - - let symbol = if let Some(impl_map) = gen.reader.method_def_impl_map(signature.def) { - gen.reader.impl_map_import_name(impl_map) - } else { - name - }; - - let link_name = if symbol != name { - quote! { #[link_name = #symbol] } - } else { - quote! {} - }; - - let params = signature.params.iter().map(|p| { - let name = gen.param_name(p.def); - let tokens = if p.kind == SignatureParamKind::ValueType { - gen.type_default_name(&p.ty) - } else { - gen.type_abi_name(&p.ty) - }; - quote! { #name: #tokens } - }); - - let return_type = gen.return_sig(signature); - - if gen.std || !gen.namespace.starts_with("Windows.") { - let library = library.trim_end_matches(".dll"); - - quote! { - #[link(name = #library)] - extern #abi { - #link_name - pub fn #ident(#(#params),*) #return_type; - } - } - } else if let Some(library) = gen.reader.method_def_static_lib(signature.def) { - quote! { - #[link(name = #library, kind = "static")] - extern #abi { - #link_name - pub fn #ident(#(#params),*) #return_type; - } - } - } else { - let symbol = if symbol != name { - format!(" \"{symbol}\"") - } else { - String::new() - }; - - let doc = if gen.sys { - gen.cfg_doc(cfg).0 - } else { - String::new() - }; - - let mut tokens = String::new(); - for param in params { - tokens.push_str(&format!("{}, ", param.as_str())); - } - let tokens = tokens.trim_end_matches(", "); - format!( - r#"::windows_targets::link!("{library}" "{abi}"{symbol}{doc} fn {name}({tokens}){return_type});"# - ) - .into() - } -} - -fn does_not_return(gen: &Gen, def: MethodDef) -> TokenStream { - if gen.reader.method_def_does_not_return(def) { - quote! { -> ! } - } else { - quote! {} - } -} - -fn handle_last_error(gen: &Gen, def: MethodDef, signature: &Signature) -> bool { - if let Some(map) = gen.reader.method_def_impl_map(def) { - if gen - .reader - .impl_map_flags(map) - .contains(PInvokeAttributes::LAST_ERROR) - { - if let Some(Type::TypeDef((return_type, _))) = &signature.return_type { - if gen.reader.type_def_is_handle(*return_type) { - if gen - .reader - .type_def_underlying_type(*return_type) - .is_pointer() - { - return true; - } - if !gen.reader.type_def_invalid_values(*return_type).is_empty() { - return true; - } - } - } - } - } - false -} diff --git a/vendor/windows-bindgen/src/interfaces.rs b/vendor/windows-bindgen/src/interfaces.rs deleted file mode 100644 index 1643e7798..000000000 --- a/vendor/windows-bindgen/src/interfaces.rs +++ /dev/null @@ -1,224 +0,0 @@ -use super::*; - -pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream { - if gen.sys { - gen_sys_interface(gen, def) - } else { - gen_win_interface(gen, def) - } -} - -fn gen_sys_interface(gen: &Gen, def: TypeDef) -> TokenStream { - let name = gen.reader.type_def_name(def); - let ident = to_ident(name); - - if gen.reader.type_def_is_exclusive(def) { - quote! {} - } else { - quote! { - pub type #ident = *mut ::core::ffi::c_void; - } - } -} - -fn gen_win_interface(gen: &Gen, def: TypeDef) -> TokenStream { - let generics: &Vec<Type> = &gen.reader.type_def_generics(def).collect(); - let ident = gen.type_def_name(def, generics); - let is_exclusive = gen.reader.type_def_is_exclusive(def); - let phantoms = gen.generic_phantoms(generics); - let constraints = gen.generic_constraints(generics); - let cfg = gen.reader.type_def_cfg(def, &[]); - let doc = gen.cfg_doc(&cfg); - let features = gen.cfg_features(&cfg); - let interfaces = gen - .reader - .type_interfaces(&Type::TypeDef((def, generics.to_vec()))); - let vtables = gen.reader.type_def_vtables(def); - let has_unknown_base = matches!(vtables.first(), Some(Type::IUnknown)); - - let mut tokens = if is_exclusive { - quote! { #[doc(hidden)] } - } else { - quote! { #doc } - }; - - if has_unknown_base { - tokens.combine("e! { - #features - #[repr(transparent)] - pub struct #ident(::windows::core::IUnknown, #phantoms) where #constraints; - }); - } else { - tokens.combine("e! { - #features - #[repr(transparent)] - pub struct #ident(::std::ptr::NonNull<::std::ffi::c_void>); - }); - } - - if !is_exclusive { - let mut methods = quote! {}; - // We need to distinguish between public and virtual methods because some WinRT type hierarchies inherit colliding (overloaded) - // methods that must be distinguishable. - let method_names = &mut MethodNames::new(); - let virtual_names = &mut MethodNames::new(); - - if gen - .reader - .type_def_flags(def) - .contains(TypeAttributes::WINRT) - { - for method in gen.reader.type_def_methods(def) { - methods.combine(&winrt_methods::gen( - gen, - def, - generics, - InterfaceKind::Default, - method, - method_names, - virtual_names, - )); - } - for interface in &interfaces { - if let Type::TypeDef((def, generics)) = &interface.ty { - for method in gen.reader.type_def_methods(*def) { - methods.combine(&winrt_methods::gen( - gen, - *def, - generics, - InterfaceKind::None, - method, - method_names, - virtual_names, - )); - } - } - } - } else { - let mut bases = vtables.len(); - for ty in &vtables { - match ty { - Type::IUnknown | Type::IInspectable => {} - Type::TypeDef((def, _)) => { - let kind = if gen.reader.type_def_type_name(*def) == TypeName::IDispatch { - InterfaceKind::None - } else { - InterfaceKind::Default - }; - for method in gen.reader.type_def_methods(*def) { - methods.combine(&com_methods::gen( - gen, - *def, - kind, - method, - method_names, - virtual_names, - bases, - )); - } - } - _ => unimplemented!(), - } - - bases -= 1; - } - for method in gen.reader.type_def_methods(def) { - methods.combine(&com_methods::gen( - gen, - def, - InterfaceKind::Default, - method, - method_names, - virtual_names, - 0, - )); - } - } - - tokens.combine("e! { - #features - impl<#constraints> #ident { - #methods - } - }); - - if !vtables.is_empty() && generics.is_empty() { - let mut hierarchy = format!("::windows::imp::interface_hierarchy!({ident}"); - let mut hierarchy_cfg = cfg.clone(); - - for ty in &vtables { - let into = gen.type_name(ty); - - write!(&mut hierarchy, ", {into}").unwrap(); - hierarchy_cfg = hierarchy_cfg.union(&gen.reader.type_cfg(ty)); - } - - hierarchy.push_str(");"); - tokens.combine(&gen.cfg_features(&hierarchy_cfg)); - tokens.push_str(&hierarchy); - } else { - for ty in &vtables { - let into = gen.type_name(ty); - let cfg = gen.cfg_features(&cfg.union(&gen.reader.type_cfg(ty))); - tokens.combine("e! { - #cfg - impl<#constraints> windows::core::CanInto<#into> for #ident {} - }); - } - } - - if gen - .reader - .type_def_flags(def) - .contains(TypeAttributes::WINRT) - { - for interface in &interfaces { - let into = gen.type_name(&interface.ty); - let cfg = gen.cfg_features(&cfg.union(&gen.reader.type_cfg(&interface.ty))); - tokens.combine("e! { - #cfg - impl<#constraints> windows::core::CanTryInto<#into> for #ident {} - }); - } - } - - tokens.combine(&gen.interface_core_traits( - def, - generics, - &ident, - &constraints, - &phantoms, - &features, - )); - tokens.combine(&gen.interface_winrt_trait( - def, - generics, - &ident, - &constraints, - &phantoms, - &features, - )); - tokens.combine(&gen.async_get(def, generics, &ident, &constraints, &phantoms, &features)); - tokens.combine(&iterators::gen( - gen, - def, - generics, - &ident, - &constraints, - &phantoms, - &cfg, - )); - tokens.combine(&gen.agile(def, &ident, &constraints, &features)); - } - - tokens.combine(&gen.interface_trait( - def, - generics, - &ident, - &constraints, - &features, - has_unknown_base, - )); - tokens.combine(&gen.interface_vtbl(def, generics, &ident, &constraints, &features)); - tokens -} diff --git a/vendor/windows-bindgen/src/lib.rs b/vendor/windows-bindgen/src/lib.rs index 0957a4f64..c9eec0e95 100644 --- a/vendor/windows-bindgen/src/lib.rs +++ b/vendor/windows-bindgen/src/lib.rs @@ -1,225 +1,268 @@ -/*! -Learn more about Rust for Windows here: <https://github.com/microsoft/windows-rs> -*/ - -mod classes; -mod com_methods; -mod constants; -mod delegates; -mod enums; -mod extensions; -mod functions; -mod gen; -mod handles; -mod implements; -mod interfaces; -mod iterators; -mod method_names; -mod standalone; -mod structs; -mod try_format; -mod winrt_methods; - -use metadata::reader::*; -use method_names::*; -pub use standalone::*; -use std::collections::*; -use std::fmt::Write; -use tokens::*; -use try_format::*; - -#[doc(hidden)] -pub use gen::*; - -#[doc(hidden)] -pub fn namespace(gen: &Gen, tree: &Tree) -> String { - let mut tokens = TokenStream::new(); - - if tree.namespace == "Windows" || !tree.namespace.starts_with("Windows.") { - tokens.combine(&allow()); - } - - for (name, tree) in &tree.nested { - let name = to_ident(name); - let namespace = tree.namespace[tree.namespace.find('.').unwrap() + 1..].replace('.', "_"); - if !gen.component { - tokens.combine("e! { #[cfg(feature = #namespace)] }); - } - tokens.combine("e! { pub mod #name; }); - } +mod args; +mod error; +mod metadata; +mod rdl; +mod rust; +mod tokens; +mod tree; +mod winmd; - let mut functions = BTreeMap::<&str, TokenStream>::new(); - let mut types = BTreeMap::<TypeKind, BTreeMap<&str, TokenStream>>::new(); +pub use error::{Error, Result}; +use tree::Tree; - for method in gen.reader.namespace_functions(tree.namespace) { - let name = gen.reader.method_def_name(method); - functions - .entry(name) - .or_default() - .combine(&functions::gen(gen, method)); - } +enum ArgKind { + None, + Input, + Output, + Filter, + Config, +} - for field in gen.reader.namespace_constants(tree.namespace) { - let name = gen.reader.field_name(field); - types - .entry(TypeKind::Class) - .or_default() - .entry(name) - .or_default() - .combine(&constants::gen(gen, field)); - } +pub fn bindgen<I, S>(args: I) -> Result<String> +where + I: IntoIterator<Item = S>, + S: AsRef<str>, +{ + let time = std::time::Instant::now(); + let args = args::expand(args)?; - for def in gen - .reader - .namespace_types(tree.namespace, &Default::default()) - { - let type_name = gen.reader.type_def_type_name(def); - if REMAP_TYPES.iter().any(|(x, _)| x == &type_name) { - continue; - } - if CORE_TYPES.iter().any(|(x, _)| x == &type_name) { - continue; + let mut kind = ArgKind::None; + let mut output = None; + let mut input = Vec::<&str>::new(); + let mut include = Vec::<&str>::new(); + let mut exclude = Vec::<&str>::new(); + let mut config = std::collections::BTreeMap::<&str, &str>::new(); + let mut format = false; + + for arg in &args { + if arg.starts_with('-') { + kind = ArgKind::None; } - let name = type_name.name; - let kind = gen.reader.type_def_kind(def); + match kind { - TypeKind::Class => { - if gen - .reader - .type_def_flags(def) - .contains(TypeAttributes::WINRT) - { - types - .entry(kind) - .or_default() - .insert(name, classes::gen(gen, def)); + ArgKind::None => match arg.as_str() { + "-i" | "--in" => kind = ArgKind::Input, + "-o" | "--out" => kind = ArgKind::Output, + "-f" | "--filter" => kind = ArgKind::Filter, + "--config" => kind = ArgKind::Config, + "--format" => format = true, + _ => return Err(Error::new(&format!("invalid option `{arg}`"))), + }, + ArgKind::Output => { + if output.is_none() { + output = Some(arg.as_str()); + } else { + return Err(Error::new("too many outputs")); } } - TypeKind::Interface => types - .entry(kind) - .or_default() - .entry(name) - .or_default() - .combine(&interfaces::gen(gen, def)), - TypeKind::Enum => types - .entry(kind) - .or_default() - .entry(name) - .or_default() - .combine(&enums::gen(gen, def)), - TypeKind::Struct => { - if gen.reader.type_def_fields(def).next().is_none() { - if let Some(guid) = gen.reader.type_def_guid(def) { - let ident = to_ident(name); - let value = gen.guid(&guid); - let guid = gen.type_name(&Type::GUID); - let cfg = gen.reader.type_def_cfg(def, &[]); - let doc = gen.cfg_doc(&cfg); - let constant = quote! { - #doc - pub const #ident: #guid = #value; - }; - types - .entry(TypeKind::Class) - .or_default() - .entry(name) - .or_default() - .combine(&constant); - continue; - } + ArgKind::Input => input.push(arg.as_str()), + ArgKind::Filter => { + if let Some(rest) = arg.strip_prefix('!') { + exclude.push(rest); + } else { + include.push(arg.as_str()); + } + } + ArgKind::Config => { + if let Some((key, value)) = arg.split_once('=') { + config.insert(key, value); + } else { + config.insert(arg, ""); } - types - .entry(kind) - .or_default() - .entry(name) - .or_default() - .combine(&structs::gen(gen, def)); } - TypeKind::Delegate => types - .entry(kind) - .or_default() - .entry(name) - .or_default() - .combine(&delegates::gen(gen, def)), } } - for function in functions.values() { - tokens.combine(function); + if format { + if output.is_some() || !include.is_empty() || !exclude.is_empty() { + return Err(Error::new("`--format` cannot be combined with `--out` or `--filter`")); + } + + let input = filter_input(&input, &["rdl"])?; + + if input.is_empty() { + return Err(Error::new("no .rdl inputs")); + } + + for path in &input { + read_file_text(path).and_then(|source| rdl::File::parse_str(&source)).and_then(|file| write_to_file(path, file.fmt())).map_err(|err| err.with_path(path))?; + } + + return Ok(String::new()); } - for ty in types.values().flat_map(|v| v.values()) { - tokens.combine(ty); + let Some(output) = output else { + return Err(Error::new("no output")); + }; + + // This isn't strictly necessary but avoids a common newbie pitfall where all metadata + // would be generated when building a component for a specific API. + if include.is_empty() { + return Err(Error::new("at least one `--filter` must be specified")); + } + + let output = canonicalize(output)?; + + let input = read_input(&input)?; + let reader = metadata::Reader::new(&input); + let filter = metadata::Filter::new(&include, &exclude); + + winmd::verify(&reader, &filter)?; + + match extension(&output) { + "rdl" => rdl::from_reader(&reader, &filter, config, &output)?, + "winmd" => winmd::from_reader(&reader, &filter, config, &output)?, + "rs" => rust::from_reader(&reader, &filter, config, &output)?, + _ => return Err(Error::new("output extension must be one of winmd/rdl/rs")), } - tokens.combine(&extensions::gen_mod(gen, tree.namespace)); - try_format(tokens.into_string()) + let elapsed = time.elapsed().as_secs_f32(); + + if elapsed > 0.1 { + Ok(format!(" Finished writing `{}` in {:.2}s", output, time.elapsed().as_secs_f32())) + } else { + Ok(format!(" Finished writing `{}`", output,)) + } } -#[doc(hidden)] -pub fn namespace_impl(gen: &Gen, tree: &Tree) -> String { - let mut types = BTreeMap::<&str, TokenStream>::new(); - - for def in gen - .reader - .namespace_types(tree.namespace, &Default::default()) - { - let type_name = gen.reader.type_def_type_name(def); - if CORE_TYPES.iter().any(|(x, _)| x == &type_name) { - continue; +fn filter_input(input: &[&str], extensions: &[&str]) -> Result<Vec<String>> { + fn try_push(path: &str, extensions: &[&str], results: &mut Vec<String>) -> Result<()> { + // First canonicalize input so that the extension check below will match the case of the path. + let path = canonicalize(path)?; + + if extensions.contains(&extension(&path)) { + results.push(path); } - if gen.reader.type_def_kind(def) != TypeKind::Interface { - continue; + + Ok(()) + } + + let mut results = vec![]; + + for input in input { + let path = std::path::Path::new(input); + + if !path.exists() { + return Err(Error::new("failed to read input").with_path(input)); } - let tokens = implements::gen(gen, def); - if !tokens.is_empty() { - types.insert(type_name.name, tokens); + if path.is_dir() { + for entry in path.read_dir().map_err(|_| Error::new("failed to read directory").with_path(input))?.flatten() { + let path = entry.path(); + + if path.is_file() { + try_push(&path.to_string_lossy(), extensions, &mut results)?; + } + } + } else { + try_push(&path.to_string_lossy(), extensions, &mut results)?; } } + Ok(results) +} - let types = types.values(); +fn read_input(input: &[&str]) -> Result<Vec<metadata::File>> { + let input = filter_input(input, &["winmd", "rdl"])?; + let mut results = vec![]; - let mut tokens = quote! { - #(#types)* - }; + if cfg!(feature = "metadata") { + results.push(metadata::File::new(std::include_bytes!("../default/Windows.winmd").to_vec()).unwrap()); + results.push(metadata::File::new(std::include_bytes!("../default/Windows.Win32.winmd").to_vec()).unwrap()); + results.push(metadata::File::new(std::include_bytes!("../default/Windows.Wdk.winmd").to_vec()).unwrap()); + } else if input.is_empty() { + return Err(Error::new("no inputs")); + } + + for input in &input { + let file = if extension(input) == "winmd" { read_winmd_file(input)? } else { read_rdl_file(input)? }; + + results.push(file); + } - tokens.combine(&extensions::gen_impl(tree.namespace)); - try_format(tokens.into_string()) + Ok(results) } -/// Generates bindings for a specific component namespace. -pub fn component(namespace: &str, files: &[File]) -> String { - let reader = &Reader::new(files); - let tree = reader.tree(namespace, &Default::default()); - let mut gen = Gen::new(reader); - gen.namespace = tree.namespace; - gen.component = true; - let mut bindings = crate::namespace(&gen, &tree); - bindings.push_str(&namespace_impl(&gen, &tree)); - try_format(bindings) +fn read_file_text(path: &str) -> Result<String> { + std::fs::read_to_string(path).map_err(|_| Error::new("failed to read text file")) } -fn allow() -> TokenStream { - quote! { - #![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)] +fn read_file_bytes(path: &str) -> Result<Vec<u8>> { + std::fs::read(path).map_err(|_| Error::new("failed to read binary file")) +} + +fn read_file_lines(path: &str) -> Result<Vec<String>> { + use std::io::BufRead; + fn error(path: &str) -> Error { + Error::new("failed to read lines").with_path(path) } + let file = std::io::BufReader::new(std::fs::File::open(path).map_err(|_| error(path))?); + let mut lines = vec![]; + for line in file.lines() { + lines.push(line.map_err(|_| error(path))?); + } + Ok(lines) } -/// Expand a possibly empty generics list with a new generic -fn expand_generics(generics: TokenStream, new: TokenStream) -> TokenStream { - if generics.is_empty() { - quote!(#new) - } else { - quote!(#generics, #new) +fn read_rdl_file(path: &str) -> Result<metadata::File> { + read_file_text(path) + .and_then(|source| rdl::File::parse_str(&source)) + .and_then(|file| file.into_winmd()) + .map(|bytes| { + // TODO: Write bytes to file if you need to debug the intermediate .winmd file like so: + _ = write_to_file("temp.winmd", &bytes); + + // Unwrapping here is fine since `rdl_to_winmd` should have produced a valid winmd + metadata::File::new(bytes).unwrap() + }) + .map_err(|err| err.with_path(path)) +} + +fn read_winmd_file(path: &str) -> Result<metadata::File> { + read_file_bytes(path).and_then(|bytes| metadata::File::new(bytes).ok_or_else(|| Error::new("failed to read .winmd format").with_path(path))) +} + +fn write_to_file<C: AsRef<[u8]>>(path: &str, contents: C) -> Result<()> { + if let Some(parent) = std::path::Path::new(path).parent() { + std::fs::create_dir_all(parent).map_err(|_| Error::new("failed to create directory").with_path(path))?; + } + + std::fs::write(path, contents).map_err(|_| Error::new("failed to write file").with_path(path)) +} + +fn canonicalize(value: &str) -> Result<String> { + let temp = !std::path::Path::new(value).exists(); + + // `std::fs::canonicalize` only works if the file exists so we temporarily create it here. + if temp { + write_to_file(value, "")?; + } + + let path = std::fs::canonicalize(value).map_err(|_| Error::new("failed to find path").with_path(value))?; + + if temp { + std::fs::remove_file(value).map_err(|_| Error::new("failed to remove temporary file").with_path(value))?; + } + + let path = path.to_string_lossy().trim_start_matches(r"\\?\").to_string(); + + match path.rsplit_once('.') { + Some((file, extension)) => Ok(format!("{file}.{}", extension.to_lowercase())), + _ => Ok(path), } } -/// Expand a possibly emppty where clause with a new generic constraint -fn expand_where_clause(where_clause: TokenStream, generic: TokenStream) -> TokenStream { - if where_clause.is_empty() { - quote!(where #generic) +fn extension(path: &str) -> &str { + path.rsplit_once('.').map_or("", |(_, extension)| extension) +} + +fn directory(path: &str) -> &str { + path.rsplit_once(&['/', '\\']).map_or("", |(directory, _)| directory) +} + +fn trim_tick(name: &str) -> &str { + if name.as_bytes().iter().rev().nth(1) == Some(&b'`') { + &name[..name.len() - 2] } else { - quote!(#where_clause #generic) + name } } diff --git a/vendor/windows-bindgen/src/metadata/mod.rs b/vendor/windows-bindgen/src/metadata/mod.rs new file mode 100644 index 000000000..027a282ac --- /dev/null +++ b/vendor/windows-bindgen/src/metadata/mod.rs @@ -0,0 +1,926 @@ +use std::collections::*; +pub use windows_metadata::*; + +#[derive(Clone)] +pub struct Interface { + pub ty: Type, + pub kind: InterfaceKind, +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum InterfaceKind { + None, + Default, + Overridable, + Static, + Base, +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub struct QueryPosition { + pub object: usize, + pub guid: usize, +} + +#[derive(Copy, Clone, PartialEq, Eq)] +pub enum SignatureKind { + Query(QueryPosition), + QueryOptional(QueryPosition), + ResultValue, + ResultVoid, + ReturnStruct, + ReturnValue, + ReturnVoid, + PreserveSig, +} + +#[derive(Copy, Clone, Eq, PartialEq)] +pub enum SignatureParamKind { + ArrayFixed(usize), + ArrayRelativeLen(usize), + ArrayRelativeByteLen(usize), + ArrayRelativePtr(usize), + TryInto, + IntoParam, + OptionalPointer, + ValueType, + Blittable, + Other, +} + +impl SignatureParamKind { + fn is_array(&self) -> bool { + matches!(self, Self::ArrayFixed(_) | Self::ArrayRelativeLen(_) | Self::ArrayRelativeByteLen(_) | Self::ArrayRelativePtr(_)) + } +} + +pub struct Signature { + pub def: MethodDef, + pub params: Vec<SignatureParam>, + pub return_type: Type, + pub call_flags: MethodCallAttributes, +} + +pub struct SignatureParam { + pub def: Param, + pub ty: Type, + pub kind: SignatureParamKind, +} + +#[derive(PartialEq, Eq, Debug)] +pub enum AsyncKind { + None, + Action, + ActionWithProgress, + Operation, + OperationWithProgress, +} + +pub fn type_def_invoke_method(reader: &Reader, row: TypeDef) -> MethodDef { + reader.type_def_methods(row).find(|method| reader.method_def_name(*method) == "Invoke").expect("`Invoke` method not found") +} + +pub fn type_def_generics(reader: &Reader, def: TypeDef) -> Vec<Type> { + reader.type_def_generics(def).map(Type::GenericParam).collect() +} + +// TODO: namespace should not be required - it's a hack to accomodate Win32 metadata +// TODO: this is very Rust-specific and Win32-metadata specific with all of its translation. Replace with literal signature parser that just returns slice of types. +pub fn method_def_signature(reader: &Reader, namespace: &str, row: MethodDef, generics: &[Type]) -> Signature { + let mut blob = reader.row_blob(row, 4); + let call_flags = MethodCallAttributes(blob.read_usize() as u8); + let _param_count = blob.read_usize(); + let mut return_type = reader.type_from_blob(&mut blob, None, generics); + + let mut params: Vec<SignatureParam> = reader + .method_def_params(row) + .filter_map(|param| { + let param_is_const = reader.has_attribute(param, "ConstAttribute"); + if reader.param_sequence(param) == 0 { + if param_is_const { + return_type = return_type.clone().to_const_type(); + } + None + } else { + let is_output = reader.param_flags(param).contains(ParamAttributes::Out); + let mut ty = reader.type_from_blob(&mut blob, None, generics); + + if let Some(name) = param_or_enum(reader, param) { + let def = reader.get_type_def(TypeName::new(namespace, &name)).next().expect("Enum not found"); + ty = Type::PrimitiveOrEnum(Box::new(ty), Box::new(Type::TypeDef(def, Vec::new()))); + } + + if param_is_const || !is_output { + ty = ty.to_const_type(); + } + if !is_output { + ty = ty.to_const_ptr(); + } + let kind = param_kind(reader, param); + Some(SignatureParam { def: param, ty, kind }) + } + }) + .collect(); + + for position in 0..params.len() { + // Point len params back to the corresponding ptr params. + match params[position].kind { + SignatureParamKind::ArrayRelativeLen(relative) | SignatureParamKind::ArrayRelativeByteLen(relative) => { + // The len params must be input only. + if !reader.param_flags(params[relative].def).contains(ParamAttributes::Out) && position != relative && !params[relative].ty.is_pointer() { + params[relative].kind = SignatureParamKind::ArrayRelativePtr(position); + } else { + params[position].kind = SignatureParamKind::Other; + } + } + SignatureParamKind::ArrayFixed(_) => { + if reader.has_attribute(params[position].def, "FreeWithAttribute") { + params[position].kind = SignatureParamKind::Other; + } + } + _ => {} + } + } + + let mut sets = BTreeMap::<usize, Vec<usize>>::new(); + + // Finds sets of ptr params pointing at the same len param. + for (position, param) in params.iter().enumerate() { + match param.kind { + SignatureParamKind::ArrayRelativeLen(relative) | SignatureParamKind::ArrayRelativeByteLen(relative) => { + sets.entry(relative).or_default().push(position); + } + _ => {} + } + } + + // Remove all sets. + for (len, ptrs) in sets { + if ptrs.len() > 1 { + params[len].kind = SignatureParamKind::Other; + for ptr in ptrs { + params[ptr].kind = SignatureParamKind::Other; + } + } + } + + // Remove any byte arrays that aren't byte-sized types. + for position in 0..params.len() { + if let SignatureParamKind::ArrayRelativeByteLen(relative) = params[position].kind { + if !params[position].ty.is_byte_size() { + params[position].kind = SignatureParamKind::Other; + params[relative].kind = SignatureParamKind::Other; + } + } + } + + for param in &mut params { + if param.kind == SignatureParamKind::Other { + if signature_param_is_convertible(reader, param) { + if type_is_non_exclusive_winrt_interface(reader, ¶m.ty) { + param.kind = SignatureParamKind::TryInto; + } else { + param.kind = SignatureParamKind::IntoParam; + } + } else { + let flags = reader.param_flags(param.def); + if param.ty.is_pointer() && (flags.contains(ParamAttributes::Optional) || reader.has_attribute(param.def, "ReservedAttribute")) { + param.kind = SignatureParamKind::OptionalPointer; + } else if type_is_primitive(reader, ¶m.ty) && (!param.ty.is_pointer() || type_is_blittable(reader, ¶m.ty.deref())) { + param.kind = SignatureParamKind::ValueType; + } else if type_is_blittable(reader, ¶m.ty) { + param.kind = SignatureParamKind::Blittable; + } + } + } + } + + Signature { def: row, params, return_type, call_flags } +} + +fn param_kind(reader: &Reader, row: Param) -> SignatureParamKind { + for attribute in reader.attributes(row) { + match reader.attribute_name(attribute) { + "NativeArrayInfoAttribute" => { + for (_, value) in reader.attribute_args(attribute) { + match value { + Value::I16(value) => return SignatureParamKind::ArrayRelativeLen(value as usize), + Value::I32(value) => return SignatureParamKind::ArrayFixed(value as usize), + _ => {} + } + } + } + "MemorySizeAttribute" => { + for (_, value) in reader.attribute_args(attribute) { + if let Value::I16(value) = value { + return SignatureParamKind::ArrayRelativeByteLen(value as usize); + } + } + } + _ => {} + } + } + SignatureParamKind::Other +} + +// TODO: this is a terribly broken Win32 metadata attribute - need to get rid of it. +fn param_or_enum(reader: &Reader, row: Param) -> Option<String> { + reader.find_attribute(row, "AssociatedEnumAttribute").and_then(|attribute| { + for (_, arg) in reader.attribute_args(attribute) { + if let Value::String(name) = arg { + return Some(name); + } + } + None + }) +} + +pub fn signature_param_is_borrowed(reader: &Reader, param: &SignatureParam) -> bool { + type_is_borrowed(reader, ¶m.ty) +} + +pub fn signature_param_is_convertible(reader: &Reader, param: &SignatureParam) -> bool { + !reader.param_flags(param.def).contains(ParamAttributes::Out) && !param.ty.is_winrt_array() && !param.ty.is_pointer() && !param.kind.is_array() && (type_is_borrowed(reader, ¶m.ty) || type_is_non_exclusive_winrt_interface(reader, ¶m.ty) || type_is_trivially_convertible(reader, ¶m.ty)) +} + +fn signature_param_is_retval(reader: &Reader, param: &SignatureParam) -> bool { + // The Win32 metadata uses `RetValAttribute` to call out retval methods but it is employed + // very sparingly, so this heuristic is used to apply the transformation more uniformly. + if reader.has_attribute(param.def, "RetValAttribute") { + return true; + } + if !param.ty.is_pointer() { + return false; + } + if param.ty.is_void() { + return false; + } + let flags = reader.param_flags(param.def); + if flags.contains(ParamAttributes::In) || !flags.contains(ParamAttributes::Out) || flags.contains(ParamAttributes::Optional) || param.kind.is_array() { + return false; + } + if param_kind(reader, param.def).is_array() { + return false; + } + // If it's bigger than 128 bits, best to pass as a reference. + if reader.type_size(¶m.ty.deref()) > 16 { + return false; + } + // Win32 callbacks are defined as `Option<T>` so we don't include them here to avoid + // producing the `Result<Option<T>>` anti-pattern. + !type_is_callback(reader, ¶m.ty.deref()) +} + +pub fn signature_kind(reader: &Reader, signature: &Signature) -> SignatureKind { + if reader.has_attribute(signature.def, "CanReturnMultipleSuccessValuesAttribute") { + return SignatureKind::PreserveSig; + } + match &signature.return_type { + Type::Void if signature_is_retval(reader, signature) => SignatureKind::ReturnValue, + Type::Void => SignatureKind::ReturnVoid, + Type::HRESULT => { + if signature.params.len() >= 2 { + if let Some(guid) = signature_param_is_query_guid(reader, &signature.params) { + if let Some(object) = signature_param_is_query_object(reader, &signature.params) { + if reader.param_flags(signature.params[object].def).contains(ParamAttributes::Optional) { + return SignatureKind::QueryOptional(QueryPosition { object, guid }); + } else { + return SignatureKind::Query(QueryPosition { object, guid }); + } + } + } + } + if signature_is_retval(reader, signature) { + SignatureKind::ResultValue + } else { + SignatureKind::ResultVoid + } + } + Type::TypeDef(def, _) if reader.type_def_type_name(*def) == TypeName::NTSTATUS => SignatureKind::ResultVoid, + Type::TypeDef(def, _) if reader.type_def_type_name(*def) == TypeName::WIN32_ERROR => SignatureKind::ResultVoid, + Type::TypeDef(def, _) if reader.type_def_type_name(*def) == TypeName::BOOL && method_def_last_error(reader, signature.def) => SignatureKind::ResultVoid, + _ if type_is_struct(reader, &signature.return_type) => SignatureKind::ReturnStruct, + _ => SignatureKind::PreserveSig, + } +} + +fn signature_is_retval(reader: &Reader, signature: &Signature) -> bool { + signature.params.last().map_or(false, |param| signature_param_is_retval(reader, param)) + && signature.params[..signature.params.len() - 1].iter().all(|param| { + let flags = reader.param_flags(param.def); + !flags.contains(ParamAttributes::Out) + }) +} + +fn signature_param_is_query_guid(reader: &Reader, params: &[SignatureParam]) -> Option<usize> { + params.iter().rposition(|param| param.ty == Type::ConstPtr(Box::new(Type::GUID), 1) && !reader.param_flags(param.def).contains(ParamAttributes::Out)) +} + +fn signature_param_is_query_object(reader: &Reader, params: &[SignatureParam]) -> Option<usize> { + params.iter().rposition(|param| param.ty == Type::MutPtr(Box::new(Type::Void), 2) && reader.has_attribute(param.def, "ComOutPtrAttribute")) +} + +fn method_def_last_error(reader: &Reader, row: MethodDef) -> bool { + if let Some(map) = reader.method_def_impl_map(row) { + reader.impl_map_flags(map).contains(PInvokeAttributes::SupportsLastError) + } else { + false + } +} + +fn type_is_borrowed(reader: &Reader, ty: &Type) -> bool { + match ty { + Type::TypeDef(row, _) => !type_def_is_blittable(reader, *row), + Type::BSTR | Type::PCSTR | Type::PCWSTR | Type::IInspectable | Type::IUnknown | Type::GenericParam(_) => true, + _ => false, + } +} + +pub fn type_is_non_exclusive_winrt_interface(reader: &Reader, ty: &Type) -> bool { + match ty { + Type::TypeDef(row, _) => { + let flags = reader.type_def_flags(*row); + if !flags.contains(TypeAttributes::WindowsRuntime) { + false + } else { + match reader.type_def_kind(*row) { + TypeKind::Interface => !type_def_is_exclusive(reader, *row), + TypeKind::Class => reader.has_attribute(*row, "ComposableAttribute"), + _ => false, + } + } + } + _ => false, + } +} + +fn type_is_trivially_convertible(reader: &Reader, ty: &Type) -> bool { + match ty { + Type::TypeDef(row, _) => match reader.type_def_kind(*row) { + TypeKind::Struct => type_def_is_handle(reader, *row), + _ => false, + }, + Type::PCSTR | Type::PCWSTR => true, + _ => false, + } +} + +fn type_is_callback(reader: &Reader, ty: &Type) -> bool { + match ty { + Type::TypeDef(row, _) => type_def_is_callback(reader, *row), + _ => false, + } +} + +fn type_def_is_callback(reader: &Reader, row: TypeDef) -> bool { + !reader.type_def_flags(row).contains(TypeAttributes::WindowsRuntime) && reader.type_def_kind(row) == TypeKind::Delegate +} + +pub fn type_has_callback(reader: &Reader, ty: &Type) -> bool { + match ty { + Type::TypeDef(row, _) => type_def_has_callback(reader, *row), + Type::Win32Array(ty, _) => type_has_callback(reader, ty), + _ => false, + } +} +pub fn type_def_has_callback(reader: &Reader, row: TypeDef) -> bool { + if type_def_is_callback(reader, row) { + return true; + } + if reader.type_def_kind(row) != TypeKind::Struct { + return false; + } + fn check(reader: &Reader, row: TypeDef) -> bool { + if reader.type_def_fields(row).any(|field| type_has_callback(reader, &reader.field_type(field, Some(row)))) { + return true; + } + false + } + let type_name = reader.type_def_type_name(row); + if type_name.namespace.is_empty() { + check(reader, row) + } else { + for row in reader.get_type_def(type_name) { + if check(reader, row) { + return true; + } + } + false + } +} + +pub fn type_interfaces(reader: &Reader, ty: &Type) -> Vec<Interface> { + // TODO: collect into btree map and then return collected vec + // This will both sort the results and should make finding dupes faster + fn walk(reader: &Reader, result: &mut Vec<Interface>, parent: &Type, is_base: bool) { + if let Type::TypeDef(row, generics) = parent { + for imp in reader.type_def_interface_impls(*row) { + let mut child = Interface { + ty: reader.interface_impl_type(imp, generics), + kind: if reader.has_attribute(imp, "DefaultAttribute") { InterfaceKind::Default } else { InterfaceKind::None }, + }; + + child.kind = if !is_base && child.kind == InterfaceKind::Default { + InterfaceKind::Default + } else if child.kind == InterfaceKind::Overridable { + continue; + } else if is_base { + InterfaceKind::Base + } else { + InterfaceKind::None + }; + let mut found = false; + for existing in result.iter_mut() { + if existing.ty == child.ty { + found = true; + if child.kind == InterfaceKind::Default { + existing.kind = child.kind + } + } + } + if !found { + walk(reader, result, &child.ty, is_base); + result.push(child); + } + } + } + } + let mut result = Vec::new(); + walk(reader, &mut result, ty, false); + if let Type::TypeDef(row, _) = ty { + if reader.type_def_kind(*row) == TypeKind::Class { + for base in type_def_bases(reader, *row) { + walk(reader, &mut result, &Type::TypeDef(base, Vec::new()), true); + } + for attribute in reader.attributes(*row) { + match reader.attribute_name(attribute) { + "StaticAttribute" | "ActivatableAttribute" => { + for (_, arg) in reader.attribute_args(attribute) { + if let Value::TypeName(type_name) = arg { + let def = reader.get_type_def(TypeName::parse(&type_name)).next().expect("Type not found"); + result.push(Interface { ty: Type::TypeDef(def, Vec::new()), kind: InterfaceKind::Static }); + break; + } + } + } + _ => {} + } + } + } + } + result.sort_by(|a, b| type_name(reader, &a.ty).cmp(type_name(reader, &b.ty))); + result +} + +fn type_name<'a>(reader: &Reader<'a>, ty: &Type) -> &'a str { + match ty { + Type::TypeDef(row, _) => reader.type_def_name(*row), + _ => "", + } +} + +pub fn type_def_async_kind(reader: &Reader, row: TypeDef) -> AsyncKind { + match reader.type_def_type_name(row) { + TypeName::IAsyncAction => AsyncKind::Action, + TypeName::IAsyncActionWithProgress => AsyncKind::ActionWithProgress, + TypeName::IAsyncOperation => AsyncKind::Operation, + TypeName::IAsyncOperationWithProgress => AsyncKind::OperationWithProgress, + _ => AsyncKind::None, + } +} + +pub fn field_is_blittable(reader: &Reader, row: Field, enclosing: TypeDef) -> bool { + type_is_blittable(reader, &reader.field_type(row, Some(enclosing))) +} + +pub fn field_is_copyable(reader: &Reader, row: Field, enclosing: TypeDef) -> bool { + type_is_copyable(reader, &reader.field_type(row, Some(enclosing))) +} + +pub fn field_guid(reader: &Reader, row: Field) -> Option<GUID> { + reader.find_attribute(row, "GuidAttribute").map(|attribute| GUID::from_args(&reader.attribute_args(attribute))) +} + +pub fn field_is_ansi(reader: &Reader, row: Field) -> bool { + reader.find_attribute(row, "NativeEncodingAttribute").is_some_and(|attribute| matches!(reader.attribute_args(attribute).get(0), Some((_, Value::String(encoding))) if encoding == "ansi")) +} + +pub fn type_is_blittable(reader: &Reader, ty: &Type) -> bool { + match ty { + Type::TypeDef(row, _) => type_def_is_blittable(reader, *row), + Type::String | Type::BSTR | Type::IInspectable | Type::IUnknown | Type::GenericParam(_) => false, + Type::Win32Array(kind, _) => type_is_blittable(reader, kind), + Type::WinrtArray(kind) => type_is_blittable(reader, kind), + _ => true, + } +} + +fn type_is_copyable(reader: &Reader, ty: &Type) -> bool { + match ty { + Type::TypeDef(row, _) => type_def_is_copyable(reader, *row), + Type::String | Type::BSTR | Type::IInspectable | Type::IUnknown | Type::GenericParam(_) => false, + Type::Win32Array(kind, _) => type_is_copyable(reader, kind), + Type::WinrtArray(kind) => type_is_copyable(reader, kind), + _ => true, + } +} + +pub fn type_def_is_blittable(reader: &Reader, row: TypeDef) -> bool { + match reader.type_def_kind(row) { + TypeKind::Struct => { + if reader.type_def_flags(row).contains(TypeAttributes::WindowsRuntime) { + reader.type_def_fields(row).all(|field| field_is_blittable(reader, field, row)) + } else { + true + } + } + TypeKind::Enum => true, + TypeKind::Delegate => !reader.type_def_flags(row).contains(TypeAttributes::WindowsRuntime), + _ => false, + } +} + +pub fn type_def_is_copyable(reader: &Reader, row: TypeDef) -> bool { + match reader.type_def_kind(row) { + TypeKind::Struct => reader.type_def_fields(row).all(|field| field_is_copyable(reader, field, row)), + TypeKind::Enum => true, + TypeKind::Delegate => !reader.type_def_flags(row).contains(TypeAttributes::WindowsRuntime), + _ => false, + } +} + +pub fn method_def_special_name(reader: &Reader, row: MethodDef) -> String { + let name = reader.method_def_name(row); + if reader.method_def_flags(row).contains(MethodAttributes::SpecialName) { + if name.starts_with("get") { + name[4..].to_string() + } else if name.starts_with("put") { + format!("Set{}", &name[4..]) + } else if name.starts_with("add") { + name[4..].to_string() + } else if name.starts_with("remove") { + format!("Remove{}", &name[7..]) + } else { + name.to_string() + } + } else { + if let Some(attribute) = reader.find_attribute(row, "OverloadAttribute") { + for (_, arg) in reader.attribute_args(attribute) { + if let Value::String(name) = arg { + return name; + } + } + } + name.to_string() + } +} + +pub fn method_def_static_lib(reader: &Reader, row: MethodDef) -> Option<String> { + reader.find_attribute(row, "StaticLibraryAttribute").and_then(|attribute| { + let args = reader.attribute_args(attribute); + if let Value::String(value) = &args[0].1 { + return Some(value.clone()); + } + None + }) +} + +pub fn method_def_extern_abi(reader: &Reader, def: MethodDef) -> &'static str { + let impl_map = reader.method_def_impl_map(def).expect("ImplMap not found"); + let flags = reader.impl_map_flags(impl_map); + + if flags.contains(PInvokeAttributes::CallConvPlatformapi) { + "system" + } else if flags.contains(PInvokeAttributes::CallConvCdecl) { + "cdecl" + } else { + unimplemented!() + } +} + +pub fn type_def_has_default_constructor(reader: &Reader, row: TypeDef) -> bool { + for attribute in reader.attributes(row) { + if reader.attribute_name(attribute) == "ActivatableAttribute" { + if reader.attribute_args(attribute).iter().any(|arg| matches!(arg.1, Value::TypeName(_))) { + continue; + } else { + return true; + } + } + } + false +} + +pub fn type_def_has_default_interface(reader: &Reader, row: TypeDef) -> bool { + reader.type_def_interface_impls(row).any(|imp| reader.has_attribute(imp, "DefaultAttribute")) +} + +pub fn type_def_is_exclusive(reader: &Reader, row: TypeDef) -> bool { + reader.has_attribute(row, "ExclusiveToAttribute") +} + +pub fn type_is_exclusive(reader: &Reader, ty: &Type) -> bool { + match ty { + Type::TypeDef(row, _) => type_def_is_exclusive(reader, *row), + _ => false, + } +} + +pub fn type_is_struct(reader: &Reader, ty: &Type) -> bool { + // This check is used to detect virtual functions that return C-style PODs that affect how the stack is packed for x86. + // It could be defined as a struct with more than one field but that check is complicated as it would have to detect + // nested structs. Fortunately, this is rare enough that this check is sufficient. + match ty { + Type::TypeDef(row, _) => reader.type_def_kind(*row) == TypeKind::Struct && !type_def_is_handle(reader, *row), + Type::GUID => true, + _ => false, + } +} + +fn type_def_is_primitive(reader: &Reader, row: TypeDef) -> bool { + match reader.type_def_kind(row) { + TypeKind::Enum => true, + TypeKind::Struct => type_def_is_handle(reader, row), + TypeKind::Delegate => !reader.type_def_flags(row).contains(TypeAttributes::WindowsRuntime), + _ => false, + } +} + +pub fn type_is_primitive(reader: &Reader, ty: &Type) -> bool { + match ty { + Type::TypeDef(row, _) => type_def_is_primitive(reader, *row), + Type::Bool | Type::Char | Type::I8 | Type::U8 | Type::I16 | Type::U16 | Type::I32 | Type::U32 | Type::I64 | Type::U64 | Type::F32 | Type::F64 | Type::ISize | Type::USize | Type::HRESULT | Type::ConstPtr(_, _) | Type::MutPtr(_, _) => true, + _ => false, + } +} + +fn type_has_explicit_layout(reader: &Reader, ty: &Type) -> bool { + match ty { + Type::TypeDef(row, _) => type_def_has_explicit_layout(reader, *row), + Type::Win32Array(ty, _) => type_has_explicit_layout(reader, ty), + _ => false, + } +} + +pub fn type_def_has_explicit_layout(reader: &Reader, row: TypeDef) -> bool { + if reader.type_def_kind(row) != TypeKind::Struct { + return false; + } + fn check(reader: &Reader, row: TypeDef) -> bool { + if reader.type_def_flags(row).contains(TypeAttributes::ExplicitLayout) { + return true; + } + if reader.type_def_fields(row).any(|field| type_has_explicit_layout(reader, &reader.field_type(field, Some(row)))) { + return true; + } + false + } + let type_name = reader.type_def_type_name(row); + if type_name.namespace.is_empty() { + check(reader, row) + } else { + for row in reader.get_type_def(type_name) { + if check(reader, row) { + return true; + } + } + false + } +} + +fn type_has_packing(reader: &Reader, ty: &Type) -> bool { + match ty { + Type::TypeDef(row, _) => type_def_has_packing(reader, *row), + Type::Win32Array(ty, _) => type_has_packing(reader, ty), + _ => false, + } +} + +pub fn type_def_has_packing(reader: &Reader, row: TypeDef) -> bool { + if reader.type_def_kind(row) != TypeKind::Struct { + return false; + } + fn check(reader: &Reader, row: TypeDef) -> bool { + if reader.type_def_class_layout(row).is_some() { + return true; + } + if reader.type_def_fields(row).any(|field| type_has_packing(reader, &reader.field_type(field, Some(row)))) { + return true; + } + false + } + let type_name = reader.type_def_type_name(row); + if type_name.namespace.is_empty() { + check(reader, row) + } else { + for row in reader.get_type_def(type_name) { + if check(reader, row) { + return true; + } + } + false + } +} + +pub fn type_def_default_interface(reader: &Reader, row: TypeDef) -> Option<Type> { + reader.type_def_interface_impls(row).find_map(move |row| if reader.has_attribute(row, "DefaultAttribute") { Some(reader.interface_impl_type(row, &[])) } else { None }) +} + +fn type_signature(reader: &Reader, ty: &Type) -> String { + match ty { + Type::Bool => "b1".to_string(), + Type::Char => "c2".to_string(), + Type::I8 => "i1".to_string(), + Type::U8 => "u1".to_string(), + Type::I16 => "i2".to_string(), + Type::U16 => "u2".to_string(), + Type::I32 => "i4".to_string(), + Type::U32 => "u4".to_string(), + Type::I64 => "i8".to_string(), + Type::U64 => "u8".to_string(), + Type::F32 => "f4".to_string(), + Type::F64 => "f8".to_string(), + Type::ISize => "is".to_string(), + Type::USize => "us".to_string(), + Type::String => "string".to_string(), + Type::IInspectable => "cinterface(IInspectable)".to_string(), + Type::GUID => "g16".to_string(), + Type::HRESULT => "struct(Windows.Foundation.HResult;i4)".to_string(), + Type::TypeDef(row, generics) => type_def_signature(reader, *row, generics), + rest => unimplemented!("{rest:?}"), + } +} + +pub fn type_def_signature(reader: &Reader, row: TypeDef, generics: &[Type]) -> String { + match reader.type_def_kind(row) { + TypeKind::Interface => type_def_interface_signature(reader, row, generics), + TypeKind::Class => { + if let Some(Type::TypeDef(default, generics)) = type_def_default_interface(reader, row) { + format!("rc({};{})", reader.type_def_type_name(row), type_def_interface_signature(reader, default, &generics)) + } else { + unimplemented!(); + } + } + TypeKind::Enum => format!("enum({};{})", reader.type_def_type_name(row), type_signature(reader, &reader.type_def_underlying_type(row))), + TypeKind::Struct => { + let mut result = format!("struct({}", reader.type_def_type_name(row)); + for field in reader.type_def_fields(row) { + result.push(';'); + result.push_str(&type_signature(reader, &reader.field_type(field, Some(row)))); + } + result.push(')'); + result + } + TypeKind::Delegate => { + if generics.is_empty() { + format!("delegate({})", type_def_interface_signature(reader, row, generics)) + } else { + type_def_interface_signature(reader, row, generics) + } + } + } +} + +fn type_def_interface_signature(reader: &Reader, row: TypeDef, generics: &[Type]) -> String { + let guid = type_def_guid(reader, row).unwrap(); + if generics.is_empty() { + format!("{{{guid:#?}}}") + } else { + let mut result = format!("pinterface({{{guid:#?}}}"); + for generic in generics { + result.push(';'); + result.push_str(&type_signature(reader, generic)); + } + result.push(')'); + result + } +} + +pub fn type_def_is_handle(reader: &Reader, row: TypeDef) -> bool { + reader.has_attribute(row, "NativeTypedefAttribute") +} + +pub fn type_has_replacement(reader: &Reader, ty: &Type) -> bool { + match ty { + Type::HRESULT | Type::PCSTR | Type::PCWSTR => true, + Type::TypeDef(row, _) => type_def_is_handle(reader, *row) || reader.type_def_kind(*row) == TypeKind::Enum, + _ => false, + } +} + +pub fn type_def_guid(reader: &Reader, row: TypeDef) -> Option<GUID> { + reader.find_attribute(row, "GuidAttribute").map(|attribute| GUID::from_args(&reader.attribute_args(attribute))) +} + +pub fn type_def_bases(reader: &Reader, mut row: TypeDef) -> Vec<TypeDef> { + let mut bases = Vec::new(); + loop { + match reader.type_def_extends(row) { + Some(base) if base != TypeName::Object => { + row = reader.get_type_def(base).next().expect("Type not found"); + bases.push(row); + } + _ => break, + } + } + bases +} + +pub fn type_def_is_agile(reader: &Reader, row: TypeDef) -> bool { + for attribute in reader.attributes(row) { + match reader.attribute_name(attribute) { + "AgileAttribute" => return true, + "MarshalingBehaviorAttribute" => { + if let Some((_, Value::EnumDef(_, value))) = reader.attribute_args(attribute).get(0) { + if let Value::I32(2) = **value { + return true; + } + } + } + _ => {} + } + } + matches!(reader.type_def_type_name(row), TypeName::IAsyncAction | TypeName::IAsyncActionWithProgress | TypeName::IAsyncOperation | TypeName::IAsyncOperationWithProgress) +} + +pub fn type_def_invalid_values(reader: &Reader, row: TypeDef) -> Vec<i64> { + let mut values = Vec::new(); + for attribute in reader.attributes(row) { + if reader.attribute_name(attribute) == "InvalidHandleValueAttribute" { + if let Some((_, Value::I64(value))) = reader.attribute_args(attribute).get(0) { + values.push(*value); + } + } + } + values +} + +pub fn type_def_usable_for(reader: &Reader, row: TypeDef) -> Option<TypeDef> { + if let Some(attribute) = reader.find_attribute(row, "AlsoUsableForAttribute") { + if let Some((_, Value::String(name))) = reader.attribute_args(attribute).get(0) { + return reader.get_type_def(TypeName::new(reader.type_def_namespace(row), name.as_str())).next(); + } + } + None +} + +fn type_def_is_nullable(reader: &Reader, row: TypeDef) -> bool { + match reader.type_def_kind(row) { + TypeKind::Interface | TypeKind::Class => true, + // Win32 callbacks are defined as `Option<T>` so we don't include them here to avoid them + // from being doubly wrapped in `Option`. + TypeKind::Delegate => reader.type_def_flags(row).contains(TypeAttributes::WindowsRuntime), + _ => false, + } +} + +pub fn type_is_nullable(reader: &Reader, ty: &Type) -> bool { + match ty { + Type::TypeDef(row, _) => type_def_is_nullable(reader, *row), + Type::IInspectable | Type::IUnknown => true, + _ => false, + } +} + +pub fn type_def_vtables(reader: &Reader, row: TypeDef) -> Vec<Type> { + let mut result = Vec::new(); + if reader.type_def_flags(row).contains(TypeAttributes::WindowsRuntime) { + result.push(Type::IUnknown); + if reader.type_def_kind(row) != TypeKind::Delegate { + result.push(Type::IInspectable); + } + } else { + let mut next = row; + while let Some(base) = type_def_interfaces(reader, next, &[]).next() { + match base { + Type::TypeDef(row, _) => { + next = row; + result.insert(0, base); + } + Type::IInspectable => { + result.insert(0, Type::IUnknown); + result.insert(1, Type::IInspectable); + break; + } + Type::IUnknown => { + result.insert(0, Type::IUnknown); + break; + } + rest => unimplemented!("{rest:?}"), + } + } + } + result +} + +pub fn type_def_interfaces<'a>(reader: &'a Reader<'a>, row: TypeDef, generics: &'a [Type]) -> impl Iterator<Item = Type> + 'a { + reader.type_def_interface_impls(row).map(move |row| reader.interface_impl_type(row, generics)) +} + +pub fn type_underlying_type(reader: &Reader, ty: &Type) -> Type { + match ty { + Type::TypeDef(row, _) => reader.type_def_underlying_type(*row), + Type::HRESULT => Type::I32, + _ => ty.clone(), + } +} diff --git a/vendor/windows-bindgen/src/method_names.rs b/vendor/windows-bindgen/src/method_names.rs deleted file mode 100644 index 9f5dad1c6..000000000 --- a/vendor/windows-bindgen/src/method_names.rs +++ /dev/null @@ -1,30 +0,0 @@ -use super::*; - -pub struct MethodNames(BTreeMap<String, u32>); - -impl MethodNames { - pub fn new() -> Self { - Self(BTreeMap::new()) - } - - pub fn add(&mut self, gen: &Gen, method: MethodDef) -> TokenStream { - let name = gen.reader.method_def_special_name(method); - let overload = self.0.entry(name.to_string()).or_insert(0); - *overload += 1; - if *overload > 1 { - format!("{name}{overload}").into() - } else { - to_ident(&name) - } - } - - pub fn add_vtable_types(&mut self, gen: &Gen, def: TypeDef) { - for def in gen.reader.type_def_vtables(def) { - if let Type::TypeDef((def, _)) = def { - for method in gen.reader.type_def_methods(def) { - self.add(gen, method); - } - } - } - } -} diff --git a/vendor/windows-bindgen/src/rdl/fmt.rs b/vendor/windows-bindgen/src/rdl/fmt.rs new file mode 100644 index 000000000..8b2df36aa --- /dev/null +++ b/vendor/windows-bindgen/src/rdl/fmt.rs @@ -0,0 +1,454 @@ +use super::*; + +// TODO: should we use rustfmt in the short term (with pre/post) + +#[derive(Default)] +pub struct Writer { + out: String, + indent: usize, + newline: bool, +} + +impl Writer { + pub fn new(file: &rdl::File) -> Self { + let mut writer = Self::default(); + writer.rdl_file(file); + writer + } + + pub fn into_string(mut self) -> String { + self.out.push('\n'); + self.out + } + + fn word(&mut self, value: &str) { + if self.newline { + self.newline = false; + self.out.push('\n'); + for _ in 0..self.indent { + self.out.push_str(" "); + } + } + + self.out.push_str(value); + } + + fn newline(&mut self) { + self.newline = true; + } + + fn rdl_file(&mut self, file: &rdl::File) { + if file.winrt { + self.word("#![winrt]\n"); + } else { + self.word("#![win32]\n"); + } + + self.newline(); + + for reference in &file.references { + self.item_use(reference); + } + + for module in &file.modules { + self.rdl_module(module); + } + } + + fn rdl_module(&mut self, module: &rdl::Module) { + self.word("mod "); + self.word(module.name()); + self.word(" {"); + self.newline(); + self.indent += 1; + + for member in &module.members { + self.rdl_module_member(member); + self.newline(); + } + + self.indent -= 1; + self.newline(); + self.word("}"); + self.newline(); + } + + fn rdl_module_member(&mut self, member: &rdl::ModuleMember) { + match member { + rdl::ModuleMember::Module(member) => self.rdl_module(member), + rdl::ModuleMember::Interface(member) => self.rdl_interface(member), + rdl::ModuleMember::Struct(member) => self.rdl_struct(member), + rdl::ModuleMember::Enum(member) => self.rdl_enum(member), + rdl::ModuleMember::Class(member) => self.rdl_class(member), + rdl::ModuleMember::Constant(member) => self.rdl_constant(member), + rdl::ModuleMember::Function(member) => self.rdl_function(member), + } + } + + fn rdl_class(&mut self, member: &rdl::Class) { + self.attrs(&member.attributes); + self.word("class "); + self.word(&member.name); + + if !member.extends.is_empty() || member.base.is_some() { + self.word(" : "); + + if let Some(path) = &member.base { + self.word("class "); + self.type_path(path); + + if !member.extends.is_empty() { + self.word(", "); + } + } + + let mut first = true; + for path in &member.extends { + if first { + first = false; + } else { + self.word(", "); + } + self.type_path(path); + } + } + + self.word(";"); + self.newline(); + } + + fn rdl_interface(&mut self, member: &rdl::Interface) { + self.attrs(&member.attributes); + self.word("interface "); + self.word(&member.name); + + if !member.generics.is_empty() { + self.word("<"); + + let mut first = true; + for generic in &member.generics { + if first { + first = false; + } else { + self.word(", "); + } + self.word(generic); + } + + self.word(">"); + } + + if !member.extends.is_empty() { + self.word(" : "); + + let mut first = true; + for path in &member.extends { + if first { + first = false; + } else { + self.word(", "); + } + self.type_path(path); + } + } + + self.word(" {"); + self.newline(); + self.indent += 1; + + for method in &member.methods { + self.trait_item_fn(method); + self.word(";"); + self.newline(); + } + + self.indent -= 1; + self.newline(); + self.word("}"); + } + + fn rdl_constant(&mut self, member: &rdl::Constant) { + self.item_const(&member.item); + } + + fn rdl_function(&mut self, member: &rdl::Function) { + self.trait_item_fn(&member.item); + self.word(";"); + self.newline(); + } + + fn item_const(&mut self, item: &syn::ItemConst) { + self.word("const "); + self.ident(&item.ident); + self.word(": "); + self.ty(&item.ty); + self.word(" = "); + self.expr(&item.expr); + self.word(";"); + self.newline(); + } + + fn attrs(&mut self, attrs: &[syn::Attribute]) { + for attr in attrs { + self.attr(attr); + } + } + + fn attr(&mut self, attr: &syn::Attribute) { + self.word("#["); + self.meta(&attr.meta); + self.word("]"); + self.newline(); + } + + fn meta(&mut self, meta: &syn::Meta) { + match meta { + syn::Meta::Path(path) => self.path(path), + syn::Meta::List(list) => self.meta_list(list), + syn::Meta::NameValue(meta) => self.meta_name_value(meta), + } + } + + fn meta_list(&mut self, meta_list: &syn::MetaList) { + self.path(&meta_list.path); + self.word("("); + self.word(&meta_list.tokens.to_string()); + self.word(")"); + } + + fn meta_name_value(&mut self, meta: &syn::MetaNameValue) { + self.path(&meta.path); + self.word(" = "); + self.expr(&meta.value); + } + + fn rdl_struct(&mut self, member: &rdl::Struct) { + self.attrs(&member.attributes); + + self.word("struct "); + self.word(&member.name); + self.word(" {"); + self.newline(); + self.indent += 1; + + for field in &member.fields { + self.word(&field.name); + self.word(": "); + self.ty(&field.ty); + self.word(","); + self.newline(); + } + + self.indent -= 1; + self.newline(); + self.word("}"); + } + + fn rdl_enum(&mut self, member: &rdl::Enum) { + self.attrs(&member.item.attrs); + + self.word("enum "); + self.ident(&member.item.ident); + self.word(" {"); + self.newline(); + self.indent += 1; + + for variant in &member.item.variants { + self.ident(&variant.ident); + if let Some((_, expr)) = &variant.discriminant { + self.word(" = "); + self.expr(expr); + } + self.word(","); + self.newline(); + } + + self.indent -= 1; + self.newline(); + self.word("}"); + } + + fn trait_item_fn(&mut self, method: &syn::TraitItemFn) { + self.attrs(&method.attrs); + self.signature(&method.sig); + } + + fn signature(&mut self, signature: &syn::Signature) { + self.word("fn "); + self.ident(&signature.ident); + self.word("("); + + let mut first = true; + for input in &signature.inputs { + if first { + first = false; + } else { + self.word(", "); + } + self.fn_arg(input); + } + + self.word(")"); + + if let syn::ReturnType::Type(_, ty) = &signature.output { + self.word(" -> "); + self.ty(ty); + } + } + + fn fn_arg(&mut self, fn_arg: &syn::FnArg) { + if let syn::FnArg::Typed(pat_type) = fn_arg { + self.pat_type(pat_type); + } + } + + fn pat_type(&mut self, pat_type: &syn::PatType) { + self.pat(&pat_type.pat); + self.word(": "); + self.ty(&pat_type.ty); + } + + fn pat(&mut self, pat: &syn::Pat) { + match pat { + syn::Pat::Ident(pat_ident) => self.pat_ident(pat_ident), + rest => unimplemented!("{rest:?}"), + } + } + + fn pat_ident(&mut self, pat_ident: &syn::PatIdent) { + self.ident(&pat_ident.ident); + } + + fn ty(&mut self, ty: &syn::Type) { + match ty { + syn::Type::Path(ty) => self.type_path(ty), + syn::Type::Ptr(ptr) => self.type_ptr(ptr), + syn::Type::Array(array) => self.type_array(array), + rest => unimplemented!("{rest:?}"), + } + } + + fn type_array(&mut self, array: &syn::TypeArray) { + self.word("["); + self.ty(&array.elem); + self.word("; "); + self.expr(&array.len); + self.word("]"); + } + + fn expr(&mut self, expr: &syn::Expr) { + match expr { + syn::Expr::Lit(lit) => self.expr_lit(lit), + syn::Expr::Unary(unary) => self.expr_unary(unary), + rest => unimplemented!("{rest:?}"), + } + } + + fn expr_unary(&mut self, unary: &syn::ExprUnary) { + self.word("-"); + self.expr(&unary.expr); + } + + fn expr_lit(&mut self, expr: &syn::ExprLit) { + self.lit(&expr.lit); + } + + fn lit(&mut self, lit: &syn::Lit) { + match lit { + syn::Lit::Int(lit) => self.lit_int(lit), + syn::Lit::Str(lit) => self.lit_str(lit), + _ => _ = dbg!(lit), + } + } + + fn lit_str(&mut self, lit: &syn::LitStr) { + self.word("\""); + self.word(&lit.value()); + self.word("\""); + } + + fn lit_int(&mut self, lit: &syn::LitInt) { + self.word(&lit.token().to_string()); + } + + fn type_ptr(&mut self, ptr: &syn::TypePtr) { + if ptr.mutability.is_some() { + self.word("*mut "); + } else { + self.word("*const "); + } + self.ty(&ptr.elem); + } + + fn type_path(&mut self, ty: &syn::TypePath) { + self.path(&ty.path); + } + + fn path(&mut self, path: &syn::Path) { + let mut first = true; + for segment in &path.segments { + if first { + first = false; + } else { + self.word("::"); + } + self.path_segment(segment); + } + } + + pub fn path_segment(&mut self, segment: &syn::PathSegment) { + self.ident(&segment.ident); + + if let syn::PathArguments::AngleBracketed(args) = &segment.arguments { + self.word("<"); + + let mut first = true; + for arg in &args.args { + if first { + first = false; + } else { + self.word(", "); + } + self.generic_argument(arg); + } + + self.word(">"); + } + } + + fn generic_argument(&mut self, arg: &syn::GenericArgument) { + match arg { + syn::GenericArgument::Type(ty) => self.ty(ty), + rest => unimplemented!("{rest:?}"), + } + } + + fn item_use(&mut self, item: &syn::ItemUse) { + self.word("use "); + self.use_tree(&item.tree); + self.word(";"); + self.newline(); + } + + fn use_tree(&mut self, use_tree: &syn::UseTree) { + match use_tree { + syn::UseTree::Path(use_path) => self.use_path(use_path), + syn::UseTree::Name(use_name) => self.use_name(use_name), + _ => {} + } + } + + fn use_path(&mut self, use_path: &syn::UsePath) { + self.ident(&use_path.ident); + self.word("::"); + self.use_tree(&use_path.tree); + } + + fn use_name(&mut self, use_name: &syn::UseName) { + self.ident(&use_name.ident); + } + + pub fn ident(&mut self, ident: &syn::Ident) { + self.word(&ident.to_string()); + } +} diff --git a/vendor/windows-bindgen/src/rdl/from_reader.rs b/vendor/windows-bindgen/src/rdl/from_reader.rs new file mode 100644 index 000000000..136430a9a --- /dev/null +++ b/vendor/windows-bindgen/src/rdl/from_reader.rs @@ -0,0 +1,435 @@ +use super::*; +use crate::tokens::{quote, to_ident, TokenStream}; +use crate::{rdl, Error, Result, Tree}; +use metadata::RowReader; + +pub fn from_reader(reader: &metadata::Reader, filter: &metadata::Filter, mut config: std::collections::BTreeMap<&str, &str>, output: &str) -> Result<()> { + let dialect = match config.remove("type") { + Some("winrt") => Dialect::WinRT, + Some("win32") => Dialect::Win32, + _ => return Err(Error::new("configuration value `type` must be `win32` or `winrt`")), + }; + + let mut writer = Writer::new(reader, filter, output, dialect); + + // TODO: be sure to use the same "split" key for winmd splitting. + // May also want to support split=N similar to the way MIDLRT supports winmd splitting + // at different nesting levels. + writer.split = config.remove("split").is_some(); + + if let Some((key, _)) = config.first_key_value() { + return Err(Error::new(&format!("invalid configuration value `{key}`"))); + } + + if writer.split { + gen_split(&writer) + } else { + gen_file(&writer) + } +} + +fn gen_split(writer: &Writer) -> Result<()> { + let tree = Tree::new(writer.reader, writer.filter); + let directory = crate::directory(writer.output); + + // TODO: parallelize + for tree in tree.flatten() { + let tokens = writer.tree(tree); + + if !tokens.is_empty() { + let output = format!("{directory}/{}.rdl", tree.namespace); + writer.write_to_file(&output, tokens)?; + } + } + + Ok(()) +} + +fn gen_file(writer: &Writer) -> Result<()> { + let tree = Tree::new(writer.reader, writer.filter); + let tokens = writer.tree(&tree); + writer.write_to_file(writer.output, tokens) +} + +#[derive(Debug, Copy, Clone, PartialEq)] +enum Dialect { + Win32, + WinRT, +} + +struct Writer<'a> { + reader: &'a metadata::Reader<'a>, + filter: &'a metadata::Filter<'a>, + namespace: &'a str, + dialect: Dialect, + split: bool, + output: &'a str, +} + +impl<'a> Writer<'a> { + fn new(reader: &'a metadata::Reader, filter: &'a metadata::Filter, output: &'a str, dialect: Dialect) -> Self { + Self { reader, filter, namespace: "", output, dialect, split: false } + } + + fn with_namespace(&self, namespace: &'a str) -> Self { + Self { reader: self.reader, filter: self.filter, namespace, dialect: self.dialect, output: self.output, split: self.split } + } + + fn write_to_file(&self, output: &str, tokens: TokenStream) -> Result<()> { + let dialect = match self.dialect { + Dialect::Win32 => quote! { #![win32] }, + Dialect::WinRT => quote! { #![winrt] }, + }; + + let tokens = quote! { + #dialect + #tokens + }; + + let file = rdl::File::parse_str(&tokens.into_string())?; + crate::write_to_file(output, file.fmt()) + //crate::write_to_file(output, tokens.into_string()) + } + + fn tree(&self, tree: &'a Tree) -> TokenStream { + let items = self.items(tree); + + if self.split { + let mut tokens = items; + + if !tokens.is_empty() { + for name in tree.namespace.rsplit('.').map(to_ident) { + tokens = quote! { + mod #name { + #tokens + } + }; + } + } + + tokens + } else { + let name = to_ident(tree.namespace.rsplit_once('.').map_or(tree.namespace, |(_, name)| name)); + + let modules = tree.nested.values().map(|tree| self.with_namespace(tree.namespace).tree(tree)); + + if tree.namespace.is_empty() { + quote! { + #(#modules)* + #items + } + } else { + quote! { + mod #name { + #(#modules)* + #items + } + } + } + } + } + + fn items(&self, tree: &'a Tree) -> TokenStream { + let mut functions = vec![]; + let mut constants = vec![]; + let mut types = vec![]; + + if !tree.namespace.is_empty() { + for item in self.reader.namespace_items(tree.namespace, self.filter).filter(|item| match item { + metadata::Item::Type(def) => { + let winrt = self.reader.type_def_flags(*def).contains(metadata::TypeAttributes::WindowsRuntime); + match self.dialect { + Dialect::Win32 => !winrt, + Dialect::WinRT => winrt, + } + } + metadata::Item::Fn(_, _) | metadata::Item::Const(_) => self.dialect == Dialect::Win32, + }) { + match item { + metadata::Item::Type(def) => types.push(self.type_def(def)), + metadata::Item::Const(field) => constants.push(self.constant(field)), + metadata::Item::Fn(method, namespace) => functions.push(self.function(method, &namespace)), + } + } + } + + quote! { + #(#functions)* + #(#constants)* + #(#types)* + } + } + + fn function(&self, def: metadata::MethodDef, _namespace: &str) -> TokenStream { + let name = to_ident(self.reader.method_def_name(def)); + quote! { fn #name(); } + } + + fn constant(&self, def: metadata::Field) -> TokenStream { + let name = to_ident(self.reader.field_name(def)); + quote! { const #name: i32 = 0; } + } + + fn type_def(&self, def: metadata::TypeDef) -> TokenStream { + if let Some(extends) = self.reader.type_def_extends(def) { + if extends.namespace == "System" { + if extends.name == "Enum" { + self.enum_def(def) + } else if extends.name == "ValueType" { + self.struct_def(def) + } else if extends.name == "MulticastDelegate" { + self.delegate_def(def) + } else { + self.class_def(def) + } + } else { + self.class_def(def) + } + } else { + self.interface_def(def) + } + } + + fn enum_def(&self, def: metadata::TypeDef) -> TokenStream { + let name = to_ident(self.reader.type_def_name(def)); + + quote! { + struct #name { + + } + } + } + + fn struct_def(&self, def: metadata::TypeDef) -> TokenStream { + let name = to_ident(self.reader.type_def_name(def)); + + let fields = self.reader.type_def_fields(def).map(|field| { + let name = to_ident(self.reader.field_name(field)); + let ty = self.ty(&self.reader.field_type(field, Some(def))); + quote! { + #name: #ty + } + }); + + quote! { + struct #name { + #(#fields),* + } + } + } + + fn delegate_def(&self, def: metadata::TypeDef) -> TokenStream { + let name = to_ident(self.reader.type_def_name(def)); + + quote! { + struct #name { + + } + } + } + + fn class_def(&self, def: metadata::TypeDef) -> TokenStream { + let name = to_ident(self.reader.type_def_name(def)); + let implements = self.implements(def, &[]); + + quote! { + class #name #implements; + } + } + + fn interface_def(&self, def: metadata::TypeDef) -> TokenStream { + let name = to_ident(self.reader.type_def_name(def)); + let generics = &metadata::type_def_generics(self.reader, def); + let implements = self.implements(def, generics); + + let methods = self.reader.type_def_methods(def).map(|method| { + let name = to_ident(self.reader.method_def_name(method)); + + // TODO: use reader.method_def_signature instead + let signature = metadata::method_def_signature(self.reader, self.reader.type_def_namespace(def), method, generics); + + let return_type = self.return_type(&signature.return_type); + + let params = signature.params.iter().map(|param| { + let name = to_ident(self.reader.param_name(param.def)); + let ty = self.ty(¶m.ty); + quote! { #name: #ty } + }); + + quote! { + fn #name(#(#params),*) #return_type; + } + }); + + let generics = self.generics(generics); + + quote! { + interface #name #generics #implements { + #(#methods)* + } + } + } + + fn generics(&self, generics: &[metadata::Type]) -> TokenStream { + if generics.is_empty() { + quote! {} + } else { + let generics = generics.iter().map(|generic| self.ty(generic)); + + quote! { <#(#generics),*>} + } + } + + fn implements(&self, def: metadata::TypeDef, generics: &[metadata::Type]) -> TokenStream { + let mut types = Vec::<TokenStream>::new(); + + // TODO: if a winrt composable class then start with base + // TODO: then list default interface first + // Then everything else + + for imp in self.reader.type_def_interface_impls(def) { + let ty = self.reader.interface_impl_type(imp, generics); + if self.reader.has_attribute(imp, "DefaultAttribute") { + types.insert(0, self.ty(&ty)); + } else { + types.push(self.ty(&ty)); + } + } + + if let Some(type_name) = self.reader.type_def_extends(def) { + if type_name != metadata::TypeName::Object { + let namespace = self.namespace(type_name.namespace); + let name = to_ident(type_name.name); + // TODO: ideally the "class" contextual keyword wouldn't be needed here + // but currently there's no way to tell the base class apart from a required interface. + types.insert(0, quote! { class #namespace #name }); + } + } + + if types.is_empty() { + quote! {} + } else { + quote! { : #(#types),* } + } + } + + fn return_type(&self, ty: &metadata::Type) -> TokenStream { + match ty { + metadata::Type::Void => quote! {}, + _ => { + let ty = self.ty(ty); + quote! { -> #ty } + } + } + } + + fn ty(&self, ty: &metadata::Type) -> TokenStream { + match ty { + metadata::Type::Void => quote! { ::core::ffi::c_void }, + metadata::Type::Bool => quote! { bool }, + metadata::Type::Char => quote! { u16 }, + metadata::Type::I8 => quote! { i8 }, + metadata::Type::U8 => quote! { u8 }, + metadata::Type::I16 => quote! { i16 }, + metadata::Type::U16 => quote! { u16 }, + metadata::Type::I32 => quote! { i32 }, + metadata::Type::U32 => quote! { u32 }, + metadata::Type::I64 => quote! { i64 }, + metadata::Type::U64 => quote! { u64 }, + metadata::Type::F32 => quote! { f32 }, + metadata::Type::F64 => quote! { f64 }, + metadata::Type::ISize => quote! { isize }, + metadata::Type::USize => quote! { usize }, + + // TODO: dialect-specific keywords for "well-known types" that don't map to metadata in all cases. + metadata::Type::String => quote! { HSTRING }, + metadata::Type::HRESULT => quote! { HRESULT }, + metadata::Type::GUID => quote! { GUID }, + metadata::Type::IInspectable => quote! { IInspectable }, + metadata::Type::IUnknown => quote! { IUnknown }, + + metadata::Type::TypeDef(def, generics) => { + let namespace = self.namespace(self.reader.type_def_namespace(*def)); + let name = to_ident(self.reader.type_def_name(*def)); + if generics.is_empty() { + quote! { #namespace #name } + } else { + let generics = generics.iter().map(|ty| self.ty(ty)); + quote! { #namespace #name<#(#generics,)*> } + } + } + + metadata::Type::TypeRef(code) => { + let type_name = self.reader.type_def_or_ref(*code); + let namespace = self.namespace(type_name.namespace); + let name = to_ident(type_name.name); + quote! { #namespace #name } + } + + metadata::Type::GenericParam(generic) => self.reader.generic_param_name(*generic).into(), + metadata::Type::WinrtArray(ty) => self.ty(ty), + metadata::Type::WinrtArrayRef(ty) => self.ty(ty), + metadata::Type::ConstRef(ty) => self.ty(ty), + metadata::Type::MutPtr(ty, _pointers) => self.ty(ty), + metadata::Type::ConstPtr(ty, _pointers) => self.ty(ty), + metadata::Type::Win32Array(ty, _len) => self.ty(ty), + // TODO: these types should just be regular metadata type defs + metadata::Type::PSTR => quote! { PSTR }, + metadata::Type::PWSTR => quote! { PWSTR }, + metadata::Type::PCSTR => quote! { PCSTR }, + metadata::Type::PCWSTR => quote! { PCWSTR }, + metadata::Type::BSTR => quote! { BSTR }, + metadata::Type::PrimitiveOrEnum(_, ty) => self.ty(ty), + rest => unimplemented!("{rest:?}"), + } + } + + fn namespace(&self, namespace: &str) -> TokenStream { + // TODO: handle nested structs? + if namespace.is_empty() || self.namespace == namespace { + quote! {} + } else { + // TODO: problem with making relative paths here is that we don't have the context to disambiguate + + // let mut relative = self.namespace.split('.').peekable(); + // let mut namespace = namespace.split('.').peekable(); + // let mut related = false; + + // while relative.peek() == namespace.peek() { + // related = true; + + // if relative.next().is_none() { + // break; + // } + + // namespace.next(); + // } + + // let mut tokens = TokenStream::new(); + + // if related { + // for _ in 0..relative.count() { + // tokens.push_str("super::"); + // } + // } + + // for namespace in namespace { + // tokens.push_str(namespace); + // tokens.push_str("::"); + // } + + // tokens + + // TODO: so instead we just gen it out in full + + let mut tokens = TokenStream::new(); + + for namespace in namespace.split('.') { + tokens.push_str(namespace); + tokens.push_str("::"); + } + + tokens + } + } +} diff --git a/vendor/windows-bindgen/src/rdl/mod.rs b/vendor/windows-bindgen/src/rdl/mod.rs new file mode 100644 index 000000000..6cabb168b --- /dev/null +++ b/vendor/windows-bindgen/src/rdl/mod.rs @@ -0,0 +1,338 @@ +use super::*; +mod fmt; +mod from_reader; +mod to_winmd; +use crate::Result; +pub use from_reader::from_reader; +use syn::spanned::Spanned; + +// TODO: may want to finally get rid of `syn` as it also doesn't support preserving code comments + +impl File { + pub fn parse_str(input: &str) -> Result<Self> { + Ok(syn::parse_str::<Self>(input)?) + } + + // Note: this isn't called automatically by `parse_str` to avoid canonicalizing when we're merely formatting IDL. + pub fn canonicalize(&mut self) -> Result<()> { + // TODO maybe we rewrite the `File` here to resolve any `super` references and use declarations so that + // subsequently the rdl-to-winmd conversion can just assume everything's fully qualified? + // * super can't refer to something outside of the IDL file + // * use declarations are only used for unqualified names that aren't defined in the IDL file + // * use declarations don't support globs and must name all externally defined types + // This way we can quickly kick out common invalid IDL files before we lost file/span context info + + Ok(()) + } + + pub fn fmt(&self) -> String { + fmt::Writer::new(self).into_string() + } + + pub fn into_winmd(mut self) -> Result<Vec<u8>> { + self.canonicalize()?; + to_winmd::rdl_to_winmd(&self) + } +} + +// The value of the IDL-specific memory representation is that it allows for constructs that are not modeled in the abstract Module +// tree such as the use declarations and if we get rid of it we'd always "format" IDL by stripping out any of that into a single +// canonical form which would not be very friendly to developers. +#[derive(Debug)] +pub struct File { + pub winrt: bool, + pub references: Vec<syn::ItemUse>, + pub modules: Vec<Module>, +} + +// TODO: need to change these to unpack the syn types and store strings we can reference for efficiency along with spans since the syn +// is made for value semantics. + +#[derive(Clone, Debug)] +pub struct Module { + pub namespace: String, + pub members: Vec<ModuleMember>, +} + +#[derive(Clone, Debug)] +pub enum ModuleMember { + Module(Module), + Interface(Interface), + Struct(Struct), + Enum(Enum), + Class(Class), + Function(Function), + Constant(Constant), +} + +impl ModuleMember { + pub fn name(&self) -> &str { + match self { + Self::Module(module) => crate::extension(&module.namespace), + Self::Interface(member) => &member.name, + Self::Struct(member) => &member.name, + Self::Enum(member) => &member.name, + Self::Class(member) => &member.name, + Self::Function(member) => &member.name, + Self::Constant(member) => &member.name, + } + } +} + +#[derive(Clone, Debug)] +pub struct Enum { + pub winrt: bool, + pub name: String, + pub item: syn::ItemEnum, +} + +#[derive(Clone, Debug)] +pub struct Constant { + pub name: String, + pub item: syn::ItemConst, +} + +#[derive(Clone, Debug)] +pub struct Struct { + pub winrt: bool, + pub name: String, + pub attributes: Vec<syn::Attribute>, + pub span: proc_macro2::Span, + pub fields: Vec<Field>, +} + +#[derive(Clone, Debug)] +pub struct Field { + pub name: String, + pub attributes: Vec<syn::Attribute>, + pub span: proc_macro2::Span, + pub ty: syn::Type, +} + +#[derive(Clone, Debug)] +pub struct Class { + pub name: String, + pub attributes: Vec<syn::Attribute>, + pub base: Option<syn::TypePath>, + pub extends: Vec<syn::TypePath>, +} + +#[derive(Clone, Debug)] +pub struct Function { + pub name: String, + pub item: syn::TraitItemFn, +} + +#[derive(Clone, Debug)] +pub struct Interface { + pub winrt: bool, + pub name: String, + pub generics: Vec<String>, + pub attributes: Vec<syn::Attribute>, + pub extends: Vec<syn::TypePath>, + pub methods: Vec<syn::TraitItemFn>, +} + +syn::custom_keyword!(interface); +syn::custom_keyword!(class); + +fn winrt(input: syn::parse::ParseStream) -> syn::Result<bool> { + let attributes = input.call(syn::Attribute::parse_inner)?; + if attributes.len() == 1 { + if let syn::Meta::Path(path) = &attributes[0].meta { + if path.is_ident("winrt") { + return Ok(true); + } + + if path.is_ident("win32") { + return Ok(false); + } + } + } + + Err(syn::Error::new(input.span(), "A single `#![win32]` or `#![winrt]` attribute required")) +} + +impl syn::parse::Parse for File { + fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> { + let mut references = vec![]; + let mut modules = vec![]; + let winrt = winrt(input)?; + + while !input.is_empty() { + let lookahead = input.lookahead1(); + if lookahead.peek(syn::Token![mod]) { + modules.push(Module::parse("", winrt, input)?); + } else if lookahead.peek(syn::Token![use]) { + references.push(input.parse()?); + } else { + return Err(lookahead.error()); + } + } + Ok(Self { winrt, references, modules }) + } +} + +impl Module { + fn name(&self) -> &str { + self.namespace.rsplit_once('.').map_or(&self.namespace, |(_, name)| name) + } + + fn parse(namespace: &str, winrt: bool, input: syn::parse::ParseStream) -> syn::Result<Self> { + input.parse::<syn::Token![mod]>()?; + let name = input.parse::<syn::Ident>()?.to_string(); + + let namespace = if namespace.is_empty() { name.to_string() } else { format!("{namespace}.{name}") }; + + let content; + syn::braced!(content in input); + let mut members = vec![]; + while !content.is_empty() { + members.push(ModuleMember::parse(&namespace, winrt, &content)?); + } + Ok(Self { namespace, members }) + } +} + +impl ModuleMember { + fn parse(namespace: &str, winrt: bool, input: syn::parse::ParseStream) -> syn::Result<Self> { + let attributes: Vec<syn::Attribute> = input.call(syn::Attribute::parse_outer)?; + let lookahead = input.lookahead1(); + if lookahead.peek(syn::Token![mod]) { + if let Some(attribute) = attributes.first() { + return Err(syn::Error::new(attribute.span(), "`use` attributes not supported")); + } + Ok(ModuleMember::Module(Module::parse(namespace, winrt, input)?)) + } else if lookahead.peek(interface) { + Ok(ModuleMember::Interface(Interface::parse(namespace, winrt, attributes, input)?)) + } else if lookahead.peek(syn::Token![struct]) { + Ok(ModuleMember::Struct(Struct::parse(namespace, winrt, attributes, input)?)) + } else if lookahead.peek(syn::Token![enum]) { + Ok(ModuleMember::Enum(Enum::parse(namespace, winrt, attributes, input)?)) + } else if lookahead.peek(class) { + Ok(ModuleMember::Class(Class::parse(attributes, input)?)) + } else if lookahead.peek(syn::Token![fn]) { + Ok(ModuleMember::Function(Function::parse(namespace, attributes, input)?)) + } else if lookahead.peek(syn::Token![const]) { + Ok(ModuleMember::Constant(Constant::parse(namespace, attributes, input)?)) + } else { + Err(lookahead.error()) + } + } +} + +impl Class { + fn parse(attributes: Vec<syn::Attribute>, input: syn::parse::ParseStream) -> syn::Result<Self> { + input.parse::<class>()?; + let name = input.parse::<syn::Ident>()?.to_string(); + let mut extends = Vec::new(); + let mut base = None; + + if input.peek(syn::Token![:]) { + input.parse::<syn::Token![:]>()?; + while !input.peek(syn::Token![;]) { + if input.peek(class) { + input.parse::<class>()?; + base = Some(input.parse()?); + } else { + extends.push(input.parse()?); + } + _ = input.parse::<syn::Token![,]>(); + } + } + + input.parse::<syn::Token![;]>()?; + Ok(Self { attributes, name, base, extends }) + } +} + +impl Interface { + fn parse(_namespace: &str, winrt: bool, attributes: Vec<syn::Attribute>, input: syn::parse::ParseStream) -> syn::Result<Self> { + input.parse::<interface>()?; + let name = input.parse::<syn::Ident>()?.to_string(); + + let mut generics = Vec::new(); + + if input.peek(syn::Token![<]) { + input.parse::<syn::Token![<]>()?; + while input.peek(syn::Ident) { + generics.push(input.parse::<syn::Ident>()?.to_string()); + _ = input.parse::<syn::Token![,]>(); + } + + input.parse::<syn::Token![>]>()?; + } + + let mut extends = Vec::new(); + + if input.peek(syn::Token![:]) { + input.parse::<syn::Token![:]>()?; + while !input.peek(syn::token::Brace) { + extends.push(input.parse()?); + _ = input.parse::<syn::Token![,]>(); + } + } + + let content; + syn::braced!(content in input); + let mut methods = vec![]; + while !content.is_empty() { + methods.push(content.parse()?); + } + Ok(Self { winrt, attributes, generics, extends, name, methods }) + } +} + +impl Struct { + fn parse(_namespace: &str, winrt: bool, attributes: Vec<syn::Attribute>, input: syn::parse::ParseStream) -> syn::Result<Self> { + // TODO: need to validate that the struct is valid according to the constraints of the winmd type system. + // Same for the other types. That way we can spit out errors quickly for things like unnamed fields. + let span = input.span(); + let item: syn::ItemStruct = input.parse()?; + let name = item.ident.to_string(); + let mut fields = vec![]; + + let syn::Fields::Named(named) = item.fields else { + return Err(syn::Error::new(item.span(), "unnamed fields not supported")); + }; + + for field in named.named { + fields.push(Field { + span: field.span(), + attributes: field.attrs, + // Simply unwrapping since we already know that it is a named field. + name: field.ident.unwrap().to_string(), + ty: field.ty, + }); + } + + Ok(Self { winrt, name, attributes, span, fields }) + } +} + +impl Enum { + fn parse(_namespace: &str, winrt: bool, attributes: Vec<syn::Attribute>, input: syn::parse::ParseStream) -> syn::Result<Self> { + let mut item: syn::ItemEnum = input.parse()?; + item.attrs = attributes; + let name = item.ident.to_string(); + Ok(Self { winrt, name, item }) + } +} + +impl Constant { + fn parse(_namespace: &str, attributes: Vec<syn::Attribute>, input: syn::parse::ParseStream) -> syn::Result<Self> { + let mut item: syn::ItemConst = input.parse()?; + item.attrs = attributes; + let name = item.ident.to_string(); + Ok(Self { name, item }) + } +} + +impl Function { + fn parse(_namespace: &str, attributes: Vec<syn::Attribute>, input: syn::parse::ParseStream) -> syn::Result<Self> { + let mut item: syn::TraitItemFn = input.parse()?; + item.attrs = attributes; + let name = item.sig.ident.to_string(); + Ok(Self { name, item }) + } +} diff --git a/vendor/windows-bindgen/src/rdl/to_winmd.rs b/vendor/windows-bindgen/src/rdl/to_winmd.rs new file mode 100644 index 000000000..d1dc65b12 --- /dev/null +++ b/vendor/windows-bindgen/src/rdl/to_winmd.rs @@ -0,0 +1,335 @@ +use super::*; +use crate::winmd::{self, writer}; +use crate::{rdl, Result}; + +// TODO: store span in winmd so that errors resolving type references can be traced back to file/line/column +use std::collections::HashMap; +//use syn::spanned::Spanned; + +// TODO: this creates a temporary in-memory winmd used to treat the IDL content uniformly as metadata. +// The winmd_to_winmd does the harder job of validating and producing canonical winmd for public consumption. + +pub fn rdl_to_winmd(file: &rdl::File) -> Result<Vec<u8>> { + // Local-to-qualified type names found in use declaration - e.g. "IStringable" -> "Windows.Foundation.IStringable" + // This is just a convenience for the developer to shorten common references like this but would not support globs or renames. + // Note that none of these are verified to be real until much later when the winmd is validated since we don't + // know what other metadata may be combined + let mut _use_map = HashMap::<String, String>::new(); + + // TODO: read file and populate use_map + + // Types are collected here in two passes - this allows us to figure out whether a local name points to a relative type + // or a type from a use declaration...? + let mut collector = HashMap::<String, HashMap<&str, rdl::ModuleMember>>::new(); + + file.modules.iter().for_each(|module| collect_module(&mut collector, module)); + + // TODO: collect type names into hashmap (phase 1) and just drop clones of the IDL members into the collector + + // TODO: Can we just walk the collector at this point and populate the winmd writer and thus need the read-phase? + // this second walking of the collector is basically the "define" phase + + let mut writer = winmd::Writer::new("temp.winmd"); + + collector.iter().for_each(|(namespace, members)| members.iter().for_each(|(name, member)| write_member(&mut writer, namespace, name, member))); + + Ok(writer.into_stream()) +} + +fn collect_module<'a>(collector: &mut HashMap<String, HashMap<&'a str, rdl::ModuleMember>>, module: &'a rdl::Module) { + module.members.iter().for_each(|member| collect_member(collector, module, member)); +} + +fn collect_member<'a>(collector: &mut HashMap<String, HashMap<&'a str, rdl::ModuleMember>>, module: &'a rdl::Module, member: &'a rdl::ModuleMember) { + match member { + rdl::ModuleMember::Module(module) => collect_module(collector, module), + rdl::ModuleMember::Constant(_) | rdl::ModuleMember::Function(_) => { + collector.entry(module.namespace.to_string()).or_default().entry("Apis").or_insert(member.clone()); + } + _ => { + collector.entry(module.namespace.to_string()).or_default().entry(member.name()).or_insert(member.clone()); + } + } +} + +fn write_member(writer: &mut winmd::Writer, namespace: &str, name: &str, member: &rdl::ModuleMember) { + match member { + rdl::ModuleMember::Interface(member) => write_interface(writer, namespace, name, member), + rdl::ModuleMember::Struct(member) => write_struct(writer, namespace, name, member), + rdl::ModuleMember::Enum(member) => write_enum(writer, namespace, name, member), + rdl::ModuleMember::Class(member) => write_class(writer, namespace, name, member), + rest => unimplemented!("{rest:?}"), + } +} + +fn write_interface(writer: &mut winmd::Writer, namespace: &str, name: &str, member: &rdl::Interface) { + let mut flags = metadata::TypeAttributes::Public | metadata::TypeAttributes::Interface | metadata::TypeAttributes::Abstract; + + if member.winrt { + flags |= metadata::TypeAttributes::WindowsRuntime + } + + writer.tables.TypeDef.push(winmd::TypeDef { + Extends: 0, + FieldList: writer.tables.Field.len() as u32, + MethodList: writer.tables.MethodDef.len() as u32, + Flags: flags.0, + TypeName: writer.strings.insert(name), + TypeNamespace: writer.strings.insert(namespace), + }); + + for (number, generic) in member.generics.iter().enumerate() { + writer.tables.GenericParam.push(writer::GenericParam { + Number: number as u16, + Flags: 0, + Owner: writer::TypeOrMethodDef::TypeDef(writer.tables.TypeDef.len() as u32 - 1).encode(), + Name: writer.strings.insert(generic), + }); + } + + for type_path in &member.extends { + let ty = syn_type_path(namespace, &member.generics, type_path); + + let reference = match &ty { + winmd::Type::TypeRef(type_name) if type_name.generics.is_empty() => writer.insert_type_ref(&type_name.namespace, &type_name.name), + winmd::Type::TypeRef(_) => writer.insert_type_spec(ty), + rest => unimplemented!("{rest:?}"), + }; + + writer.tables.InterfaceImpl.push(writer::InterfaceImpl { Class: writer.tables.TypeDef.len() as u32 - 1, Interface: reference }); + } + + for method in &member.methods { + let signature = syn_signature(namespace, &member.generics, &method.sig); + + let params: Vec<winmd::Type> = signature.params.iter().map(|param| param.ty.clone()).collect(); + + let signature_blob = writer.insert_method_sig(metadata::MethodCallAttributes(0), &signature.return_type, ¶ms); + + let flags = metadata::MethodAttributes::Abstract | metadata::MethodAttributes::HideBySig | metadata::MethodAttributes::HideBySig | metadata::MethodAttributes::NewSlot | metadata::MethodAttributes::Public | metadata::MethodAttributes::Virtual; + + writer.tables.MethodDef.push(winmd::MethodDef { + RVA: 0, + ImplFlags: 0, + Flags: flags.0, + Name: writer.strings.insert(&method.sig.ident.to_string()), + Signature: signature_blob, + ParamList: writer.tables.Param.len() as u32, + }); + + for (sequence, param) in signature.params.iter().enumerate() { + writer.tables.Param.push(winmd::Param { Flags: 0, Sequence: (sequence + 1) as u16, Name: writer.strings.insert(¶m.name) }); + } + } +} + +fn write_struct(writer: &mut winmd::Writer, namespace: &str, name: &str, member: &rdl::Struct) { + let mut flags = metadata::TypeAttributes::Public | metadata::TypeAttributes::Sealed | metadata::TypeAttributes::SequentialLayout; + + if member.winrt { + flags |= metadata::TypeAttributes::WindowsRuntime + } + + let extends = writer.insert_type_ref("System", "ValueType"); + + writer.tables.TypeDef.push(winmd::TypeDef { + Extends: extends, + FieldList: writer.tables.Field.len() as u32, + MethodList: writer.tables.MethodDef.len() as u32, + Flags: flags.0, + TypeName: writer.strings.insert(name), + TypeNamespace: writer.strings.insert(namespace), + }); + + for field in &member.fields { + let flags = metadata::FieldAttributes::Public; + let ty = syn_type(namespace, &[], &field.ty); + let signature = writer.insert_field_sig(&ty); + + writer.tables.Field.push(winmd::Field { Flags: flags.0, Name: writer.strings.insert(&field.name), Signature: signature }); + } +} + +fn write_enum(_writer: &mut winmd::Writer, _namespace: &str, _name: &str, _member: &rdl::Enum) {} + +fn write_class(writer: &mut winmd::Writer, namespace: &str, name: &str, member: &rdl::Class) { + let flags = metadata::TypeAttributes::Public | metadata::TypeAttributes::Sealed | metadata::TypeAttributes::WindowsRuntime; + + let extends = if let Some(base) = &member.base { + match syn_type_path(namespace, &[], base) { + winmd::Type::TypeRef(base) => writer.insert_type_ref(&base.namespace, &base.name), + rest => unimplemented!("{rest:?}"), + } + } else { + writer.insert_type_ref("System", "Object") + }; + + writer.tables.TypeDef.push(winmd::TypeDef { + Extends: extends, + // Even though ECMA-335 says these can be "null", bugs in ILDASM necessitate this to avoid "misreading" the list terminators. + FieldList: writer.tables.Field.len() as u32, + MethodList: writer.tables.MethodDef.len() as u32, + Flags: flags.0, + TypeName: writer.strings.insert(name), + TypeNamespace: writer.strings.insert(namespace), + }); + + for (index, extends) in member.extends.iter().enumerate() { + let ty = syn_type_path(namespace, &[], extends); + + let reference = match &ty { + winmd::Type::TypeRef(type_name) if type_name.generics.is_empty() => writer.insert_type_ref(&type_name.namespace, &type_name.name), + winmd::Type::TypeRef(_) => writer.insert_type_spec(ty), + winmd::Type::IUnknown => writer.insert_type_ref("Windows.Win32.System.Com", "IUnknown"), + winmd::Type::IInspectable => writer.insert_type_ref("Windows.Win32.System.WinRT", "IInspectable"), + rest => unimplemented!("{rest:?}"), + }; + + writer.tables.InterfaceImpl.push(writer::InterfaceImpl { Class: writer.tables.TypeDef.len() as u32 - 1, Interface: reference }); + + if index == 0 { + // TODO: add the DefaultAttribute to the first interface + } + } +} + +fn syn_signature(namespace: &str, generics: &[String], sig: &syn::Signature) -> winmd::Signature { + let params = sig + .inputs + .iter() + .map(|param| match param { + syn::FnArg::Typed(pat_type) => { + let name = match &*pat_type.pat { + syn::Pat::Ident(pat_ident) => pat_ident.ident.to_string(), + rest => unimplemented!("{rest:?}"), + }; + let ty = syn_type(namespace, generics, &pat_type.ty); + winmd::SignatureParam { name, ty } + } + rest => unimplemented!("{rest:?}"), + }) + .collect(); + + let return_type = if let syn::ReturnType::Type(_, ty) = &sig.output { syn_type(namespace, generics, ty) } else { winmd::Type::Void }; + + winmd::Signature { params, return_type, call_flags: 0 } +} + +fn syn_type(namespace: &str, generics: &[String], ty: &syn::Type) -> winmd::Type { + match ty { + syn::Type::Path(ty) => syn_type_path(namespace, generics, ty), + syn::Type::Ptr(ptr) => syn_type_ptr(namespace, ptr), + syn::Type::Array(array) => syn_type_array(namespace, array), + rest => unimplemented!("{rest:?}"), + } +} + +fn syn_type_array(namespace: &str, array: &syn::TypeArray) -> winmd::Type { + let ty = syn_type(namespace, &[], &array.elem); + + if let syn::Expr::Lit(lit) = &array.len { + if let syn::Lit::Int(lit) = &lit.lit { + if let Ok(len) = lit.base10_parse() { + return ty.into_array(len); + } + } + } + + unimplemented!() +} + +fn syn_type_ptr(namespace: &str, ptr: &syn::TypePtr) -> winmd::Type { + let ty = syn_type(namespace, &[], &ptr.elem); + if ptr.mutability.is_some() { + ty.into_mut_ptr() + } else { + ty.into_const_ptr() + } +} + +fn syn_type_path(namespace: &str, generics: &[String], ty: &syn::TypePath) -> winmd::Type { + if ty.qself.is_none() { + return syn_path(namespace, generics, &ty.path); + } + + unimplemented!() +} + +fn syn_path(namespace: &str, generics: &[String], path: &syn::Path) -> winmd::Type { + if let Some(segment) = path.segments.first() { + if path.segments.len() == 1 && segment.arguments.is_empty() { + let name = segment.ident.to_string(); + + if let Some(number) = generics.iter().position(|generic| generic == &name) { + return winmd::Type::GenericParam(number as u16); + } + + match name.as_str() { + "void" => return winmd::Type::Void, + "bool" => return winmd::Type::Bool, + "char" => return winmd::Type::Char, + "i8" => return winmd::Type::I8, + "u8" => return winmd::Type::U8, + "i16" => return winmd::Type::I16, + "u16" => return winmd::Type::U16, + "i32" => return winmd::Type::I32, + "u32" => return winmd::Type::U32, + "i64" => return winmd::Type::I64, + "u64" => return winmd::Type::U64, + "f32" => return winmd::Type::F32, + "f64" => return winmd::Type::F64, + "isize" => return winmd::Type::ISize, + "usize" => return winmd::Type::USize, + "HSTRING" => return winmd::Type::String, + "GUID" => return winmd::Type::GUID, + "IUnknown" => return winmd::Type::IUnknown, + "IInspectable" => return winmd::Type::IInspectable, + "HRESULT" => return winmd::Type::HRESULT, + "PSTR" => return winmd::Type::PSTR, + "PWSTR" => return winmd::Type::PWSTR, + "PCSTR" => return winmd::Type::PCSTR, + "PCWSTR" => return winmd::Type::PCWSTR, + "BSTR" => return winmd::Type::BSTR, + _ => {} + }; + } + } + + // TODO: Here we assume that paths are absolute since there's no way to disambiguate between nested and absolute paths + // The canonicalize function (should maybe) preprocesses the IDL to make this work + + let mut builder = vec![]; + + for segment in &path.segments { + let segment = segment.ident.to_string(); + + if segment == "super" { + if builder.is_empty() { + for segment in namespace.split('.') { + builder.push(segment.to_string()); + } + } + builder.pop(); + } else { + builder.push(segment); + } + } + + // Unwrapping is fine as there should always be at least one segment. + let (name, type_namespace) = builder.split_last().unwrap(); + let type_namespace = if type_namespace.is_empty() { namespace.to_string() } else { type_namespace.join(".") }; + let mut type_generics = vec![]; + + if let Some(segment) = path.segments.last() { + if let syn::PathArguments::AngleBracketed(args) = &segment.arguments { + for arg in &args.args { + match arg { + syn::GenericArgument::Type(ty) => type_generics.push(syn_type(namespace, generics, ty)), + rest => unimplemented!("{rest:?}"), + } + } + } + } + + winmd::Type::TypeRef(winmd::TypeName { namespace: type_namespace, name: name.to_string(), generics: type_generics }) +} diff --git a/vendor/windows-bindgen/src/rust/cfg.rs b/vendor/windows-bindgen/src/rust/cfg.rs new file mode 100644 index 000000000..db77497bf --- /dev/null +++ b/vendor/windows-bindgen/src/rust/cfg.rs @@ -0,0 +1,169 @@ +use super::*; + +#[derive(Default, Clone)] +pub struct Cfg<'a> { + pub types: BTreeMap<&'a str, BTreeSet<TypeDef>>, + pub core_types: BTreeSet<Type>, + pub arches: BTreeSet<&'static str>, + pub implement: bool, +} + +impl<'a> Cfg<'a> { + pub fn add_feature(&mut self, feature: &'a str) { + self.types.entry(feature).or_default(); + } + pub fn union(&self, other: &Self) -> Self { + let mut union = Self::default(); + self.types.keys().for_each(|feature| { + union.types.entry(feature).or_default(); + }); + other.types.keys().for_each(|feature| { + union.types.entry(feature).or_default(); + }); + self.arches.iter().for_each(|arch| { + union.arches.insert(arch); + }); + other.arches.iter().for_each(|arch| { + union.arches.insert(arch); + }); + union + } +} + +pub fn field_cfg<'a>(reader: &'a Reader<'a>, row: Field) -> Cfg<'a> { + let mut cfg = Cfg::default(); + field_cfg_combine(reader, row, None, &mut cfg); + cfg +} +fn field_cfg_combine<'a>(reader: &'a Reader, row: Field, enclosing: Option<TypeDef>, cfg: &mut Cfg<'a>) { + type_cfg_combine(reader, &reader.field_type(row, enclosing), cfg) +} + +pub fn type_def_cfg<'a>(reader: &'a Reader, row: TypeDef, generics: &[Type]) -> Cfg<'a> { + let mut cfg = Cfg::default(); + type_def_cfg_combine(reader, row, generics, &mut cfg); + cfg_add_attributes(reader, &mut cfg, row); + cfg +} +pub fn type_def_cfg_impl<'a>(reader: &'a Reader, def: TypeDef, generics: &[Type]) -> Cfg<'a> { + let mut cfg = Cfg { implement: true, ..Default::default() }; + + fn combine<'a>(reader: &'a Reader, def: TypeDef, generics: &[Type], cfg: &mut Cfg<'a>) { + type_def_cfg_combine(reader, def, generics, cfg); + + for method in reader.type_def_methods(def) { + signature_cfg_combine(reader, &reader.method_def_signature(method, generics), cfg); + } + } + + combine(reader, def, generics, &mut cfg); + + for def in type_def_vtables(reader, def) { + if let Type::TypeDef(def, generics) = def { + combine(reader, def, &generics, &mut cfg); + } + } + + if reader.type_def_flags(def).contains(TypeAttributes::WindowsRuntime) { + for interface in type_def_interfaces(reader, def, generics) { + if let Type::TypeDef(def, generics) = interface { + combine(reader, def, &generics, &mut cfg); + } + } + } + + cfg_add_attributes(reader, &mut cfg, def); + cfg +} +pub fn type_def_cfg_combine<'a>(reader: &'a Reader, row: TypeDef, generics: &[Type], cfg: &mut Cfg<'a>) { + let type_name = reader.type_def_type_name(row); + + for generic in generics { + type_cfg_combine(reader, generic, cfg); + } + + if cfg.types.entry(type_name.namespace).or_default().insert(row) { + match reader.type_def_kind(row) { + TypeKind::Class => { + if let Some(default_interface) = type_def_default_interface(reader, row) { + type_cfg_combine(reader, &default_interface, cfg); + } + } + TypeKind::Interface => { + if !reader.type_def_flags(row).contains(TypeAttributes::WindowsRuntime) { + for def in type_def_vtables(reader, row) { + if let Type::TypeDef(def, _) = def { + cfg.add_feature(reader.type_def_namespace(def)); + } + } + } + } + TypeKind::Struct => { + reader.type_def_fields(row).for_each(|field| field_cfg_combine(reader, field, Some(row), cfg)); + if !type_name.namespace.is_empty() { + for def in reader.get_type_def(type_name) { + if def != row { + type_def_cfg_combine(reader, def, &[], cfg); + } + } + } + } + TypeKind::Delegate => signature_cfg_combine(reader, &reader.method_def_signature(type_def_invoke_method(reader, row), generics), cfg), + _ => {} + } + } +} + +pub fn signature_cfg<'a>(reader: &'a Reader, method: MethodDef) -> Cfg<'a> { + let mut cfg = Cfg::default(); + signature_cfg_combine(reader, &reader.method_def_signature(method, &[]), &mut cfg); + cfg_add_attributes(reader, &mut cfg, method); + cfg +} +fn signature_cfg_combine<'a>(reader: &'a Reader, signature: &MethodDefSig, cfg: &mut Cfg<'a>) { + type_cfg_combine(reader, &signature.return_type, cfg); + signature.params.iter().for_each(|param| type_cfg_combine(reader, param, cfg)); +} + +fn cfg_add_attributes<R: AsRow + Into<HasAttribute>>(reader: &Reader, cfg: &mut Cfg, row: R) { + for attribute in reader.attributes(row) { + match reader.attribute_name(attribute) { + "SupportedArchitectureAttribute" => { + if let Some((_, Value::EnumDef(_, value))) = reader.attribute_args(attribute).get(0) { + if let Value::I32(value) = **value { + if value & 1 == 1 { + cfg.arches.insert("x86"); + } + if value & 2 == 2 { + cfg.arches.insert("x86_64"); + } + if value & 4 == 4 { + cfg.arches.insert("aarch64"); + } + } + } + } + "DeprecatedAttribute" => { + cfg.add_feature("deprecated"); + } + _ => {} + } + } +} + +pub fn type_cfg<'a>(reader: &'a Reader, ty: &Type) -> Cfg<'a> { + let mut cfg = Cfg::default(); + type_cfg_combine(reader, ty, &mut cfg); + cfg +} +fn type_cfg_combine<'a>(reader: &'a Reader, ty: &Type, cfg: &mut Cfg<'a>) { + match ty { + Type::TypeDef(row, generics) => type_def_cfg_combine(reader, *row, generics, cfg), + Type::Win32Array(ty, _) => type_cfg_combine(reader, ty, cfg), + Type::ConstPtr(ty, _) => type_cfg_combine(reader, ty, cfg), + Type::MutPtr(ty, _) => type_cfg_combine(reader, ty, cfg), + Type::WinrtArray(ty) => type_cfg_combine(reader, ty, cfg), + Type::WinrtArrayRef(ty) => type_cfg_combine(reader, ty, cfg), + ty => _ = cfg.core_types.insert(ty.clone()), + } +} diff --git a/vendor/windows-bindgen/src/rust/classes.rs b/vendor/windows-bindgen/src/rust/classes.rs new file mode 100644 index 000000000..397abff10 --- /dev/null +++ b/vendor/windows-bindgen/src/rust/classes.rs @@ -0,0 +1,160 @@ +use super::*; + +pub fn writer(writer: &Writer, def: TypeDef) -> TokenStream { + if writer.sys { + if type_def_has_default_interface(writer.reader, def) { + let name = to_ident(writer.reader.type_def_name(def)); + quote! { + pub type #name = *mut ::core::ffi::c_void; + } + } else { + quote! {} + } + } else { + gen_class(writer, def) + } +} + +fn gen_class(writer: &Writer, def: TypeDef) -> TokenStream { + if writer.reader.type_def_extends(def) == Some(TypeName::Attribute) { + return TokenStream::new(); + } + + let name = to_ident(writer.reader.type_def_name(def)); + let interfaces = type_interfaces(writer.reader, &Type::TypeDef(def, Vec::new())); + let mut methods = quote! {}; + let mut method_names = MethodNames::new(); + + let cfg = type_def_cfg(writer.reader, def, &[]); + let doc = writer.cfg_doc(&cfg); + let features = writer.cfg_features(&cfg); + + for interface in &interfaces { + if let Type::TypeDef(def, generics) = &interface.ty { + let mut virtual_names = MethodNames::new(); + + for method in writer.reader.type_def_methods(*def) { + methods.combine(&winrt_methods::writer(writer, *def, generics, interface.kind, method, &mut method_names, &mut virtual_names)); + } + } + } + + let factories = interfaces.iter().filter_map(|interface| match interface.kind { + InterfaceKind::Static => { + if let Type::TypeDef(def, generics) = &interface.ty { + if writer.reader.type_def_methods(*def).next().is_some() { + let interface_type = writer.type_name(&interface.ty); + let features = writer.cfg_features(&type_def_cfg(writer.reader, *def, generics)); + + return Some(quote! { + #[doc(hidden)] + #features + pub fn #interface_type<R, F: FnOnce(&#interface_type) -> ::windows_core::Result<R>>( + callback: F, + ) -> ::windows_core::Result<R> { + static SHARED: ::windows_core::imp::FactoryCache<#name, #interface_type> = + ::windows_core::imp::FactoryCache::new(); + SHARED.call(callback) + } + }); + } + } + None + } + _ => None, + }); + + if type_def_has_default_interface(writer.reader, def) { + let new = if type_def_has_default_constructor(writer.reader, def) { + quote! { + pub fn new() -> ::windows_core::Result<Self> { + Self::IActivationFactory(|f| f.ActivateInstance::<Self>()) + } + fn IActivationFactory<R, F: FnOnce(&::windows_core::imp::IGenericFactory) -> ::windows_core::Result<R>>( + callback: F, + ) -> ::windows_core::Result<R> { + static SHARED: ::windows_core::imp::FactoryCache<#name, ::windows_core::imp::IGenericFactory> = + ::windows_core::imp::FactoryCache::new(); + SHARED.call(callback) + } + } + } else { + quote! {} + }; + + let mut tokens = quote! { + #doc + #features + #[repr(transparent)] + pub struct #name(::windows_core::IUnknown); + #features + impl #name { + #new + #methods + #(#factories)* + } + }; + + tokens.combine(&writer.interface_core_traits(def, &[], &name, &TokenStream::new(), &TokenStream::new(), &features)); + tokens.combine(&writer.interface_winrt_trait(def, &[], &name, &TokenStream::new(), &TokenStream::new(), &features)); + tokens.combine(&writer.interface_trait(def, &[], &name, &TokenStream::new(), &features, true)); + tokens.combine(&writer.runtime_name_trait(def, &[], &name, &TokenStream::new(), &features)); + tokens.combine(&writer.async_get(def, &[], &name, &TokenStream::new(), &TokenStream::new(), &features)); + tokens.combine(&iterators::writer(writer, def, &[], &name, &TokenStream::new(), &TokenStream::new(), &cfg)); + tokens.combine(&gen_conversions(writer, def, &name, &interfaces, &cfg)); + tokens.combine(&writer.agile(def, &name, &TokenStream::new(), &features)); + tokens + } else { + let mut tokens = quote! { + #doc + #features + pub struct #name; + #features + impl #name { + #methods + #(#factories)* + } + }; + + tokens.combine(&writer.runtime_name_trait(def, &[], &name, &TokenStream::new(), &features)); + tokens + } +} + +fn gen_conversions(writer: &Writer, def: TypeDef, name: &TokenStream, interfaces: &[Interface], cfg: &Cfg) -> TokenStream { + let features = writer.cfg_features(cfg); + let mut tokens = quote! { + #features + ::windows_core::imp::interface_hierarchy!(#name, ::windows_core::IUnknown, ::windows_core::IInspectable); + }; + + for interface in interfaces { + if type_is_exclusive(writer.reader, &interface.ty) { + continue; + } + + if interface.kind != InterfaceKind::Default && interface.kind != InterfaceKind::None && interface.kind != InterfaceKind::Base { + continue; + } + + let into = writer.type_name(&interface.ty); + let features = writer.cfg_features(&cfg.union(&type_cfg(writer.reader, &interface.ty))); + + tokens.combine("e! { + #features + impl ::windows_core::CanTryInto<#into> for #name {} + }); + } + + for def in type_def_bases(writer.reader, def) { + let into = writer.type_def_name(def, &[]); + let features = writer.cfg_features(&cfg.union(&type_def_cfg(writer.reader, def, &[]))); + + tokens.combine("e! { + #features + impl ::windows_core::CanTryInto<#into> for #name {} + }); + } + + tokens +} diff --git a/vendor/windows-bindgen/src/rust/com_methods.rs b/vendor/windows-bindgen/src/rust/com_methods.rs new file mode 100644 index 000000000..132e7f220 --- /dev/null +++ b/vendor/windows-bindgen/src/rust/com_methods.rs @@ -0,0 +1,207 @@ +use super::*; + +pub fn writer(writer: &Writer, def: TypeDef, kind: InterfaceKind, method: MethodDef, method_names: &mut MethodNames, virtual_names: &mut MethodNames, base_count: usize) -> TokenStream { + let signature = method_def_signature(writer.reader, writer.reader.type_def_namespace(def), method, &[]); + + let name = method_names.add(writer, method); + let vname = virtual_names.add(writer, method); + let generics = writer.constraint_generics(&signature.params); + let where_clause = writer.where_clause(&signature.params); + let mut cfg = signature_cfg(writer.reader, method); + cfg.add_feature(writer.reader.type_def_namespace(def)); + let doc = writer.cfg_method_doc(&cfg); + let features = writer.cfg_features(&cfg); + + if kind == InterfaceKind::None { + return quote! {}; + } + + let mut bases = quote! {}; + + for _ in 0..base_count { + bases.combine("e! { .base__ }); + } + + let kind = signature_kind(writer.reader, &signature); + match kind { + SignatureKind::Query(_) => { + let args = writer.win32_args(&signature.params, kind); + let params = writer.win32_params(&signature.params, kind); + let generics = expand_generics(generics, quote!(T)); + let where_clause = expand_where_clause(where_clause, quote!(T: ::windows_core::ComInterface)); + + quote! { + #doc + #features + pub unsafe fn #name<#generics>(&self, #params) -> ::windows_core::Result<T> #where_clause { + let mut result__ = ::std::ptr::null_mut(); + (::windows_core::Interface::vtable(self)#bases.#vname)(::windows_core::Interface::as_raw(self), #args).from_abi(result__) + } + } + } + SignatureKind::QueryOptional(_) => { + let args = writer.win32_args(&signature.params, kind); + let params = writer.win32_params(&signature.params, kind); + let generics = expand_generics(generics, quote!(T)); + let where_clause = expand_where_clause(where_clause, quote!(T: ::windows_core::ComInterface)); + + quote! { + #doc + #features + pub unsafe fn #name<#generics>(&self, #params result__: *mut ::core::option::Option<T>) -> ::windows_core::Result<()> #where_clause { + (::windows_core::Interface::vtable(self)#bases.#vname)(::windows_core::Interface::as_raw(self), #args).ok() + } + } + } + SignatureKind::ResultValue => { + let args = writer.win32_args(&signature.params, kind); + let params = writer.win32_params(&signature.params, kind); + let return_type = signature.params[signature.params.len() - 1].ty.deref(); + let return_type = writer.type_name(&return_type); + + quote! { + #doc + #features + pub unsafe fn #name<#generics>(&self, #params) -> ::windows_core::Result<#return_type> #where_clause { + let mut result__ = ::std::mem::zeroed(); + (::windows_core::Interface::vtable(self)#bases.#vname)(::windows_core::Interface::as_raw(self), #args).from_abi(result__) + } + } + } + SignatureKind::ResultVoid => { + let args = writer.win32_args(&signature.params, kind); + let params = writer.win32_params(&signature.params, kind); + + quote! { + #doc + #features + pub unsafe fn #name<#generics>(&self, #params) -> ::windows_core::Result<()> #where_clause { + (::windows_core::Interface::vtable(self)#bases.#vname)(::windows_core::Interface::as_raw(self), #args).ok() + } + } + } + SignatureKind::ReturnValue => { + let args = writer.win32_args(&signature.params, kind); + let params = writer.win32_params(&signature.params, kind); + let return_type = signature.params[signature.params.len() - 1].ty.deref(); + let is_nullable = type_is_nullable(writer.reader, &return_type); + let return_type = writer.type_name(&return_type); + + if is_nullable { + quote! { + #doc + #features + pub unsafe fn #name<#generics>(&self, #params) -> ::windows_core::Result<#return_type> #where_clause { + let mut result__ = ::std::mem::zeroed(); + (::windows_core::Interface::vtable(self)#bases.#vname)(::windows_core::Interface::as_raw(self), #args); + ::windows_core::from_abi(result__) + } + } + } else { + quote! { + #doc + #features + pub unsafe fn #name<#generics>(&self, #params) -> #return_type #where_clause { + let mut result__ = ::std::mem::zeroed(); + (::windows_core::Interface::vtable(self)#bases.#vname)(::windows_core::Interface::as_raw(self), #args); + ::std::mem::transmute(result__) + } + } + } + } + SignatureKind::ReturnStruct => { + let args = writer.win32_args(&signature.params, kind); + let params = writer.win32_params(&signature.params, kind); + let return_type = writer.type_name(&signature.return_type); + + quote! { + #doc + #features + pub unsafe fn #name<#generics>(&self, #params) -> #return_type #where_clause { + let mut result__: #return_type = ::core::mem::zeroed(); + (::windows_core::Interface::vtable(self)#bases.#vname)(::windows_core::Interface::as_raw(self), &mut result__, #args); + result__ + } + } + } + SignatureKind::PreserveSig => { + let args = writer.win32_args(&signature.params, kind); + let params = writer.win32_params(&signature.params, kind); + let return_type = writer.return_sig(&signature); + + quote! { + #doc + #features + pub unsafe fn #name<#generics>(&self, #params) #return_type #where_clause { + (::windows_core::Interface::vtable(self)#bases.#vname)(::windows_core::Interface::as_raw(self), #args) + } + } + } + SignatureKind::ReturnVoid => { + let args = writer.win32_args(&signature.params, kind); + let params = writer.win32_params(&signature.params, kind); + + quote! { + #doc + #features + pub unsafe fn #name<#generics>(&self, #params) #where_clause { + (::windows_core::Interface::vtable(self)#bases.#vname)(::windows_core::Interface::as_raw(self), #args) + } + } + } + } +} + +pub fn gen_upcall(writer: &Writer, sig: &Signature, inner: TokenStream) -> TokenStream { + match signature_kind(writer.reader, sig) { + SignatureKind::ResultValue => { + let invoke_args = sig.params[..sig.params.len() - 1].iter().map(|param| gen_win32_invoke_arg(writer, param)); + + let result = writer.param_name(sig.params[sig.params.len() - 1].def); + + quote! { + match #inner(#(#invoke_args,)*) { + ::core::result::Result::Ok(ok__) => { + // use `core::ptr::write` since the result could be uninitialized + ::core::ptr::write(#result, ::core::mem::transmute(ok__)); + ::windows_core::HRESULT(0) + } + ::core::result::Result::Err(err) => err.into() + } + } + } + SignatureKind::Query(_) | SignatureKind::QueryOptional(_) | SignatureKind::ResultVoid => { + let invoke_args = sig.params.iter().map(|param| gen_win32_invoke_arg(writer, param)); + + quote! { + #inner(#(#invoke_args,)*).into() + } + } + SignatureKind::ReturnStruct => { + let invoke_args = sig.params.iter().map(|param| gen_win32_invoke_arg(writer, param)); + + quote! { + *result__ = #inner(#(#invoke_args,)*) + } + } + _ => { + let invoke_args = sig.params.iter().map(|param| gen_win32_invoke_arg(writer, param)); + + quote! { + #inner(#(#invoke_args,)*) + } + } + } +} + +fn gen_win32_invoke_arg(writer: &Writer, param: &SignatureParam) -> TokenStream { + let name = writer.param_name(param.def); + + if writer.reader.param_flags(param.def).contains(ParamAttributes::In) && type_is_nullable(writer.reader, ¶m.ty) { + quote! { ::windows_core::from_raw_borrowed(&#name) } + } else if (!param.ty.is_pointer() && type_is_nullable(writer.reader, ¶m.ty)) || (writer.reader.param_flags(param.def).contains(ParamAttributes::In) && !type_is_primitive(writer.reader, ¶m.ty)) { + quote! { ::core::mem::transmute(&#name) } + } else { + quote! { ::core::mem::transmute_copy(&#name) } + } +} diff --git a/vendor/windows-bindgen/src/constants.rs b/vendor/windows-bindgen/src/rust/constants.rs index 1a08db0ae..672dbcc8a 100644 --- a/vendor/windows-bindgen/src/constants.rs +++ b/vendor/windows-bindgen/src/rust/constants.rs @@ -1,27 +1,27 @@ use super::*; -pub fn gen(gen: &Gen, def: Field) -> TokenStream { - let name = to_ident(gen.reader.field_name(def)); - let ty = gen.reader.field_type(def, None).to_const_type(); - let cfg = gen.reader.field_cfg(def); - let doc = gen.cfg_doc(&cfg); - let features = gen.cfg_features(&cfg); +pub fn writer(writer: &Writer, def: Field) -> TokenStream { + let name = to_ident(writer.reader.field_name(def)); + let ty = writer.reader.field_type(def, None).to_const_type(); + let cfg = field_cfg(writer.reader, def); + let doc = writer.cfg_doc(&cfg); + let features = writer.cfg_features(&cfg); - if let Some(constant) = gen.reader.field_constant(def) { - let constant_type = gen.reader.constant_type(constant); + if let Some(constant) = writer.reader.field_constant(def) { + let constant_type = writer.reader.constant_type(constant); if ty == constant_type { if ty == Type::String { - let crate_name = gen.crate_name(); - if gen.reader.field_is_ansi(def) { - let value = gen.value(&gen.reader.constant_value(constant)); + let crate_name = writer.crate_name(); + if field_is_ansi(writer.reader, def) { + let value = writer.value(&writer.reader.constant_value(constant)); quote! { #doc #features pub const #name: #crate_name PCSTR = #crate_name s!(#value); } } else { - let value = gen.value(&gen.reader.constant_value(constant)); + let value = writer.value(&writer.reader.constant_value(constant)); quote! { #doc #features @@ -29,7 +29,7 @@ pub fn gen(gen: &Gen, def: Field) -> TokenStream { } } } else { - let value = gen.typed_value(&gen.reader.constant_value(constant)); + let value = writer.typed_value(&writer.reader.constant_value(constant)); quote! { #doc #features @@ -37,19 +37,19 @@ pub fn gen(gen: &Gen, def: Field) -> TokenStream { } } } else { - let kind = gen.type_default_name(&ty); - let value = gen.value(&gen.reader.constant_value(constant)); - let underlying_type = gen.reader.type_underlying_type(&ty); + let kind = writer.type_default_name(&ty); + let value = writer.value(&writer.reader.constant_value(constant)); + let underlying_type = type_underlying_type(writer.reader, &ty); let value = if underlying_type == constant_type { value - } else if gen.std && underlying_type == Type::ISize { + } else if writer.std && underlying_type == Type::ISize { quote! { ::core::ptr::invalid_mut(#value as _) } } else { quote! { #value as _ } }; - if !gen.sys && gen.reader.type_has_replacement(&ty) { + if !writer.sys && type_has_replacement(writer.reader, &ty) { quote! { #doc #features @@ -63,15 +63,15 @@ pub fn gen(gen: &Gen, def: Field) -> TokenStream { } } } - } else if let Some(guid) = gen.reader.field_guid(def) { - let value = gen.guid(&guid); - let guid = gen.type_name(&Type::GUID); + } else if let Some(guid) = field_guid(writer.reader, def) { + let value = writer.guid(&guid); + let guid = writer.type_name(&Type::GUID); quote! { #doc pub const #name: #guid = #value; } - } else if let Some(value) = initializer(gen, def) { - let kind = gen.type_default_name(&ty); + } else if let Some(value) = initializer(writer, def) { + let kind = writer.type_default_name(&ty); quote! { #doc @@ -83,21 +83,21 @@ pub fn gen(gen: &Gen, def: Field) -> TokenStream { } } -fn initializer(gen: &Gen, def: Field) -> Option<TokenStream> { - let Some(value) = constant(gen, def) else { +fn initializer(writer: &Writer, def: Field) -> Option<TokenStream> { + let Some(value) = constant(writer, def) else { return None; }; let mut input = value.as_str(); - let Type::TypeDef((def, _)) = gen.reader.field_type(def, None) else { + let Type::TypeDef(def, _) = writer.reader.field_type(def, None) else { unimplemented!(); }; let mut result = quote! {}; - for field in gen.reader.type_def_fields(def) { - let (value, rest) = field_initializer(gen, field, input); + for field in writer.reader.type_def_fields(def) { + let (value, rest) = field_initializer(writer, field, input); input = rest; result.combine(&value); } @@ -105,16 +105,16 @@ fn initializer(gen: &Gen, def: Field) -> Option<TokenStream> { Some(result) } -fn field_initializer<'a>(gen: &Gen, field: Field, input: &'a str) -> (TokenStream, &'a str) { - let name = to_ident(gen.reader.field_name(field)); +fn field_initializer<'a>(writer: &Writer, field: Field, input: &'a str) -> (TokenStream, &'a str) { + let name = to_ident(writer.reader.field_name(field)); - match gen.reader.field_type(field, None) { + match writer.reader.field_type(field, None) { Type::GUID => { let (literals, rest) = read_literal_array(input, 11); - let value = gen.guid(&GUID::from_string_args(&literals)); + let value = writer.guid(&GUID::from_string_args(&literals)); (quote! { #name: #value, }, rest) } - Type::Win32Array((_, len)) => { + Type::Win32Array(_, len) => { let (literals, rest) = read_literal_array(input, len); let literals = literals.iter().map(|literal| TokenStream::from(*literal)); (quote! { #name: [#(#literals,)*], }, rest) @@ -127,17 +127,14 @@ fn field_initializer<'a>(gen: &Gen, field: Field, input: &'a str) -> (TokenStrea } } -fn constant(gen: &Gen, def: Field) -> Option<String> { - gen.reader - .field_attributes(def) - .find(|attribute| gen.reader.attribute_name(*attribute) == "ConstantAttribute") - .map(|attribute| { - let args = gen.reader.attribute_args(attribute); - match &args[0].1 { - Value::String(value) => value.clone(), - _ => unimplemented!(), - } - }) +fn constant(writer: &Writer, def: Field) -> Option<String> { + writer.reader.find_attribute(def, "ConstantAttribute").map(|attribute| { + let args = writer.reader.attribute_args(attribute); + match &args[0].1 { + Value::String(value) => value.clone(), + rest => unimplemented!("{rest:?}"), + } + }) } fn read_literal(input: &str) -> (&str, &str) { diff --git a/vendor/windows-bindgen/src/rust/delegates.rs b/vendor/windows-bindgen/src/rust/delegates.rs new file mode 100644 index 000000000..5b1b12022 --- /dev/null +++ b/vendor/windows-bindgen/src/rust/delegates.rs @@ -0,0 +1,156 @@ +use super::*; + +pub fn writer(writer: &Writer, def: TypeDef) -> TokenStream { + if writer.reader.type_def_flags(def).contains(TypeAttributes::WindowsRuntime) { + gen_delegate(writer, def) + } else { + gen_callback(writer, def) + } +} + +fn gen_callback(writer: &Writer, def: TypeDef) -> TokenStream { + let name = to_ident(writer.reader.type_def_name(def)); + let method = type_def_invoke_method(writer.reader, def); + + let signature = method_def_signature(writer.reader, writer.reader.type_def_namespace(def), method, &[]); + + let return_type = writer.return_sig(&signature); + let cfg = type_def_cfg(writer.reader, def, &[]); + let doc = writer.cfg_doc(&cfg); + let features = writer.cfg_features(&cfg); + + let params = signature.params.iter().map(|p| { + let name = writer.param_name(p.def); + let tokens = writer.type_default_name(&p.ty); + quote! { #name: #tokens } + }); + + quote! { + #doc + #features + pub type #name = ::core::option::Option<unsafe extern "system" fn(#(#params),*) #return_type>; + } +} + +fn gen_delegate(writer: &Writer, def: TypeDef) -> TokenStream { + if writer.sys { + let name = to_ident(writer.reader.type_def_name(def)); + quote! { + pub type #name = *mut ::core::ffi::c_void; + } + } else { + gen_win_delegate(writer, def) + } +} + +fn gen_win_delegate(writer: &Writer, def: TypeDef) -> TokenStream { + let name = to_ident(writer.reader.type_def_name(def)); + let vtbl = name.join("_Vtbl"); + let boxed = name.join("Box"); + + let generics = &type_def_generics(writer.reader, def); + let phantoms = writer.generic_phantoms(generics); + let named_phantoms = writer.generic_named_phantoms(generics); + let constraints = writer.generic_constraints(generics); + let generic_names = writer.generic_names(generics); + + let ident = writer.type_def_name(def, generics); + let method = type_def_invoke_method(writer.reader, def); + + let signature = method_def_signature(writer.reader, writer.reader.type_def_namespace(def), method, generics); + + let fn_constraint = gen_fn_constraint(writer, def, &signature); + let cfg = type_def_cfg(writer.reader, def, generics); + let doc = writer.cfg_doc(&cfg); + let features = writer.cfg_features(&cfg); + + let vtbl_signature = writer.vtbl_signature(def, generics, &signature); + let invoke = winrt_methods::writer(writer, def, generics, InterfaceKind::Default, method, &mut MethodNames::new(), &mut MethodNames::new()); + let invoke_upcall = winrt_methods::gen_upcall(writer, &signature, quote! { ((*this).invoke) }); + + let mut tokens = quote! { + #doc + #features + #[repr(transparent)] + pub struct #ident(pub ::windows_core::IUnknown, #phantoms) where #constraints; + #features + impl<#constraints> #ident { + pub fn new<#fn_constraint>(invoke: F) -> Self { + let com = #boxed::<#generic_names F> { + vtable: &#boxed::<#generic_names F>::VTABLE, + count: ::windows_core::imp::RefCount::new(1), + invoke, + }; + unsafe { + ::core::mem::transmute(::std::boxed::Box::new(com)) + } + } + #invoke + } + #features + #[repr(C)] + struct #boxed<#generic_names #fn_constraint> where #constraints { + vtable: *const #vtbl<#generic_names>, + invoke: F, + count: ::windows_core::imp::RefCount, + } + #features + impl<#constraints #fn_constraint> #boxed<#generic_names F> { + const VTABLE: #vtbl<#generic_names> = #vtbl::<#generic_names>{ + base__: ::windows_core::IUnknown_Vtbl{QueryInterface: Self::QueryInterface, AddRef: Self::AddRef, Release: Self::Release}, + Invoke: Self::Invoke, + #(#named_phantoms)* + }; + unsafe extern "system" fn QueryInterface(this: *mut ::core::ffi::c_void, iid: &::windows_core::GUID, interface: *mut *const ::core::ffi::c_void) -> ::windows_core::HRESULT { + let this = this as *mut *mut ::core::ffi::c_void as *mut Self; + + *interface = if iid == &<#ident as ::windows_core::ComInterface>::IID || + iid == &<::windows_core::IUnknown as ::windows_core::ComInterface>::IID || + iid == &<::windows_core::imp::IAgileObject as ::windows_core::ComInterface>::IID { + &mut (*this).vtable as *mut _ as _ + } else { + ::core::ptr::null_mut() + }; + + // TODO: implement IMarshal + + if (*interface).is_null() { + ::windows_core::HRESULT(-2147467262) // E_NOINTERFACE + } else { + (*this).count.add_ref(); + ::windows_core::HRESULT(0) + } + } + unsafe extern "system" fn AddRef(this: *mut ::core::ffi::c_void) -> u32 { + let this = this as *mut *mut ::core::ffi::c_void as *mut Self; + (*this).count.add_ref() + } + unsafe extern "system" fn Release(this: *mut ::core::ffi::c_void) -> u32 { + let this = this as *mut *mut ::core::ffi::c_void as *mut Self; + let remaining = (*this).count.release(); + + if remaining == 0 { + let _ = ::std::boxed::Box::from_raw(this); + } + + remaining + } + unsafe extern "system" fn Invoke #vtbl_signature { + let this = this as *mut *mut ::core::ffi::c_void as *mut Self; + #invoke_upcall + } + } + }; + + tokens.combine(&writer.interface_core_traits(def, generics, &ident, &constraints, &phantoms, &features)); + tokens.combine(&writer.interface_trait(def, generics, &ident, &constraints, &features, true)); + tokens.combine(&writer.interface_winrt_trait(def, generics, &ident, &constraints, &phantoms, &features)); + tokens.combine(&writer.interface_vtbl(def, generics, &ident, &constraints, &features)); + tokens +} + +fn gen_fn_constraint(writer: &Writer, def: TypeDef, signature: &Signature) -> TokenStream { + let signature = writer.impl_signature(def, signature); + + quote! { F: FnMut #signature + ::core::marker::Send + 'static } +} diff --git a/vendor/windows-bindgen/src/enums.rs b/vendor/windows-bindgen/src/rust/enums.rs index ee7616fda..344ca28ae 100644 --- a/vendor/windows-bindgen/src/enums.rs +++ b/vendor/windows-bindgen/src/rust/enums.rs @@ -1,27 +1,26 @@ use super::*; -pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream { - let type_name = gen.reader.type_def_type_name(def); +pub fn writer(writer: &Writer, def: TypeDef) -> TokenStream { + let type_name = writer.reader.type_def_type_name(def); let ident = to_ident(type_name.name); - let underlying_type = gen.reader.type_def_underlying_type(def); - let underlying_type = gen.type_name(&underlying_type); - let is_scoped = gen.reader.type_def_is_scoped(def); - let cfg = gen.reader.type_def_cfg(def, &[]); - let doc = gen.cfg_doc(&cfg); - let features = gen.cfg_features(&cfg); - - let fields: Vec<(TokenStream, TokenStream)> = gen + let underlying_type = writer.reader.type_def_underlying_type(def); + let underlying_type = writer.type_name(&underlying_type); + + // TODO: unscoped enums should be removed from metadata + let is_scoped = writer.reader.type_def_flags(def).contains(TypeAttributes::WindowsRuntime) || writer.reader.has_attribute(def, "ScopedEnumAttribute"); + + let cfg = type_def_cfg(writer.reader, def, &[]); + let doc = writer.cfg_doc(&cfg); + let features = writer.cfg_features(&cfg); + + let fields: Vec<(TokenStream, TokenStream)> = writer .reader .type_def_fields(def) .filter_map(|field| { - if gen - .reader - .field_flags(field) - .contains(FieldAttributes::LITERAL) - { - let field_name = to_ident(gen.reader.field_name(field)); - let constant = gen.reader.field_constant(field).unwrap(); - let value = gen.value(&gen.reader.constant_value(constant)); + if writer.reader.field_flags(field).contains(FieldAttributes::Literal) { + let field_name = to_ident(writer.reader.field_name(field)); + let constant = writer.reader.field_constant(field).unwrap(); + let value = writer.value(&writer.reader.constant_value(constant)); Some((field_name, value)) } else { @@ -30,7 +29,7 @@ pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream { }) .collect(); - let eq = if gen.sys { + let eq = if writer.sys { quote! {} } else { quote! { @@ -39,7 +38,7 @@ pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream { } }; - let mut tokens = if is_scoped || !gen.sys { + let mut tokens = if is_scoped || !writer.sys { quote! { #doc #features @@ -55,48 +54,22 @@ pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream { } }; - tokens.combine(&if is_scoped { + if is_scoped { let fields = fields.iter().map(|(field_name, value)| { quote! { pub const #field_name: Self = Self(#value); } }); - quote! { + tokens.combine("e! { #features impl #ident { #(#fields)* } - } - } else if !gen.sys { - let fields = fields.iter().map(|(field_name, value)| { - quote! { - #doc - #features - pub const #field_name: #ident = #ident(#value); - } }); + } - quote! { - #(#fields)* - } - } else if !gen.standalone { - let fields = fields.iter().map(|(field_name, value)| { - quote! { - #doc - #features - pub const #field_name: #ident = #value; - } - }); - - quote! { - #(#fields)* - } - } else { - quote! {} - }); - - if is_scoped || !gen.sys { + if is_scoped || !writer.sys { tokens.combine("e! { #features impl ::core::marker::Copy for #ident {} @@ -109,7 +82,7 @@ pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream { }); } - if !gen.sys { + if !writer.sys { tokens.combine("e! { #features impl ::core::default::Default for #ident { @@ -120,12 +93,12 @@ pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream { }); } - if !gen.sys { + if !writer.sys { let name = type_name.name; tokens.combine("e! { #features - impl ::windows::core::TypeKind for #ident { - type TypeKind = ::windows::core::CopyType; + impl ::windows_core::TypeKind for #ident { + type TypeKind = ::windows_core::CopyType; } #features impl ::core::fmt::Debug for #ident { @@ -135,7 +108,12 @@ pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream { } }); - if gen.reader.type_def_is_flags(def) { + // Win32 enums use the Flags attribute. WinRT enums don't have the Flags attribute but are paritioned merely based + // on whether they are signed. + // TODO: Win32 metadata should just follow WinRT's example here. + let type_def_is_flags = writer.reader.has_attribute(def, "FlagsAttribute") || (writer.reader.type_def_flags(def).contains(TypeAttributes::WindowsRuntime) && writer.reader.type_def_underlying_type(def) == Type::U32); + + if type_def_is_flags { tokens.combine("e! { #features impl #ident { @@ -182,18 +160,13 @@ pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream { }); } - if gen - .reader - .type_def_flags(def) - .contains(TypeAttributes::WINRT) - { - let signature = - Literal::byte_string(gen.reader.type_def_signature(def, &[]).as_bytes()); + if writer.reader.type_def_flags(def).contains(TypeAttributes::WindowsRuntime) { + let signature = Literal::byte_string(type_def_signature(writer.reader, def, &[]).as_bytes()); tokens.combine("e! { #features - impl ::windows::core::RuntimeType for #ident { - const SIGNATURE: ::windows::imp::ConstBuffer = ::windows::imp::ConstBuffer::from_slice(#signature); + impl ::windows_core::RuntimeType for #ident { + const SIGNATURE: ::windows_core::imp::ConstBuffer = ::windows_core::imp::ConstBuffer::from_slice(#signature); } }); } diff --git a/vendor/windows-bindgen/src/extensions/impl/Foundation/Collections/Iterable.rs b/vendor/windows-bindgen/src/rust/extensions/impl/Foundation/Collections/Iterable.rs index 7d379fdf6..6bed10d68 100644 --- a/vendor/windows-bindgen/src/extensions/impl/Foundation/Collections/Iterable.rs +++ b/vendor/windows-bindgen/src/rust/extensions/impl/Foundation/Collections/Iterable.rs @@ -1,18 +1,18 @@ -#[::windows::core::implement(IIterable<T>)] +#[::windows_implement::implement(IIterable<T>)] struct StockIterable<T> where - T: ::windows::core::RuntimeType + 'static, - <T as ::windows::core::Type<T>>::Default: ::std::clone::Clone, + T: ::windows_core::RuntimeType + 'static, + <T as ::windows_core::Type<T>>::Default: ::std::clone::Clone, { values: std::vec::Vec<T::Default>, } impl<T> IIterable_Impl<T> for StockIterable<T> where - T: ::windows::core::RuntimeType, - <T as ::windows::core::Type<T>>::Default: ::std::clone::Clone, + T: ::windows_core::RuntimeType, + <T as ::windows_core::Type<T>>::Default: ::std::clone::Clone, { - fn First(&self) -> ::windows::core::Result<IIterator<T>> { + fn First(&self) -> ::windows_core::Result<IIterator<T>> { unsafe { // TODO: ideally we can do an AddRef rather than a QI here (via cast)... // and then we can get rid of the unsafe as well. @@ -25,11 +25,11 @@ where } } -#[::windows::core::implement(IIterator<T>)] +#[::windows_implement::implement(IIterator<T>)] struct StockIterator<T> where - T: ::windows::core::RuntimeType + 'static, - <T as ::windows::core::Type<T>>::Default: ::std::clone::Clone, + T: ::windows_core::RuntimeType + 'static, + <T as ::windows_core::Type<T>>::Default: ::std::clone::Clone, { owner: IIterable<T>, current: ::std::sync::atomic::AtomicUsize, @@ -37,29 +37,29 @@ where impl<T> IIterator_Impl<T> for StockIterator<T> where - T: ::windows::core::RuntimeType, - <T as ::windows::core::Type<T>>::Default: ::std::clone::Clone, + T: ::windows_core::RuntimeType, + <T as ::windows_core::Type<T>>::Default: ::std::clone::Clone, { - fn Current(&self) -> ::windows::core::Result<T> { - let owner: &StockIterable<T> = ::windows::core::AsImpl::as_impl(&self.owner); + fn Current(&self) -> ::windows_core::Result<T> { + let owner: &StockIterable<T> = unsafe { ::windows_core::AsImpl::as_impl(&self.owner) }; let current = self.current.load(::std::sync::atomic::Ordering::Relaxed); if owner.values.len() > current { T::from_default(&owner.values[current]) } else { - Err(::windows::imp::E_BOUNDS.into()) + Err(::windows_core::Error::from(::windows_core::imp::E_BOUNDS)) } } - fn HasCurrent(&self) -> ::windows::core::Result<bool> { - let owner: &StockIterable<T> = ::windows::core::AsImpl::as_impl(&self.owner); + fn HasCurrent(&self) -> ::windows_core::Result<bool> { + let owner: &StockIterable<T> = unsafe { ::windows_core::AsImpl::as_impl(&self.owner) }; let current = self.current.load(::std::sync::atomic::Ordering::Relaxed); Ok(owner.values.len() > current) } - fn MoveNext(&self) -> ::windows::core::Result<bool> { - let owner: &StockIterable<T> = ::windows::core::AsImpl::as_impl(&self.owner); + fn MoveNext(&self) -> ::windows_core::Result<bool> { + let owner: &StockIterable<T> = unsafe { ::windows_core::AsImpl::as_impl(&self.owner) }; let current = self.current.load(::std::sync::atomic::Ordering::Relaxed); if current < owner.values.len() { @@ -70,8 +70,8 @@ where Ok(owner.values.len() > current + 1) } - fn GetMany(&self, values: &mut [T::Default]) -> ::windows::core::Result<u32> { - let owner: &StockIterable<T> = ::windows::core::AsImpl::as_impl(&self.owner); + fn GetMany(&self, values: &mut [T::Default]) -> ::windows_core::Result<u32> { + let owner: &StockIterable<T> = unsafe { ::windows_core::AsImpl::as_impl(&self.owner) }; let current = self.current.load(::std::sync::atomic::Ordering::Relaxed); let actual = std::cmp::min(owner.values.len() - current, values.len()); @@ -79,17 +79,17 @@ where values.clone_from_slice(&owner.values[current..current + actual]); self.current .fetch_add(actual, ::std::sync::atomic::Ordering::Relaxed); - Ok(actual as _) + Ok(actual as u32) } } impl<T> ::core::convert::TryFrom<::std::vec::Vec<T::Default>> for IIterable<T> where - T: ::windows::core::RuntimeType, - <T as ::windows::core::Type<T>>::Default: ::std::clone::Clone, + T: ::windows_core::RuntimeType, + <T as ::windows_core::Type<T>>::Default: ::std::clone::Clone, { - type Error = ::windows::core::Error; - fn try_from(values: ::std::vec::Vec<T::Default>) -> ::windows::core::Result<Self> { + type Error = ::windows_core::Error; + fn try_from(values: ::std::vec::Vec<T::Default>) -> ::windows_core::Result<Self> { // TODO: should provide a fallible try_into or more explicit allocator Ok(StockIterable { values }.into()) } diff --git a/vendor/windows-bindgen/src/extensions/impl/Foundation/Collections/MapView.rs b/vendor/windows-bindgen/src/rust/extensions/impl/Foundation/Collections/MapView.rs index e8980e4d2..72b39f56e 100644 --- a/vendor/windows-bindgen/src/extensions/impl/Foundation/Collections/MapView.rs +++ b/vendor/windows-bindgen/src/rust/extensions/impl/Foundation/Collections/MapView.rs @@ -1,22 +1,22 @@ -#[windows::core::implement(IMapView<K, V>, IIterable<IKeyValuePair<K, V>>)] +#[::windows_implement::implement(IMapView<K, V>, IIterable<IKeyValuePair<K, V>>)] struct StockMapView<K, V> where - K: windows::core::RuntimeType + 'static, - V: windows::core::RuntimeType + 'static, - <K as windows::core::Type<K>>::Default: std::clone::Clone + std::cmp::Ord, - <V as windows::core::Type<V>>::Default: std::clone::Clone, + K: ::windows_core::RuntimeType + 'static, + V: ::windows_core::RuntimeType + 'static, + <K as ::windows_core::Type<K>>::Default: std::clone::Clone + std::cmp::Ord, + <V as ::windows_core::Type<V>>::Default: std::clone::Clone, { map: std::collections::BTreeMap<K::Default, V::Default>, } impl<K, V> IIterable_Impl<IKeyValuePair<K, V>> for StockMapView<K, V> where - K: windows::core::RuntimeType, - V: windows::core::RuntimeType, - <K as windows::core::Type<K>>::Default: std::clone::Clone + std::cmp::Ord, - <V as windows::core::Type<V>>::Default: std::clone::Clone, + K: ::windows_core::RuntimeType, + V: ::windows_core::RuntimeType, + <K as ::windows_core::Type<K>>::Default: std::clone::Clone + std::cmp::Ord, + <V as ::windows_core::Type<V>>::Default: std::clone::Clone, { - fn First(&self) -> windows::core::Result<IIterator<IKeyValuePair<K, V>>> { + fn First(&self) -> ::windows_core::Result<IIterator<IKeyValuePair<K, V>>> { unsafe { // TODO: ideally we can do an AddRef rather than a QI here (via cast)... // and then we can get rid of the unsafe as well. @@ -31,42 +31,42 @@ where impl<K, V> IMapView_Impl<K, V> for StockMapView<K, V> where - K: windows::core::RuntimeType, - V: windows::core::RuntimeType, - <K as windows::core::Type<K>>::Default: std::clone::Clone + std::cmp::Ord, - <V as windows::core::Type<V>>::Default: std::clone::Clone, + K: ::windows_core::RuntimeType, + V: ::windows_core::RuntimeType, + <K as ::windows_core::Type<K>>::Default: std::clone::Clone + std::cmp::Ord, + <V as ::windows_core::Type<V>>::Default: std::clone::Clone, { - fn Lookup(&self, key: &K::Default) -> windows::core::Result<V> { + fn Lookup(&self, key: &K::Default) -> ::windows_core::Result<V> { let value = self .map .get(key) - .ok_or_else(|| windows::core::Error::from(windows::imp::E_BOUNDS))?; + .ok_or_else(|| ::windows_core::Error::from(::windows_core::imp::E_BOUNDS))?; V::from_default(value) } - fn Size(&self) -> windows::core::Result<u32> { - Ok(self.map.len() as _) + fn Size(&self) -> ::windows_core::Result<u32> { + Ok(self.map.len() as u32) } - fn HasKey(&self, key: &K::Default) -> windows::core::Result<bool> { + fn HasKey(&self, key: &K::Default) -> ::windows_core::Result<bool> { Ok(self.map.contains_key(key)) } fn Split( &self, first: &mut std::option::Option<IMapView<K, V>>, second: &mut std::option::Option<IMapView<K, V>>, - ) -> windows::core::Result<()> { + ) -> ::windows_core::Result<()> { *first = None; *second = None; Ok(()) } } -#[::windows::core::implement(IIterator<IKeyValuePair<K, V>>)] +#[::windows_implement::implement(IIterator<IKeyValuePair<K, V>>)] struct StockMapViewIterator<'a, K, V> where - K: windows::core::RuntimeType + 'static, - V: windows::core::RuntimeType + 'static, - <K as windows::core::Type<K>>::Default: std::clone::Clone + std::cmp::Ord, - <V as windows::core::Type<V>>::Default: std::clone::Clone, + K: ::windows_core::RuntimeType + 'static, + V: ::windows_core::RuntimeType + 'static, + <K as ::windows_core::Type<K>>::Default: std::clone::Clone + std::cmp::Ord, + <V as ::windows_core::Type<V>>::Default: std::clone::Clone, { _owner: IIterable<IKeyValuePair<K, V>>, current: ::std::sync::RwLock<std::collections::btree_map::Iter<'a, K::Default, V::Default>>, @@ -74,12 +74,12 @@ where impl<'a, K, V> IIterator_Impl<IKeyValuePair<K, V>> for StockMapViewIterator<'a, K, V> where - K: windows::core::RuntimeType, - V: windows::core::RuntimeType, - <K as windows::core::Type<K>>::Default: std::clone::Clone + std::cmp::Ord, - <V as windows::core::Type<V>>::Default: std::clone::Clone, + K: ::windows_core::RuntimeType, + V: ::windows_core::RuntimeType, + <K as ::windows_core::Type<K>>::Default: std::clone::Clone + std::cmp::Ord, + <V as ::windows_core::Type<V>>::Default: std::clone::Clone, { - fn Current(&self) -> ::windows::core::Result<IKeyValuePair<K, V>> { + fn Current(&self) -> ::windows_core::Result<IKeyValuePair<K, V>> { let mut current = self.current.read().unwrap().clone().peekable(); if let Some((key, value)) = current.peek() { @@ -89,24 +89,24 @@ where } .into()) } else { - Err(windows::core::Error::from(windows::imp::E_BOUNDS)) + Err(::windows_core::Error::from(::windows_core::imp::E_BOUNDS)) } } - fn HasCurrent(&self) -> ::windows::core::Result<bool> { + fn HasCurrent(&self) -> ::windows_core::Result<bool> { let mut current = self.current.read().unwrap().clone().peekable(); Ok(current.peek().is_some()) } - fn MoveNext(&self) -> ::windows::core::Result<bool> { + fn MoveNext(&self) -> ::windows_core::Result<bool> { let mut current = self.current.write().unwrap(); current.next(); Ok(current.clone().peekable().peek().is_some()) } - fn GetMany(&self, pairs: &mut [Option<IKeyValuePair<K, V>>]) -> ::windows::core::Result<u32> { + fn GetMany(&self, pairs: &mut [Option<IKeyValuePair<K, V>>]) -> ::windows_core::Result<u32> { let mut current = self.current.write().unwrap(); let mut actual = 0; @@ -125,17 +125,17 @@ where } } - Ok(actual as _) + Ok(actual) } } -#[windows::core::implement(IKeyValuePair<K, V>)] +#[::windows_implement::implement(IKeyValuePair<K, V>)] struct StockKeyValuePair<K, V> where - K: windows::core::RuntimeType + 'static, - V: windows::core::RuntimeType + 'static, - <K as windows::core::Type<K>>::Default: std::clone::Clone, - <V as windows::core::Type<V>>::Default: std::clone::Clone, + K: ::windows_core::RuntimeType + 'static, + V: ::windows_core::RuntimeType + 'static, + <K as ::windows_core::Type<K>>::Default: std::clone::Clone, + <V as ::windows_core::Type<V>>::Default: std::clone::Clone, { key: K::Default, value: V::Default, @@ -143,15 +143,15 @@ where impl<K, V> IKeyValuePair_Impl<K, V> for StockKeyValuePair<K, V> where - K: windows::core::RuntimeType, - V: windows::core::RuntimeType, - <K as windows::core::Type<K>>::Default: std::clone::Clone, - <V as windows::core::Type<V>>::Default: std::clone::Clone, + K: ::windows_core::RuntimeType, + V: ::windows_core::RuntimeType, + <K as ::windows_core::Type<K>>::Default: std::clone::Clone, + <V as ::windows_core::Type<V>>::Default: std::clone::Clone, { - fn Key(&self) -> windows::core::Result<K> { + fn Key(&self) -> ::windows_core::Result<K> { K::from_default(&self.key) } - fn Value(&self) -> windows::core::Result<V> { + fn Value(&self) -> ::windows_core::Result<V> { V::from_default(&self.value) } } @@ -159,15 +159,15 @@ where impl<K, V> ::core::convert::TryFrom<std::collections::BTreeMap<K::Default, V::Default>> for IMapView<K, V> where - K: windows::core::RuntimeType, - V: windows::core::RuntimeType, - <K as windows::core::Type<K>>::Default: std::clone::Clone + std::cmp::Ord, - <V as windows::core::Type<V>>::Default: std::clone::Clone, + K: ::windows_core::RuntimeType, + V: ::windows_core::RuntimeType, + <K as ::windows_core::Type<K>>::Default: std::clone::Clone + std::cmp::Ord, + <V as ::windows_core::Type<V>>::Default: std::clone::Clone, { - type Error = ::windows::core::Error; + type Error = ::windows_core::Error; fn try_from( map: std::collections::BTreeMap<K::Default, V::Default>, - ) -> windows::core::Result<Self> { + ) -> ::windows_core::Result<Self> { // TODO: should provide a fallible try_into or more explicit allocator Ok(StockMapView { map }.into()) } diff --git a/vendor/windows-bindgen/src/extensions/impl/Foundation/Collections/VectorView.rs b/vendor/windows-bindgen/src/rust/extensions/impl/Foundation/Collections/VectorView.rs index c51dc0c8c..cc482b70f 100644 --- a/vendor/windows-bindgen/src/extensions/impl/Foundation/Collections/VectorView.rs +++ b/vendor/windows-bindgen/src/rust/extensions/impl/Foundation/Collections/VectorView.rs @@ -1,18 +1,18 @@ -#[windows::core::implement(IVectorView<T>, IIterable<T>)] +#[::windows_implement::implement(IVectorView<T>, IIterable<T>)] struct StockVectorView<T> where - T: windows::core::RuntimeType + 'static, - <T as windows::core::Type<T>>::Default: std::clone::Clone + std::cmp::PartialEq, + T: ::windows_core::RuntimeType + 'static, + <T as ::windows_core::Type<T>>::Default: std::clone::Clone + std::cmp::PartialEq, { values: std::vec::Vec<T::Default>, } impl<T> IIterable_Impl<T> for StockVectorView<T> where - T: windows::core::RuntimeType, - <T as windows::core::Type<T>>::Default: std::clone::Clone + std::cmp::PartialEq, + T: ::windows_core::RuntimeType, + <T as ::windows_core::Type<T>>::Default: std::clone::Clone + std::cmp::PartialEq, { - fn First(&self) -> windows::core::Result<IIterator<T>> { + fn First(&self) -> ::windows_core::Result<IIterator<T>> { unsafe { // TODO: ideally we can do an AddRef rather than a QI here (via cast)... // and then we can get rid of the unsafe as well. @@ -27,29 +27,29 @@ where impl<T> IVectorView_Impl<T> for StockVectorView<T> where - T: windows::core::RuntimeType, - <T as windows::core::Type<T>>::Default: std::clone::Clone + std::cmp::PartialEq, + T: ::windows_core::RuntimeType, + <T as ::windows_core::Type<T>>::Default: std::clone::Clone + std::cmp::PartialEq, { - fn GetAt(&self, index: u32) -> windows::core::Result<T> { + fn GetAt(&self, index: u32) -> ::windows_core::Result<T> { let item = self .values .get(index as usize) - .ok_or_else(|| windows::core::Error::from(windows::imp::E_BOUNDS))?; + .ok_or_else(|| ::windows_core::Error::from(::windows_core::imp::E_BOUNDS))?; T::from_default(item) } - fn Size(&self) -> windows::core::Result<u32> { - Ok(self.values.len() as _) + fn Size(&self) -> ::windows_core::Result<u32> { + Ok(self.values.len() as u32) } - fn IndexOf(&self, value: &T::Default, result: &mut u32) -> windows::core::Result<bool> { + fn IndexOf(&self, value: &T::Default, result: &mut u32) -> ::windows_core::Result<bool> { match self.values.iter().position(|element| element == value) { Some(index) => { - *result = index as _; + *result = index as u32; Ok(true) } None => Ok(false), } } - fn GetMany(&self, current: u32, values: &mut [T::Default]) -> windows::core::Result<u32> { + fn GetMany(&self, current: u32, values: &mut [T::Default]) -> ::windows_core::Result<u32> { let current = current as usize; if current >= self.values.len() { return Ok(0); @@ -57,15 +57,15 @@ where let actual = std::cmp::min(self.values.len() - current, values.len()); let (values, _) = values.split_at_mut(actual); values.clone_from_slice(&self.values[current..current + actual]); - Ok(actual as _) + Ok(actual as u32) } } -#[::windows::core::implement(IIterator<T>)] +#[::windows_implement::implement(IIterator<T>)] struct StockVectorViewIterator<T> where - T: ::windows::core::RuntimeType + 'static, - <T as ::windows::core::Type<T>>::Default: std::clone::Clone + std::cmp::PartialEq, + T: ::windows_core::RuntimeType + 'static, + <T as ::windows_core::Type<T>>::Default: std::clone::Clone + std::cmp::PartialEq, { owner: IIterable<T>, current: ::std::sync::atomic::AtomicUsize, @@ -73,29 +73,29 @@ where impl<T> IIterator_Impl<T> for StockVectorViewIterator<T> where - T: ::windows::core::RuntimeType, - <T as ::windows::core::Type<T>>::Default: std::clone::Clone + std::cmp::PartialEq, + T: ::windows_core::RuntimeType, + <T as ::windows_core::Type<T>>::Default: std::clone::Clone + std::cmp::PartialEq, { - fn Current(&self) -> ::windows::core::Result<T> { - let owner: &StockVectorView<T> = ::windows::core::AsImpl::as_impl(&self.owner); + fn Current(&self) -> ::windows_core::Result<T> { + let owner: &StockVectorView<T> = unsafe { ::windows_core::AsImpl::as_impl(&self.owner) }; let current = self.current.load(::std::sync::atomic::Ordering::Relaxed); if owner.values.len() > current { T::from_default(&owner.values[current]) } else { - Err(windows::core::Error::from(windows::imp::E_BOUNDS)) + Err(::windows_core::Error::from(::windows_core::imp::E_BOUNDS)) } } - fn HasCurrent(&self) -> ::windows::core::Result<bool> { - let owner: &StockVectorView<T> = ::windows::core::AsImpl::as_impl(&self.owner); + fn HasCurrent(&self) -> ::windows_core::Result<bool> { + let owner: &StockVectorView<T> = unsafe { ::windows_core::AsImpl::as_impl(&self.owner) }; let current = self.current.load(::std::sync::atomic::Ordering::Relaxed); Ok(owner.values.len() > current) } - fn MoveNext(&self) -> ::windows::core::Result<bool> { - let owner: &StockVectorView<T> = ::windows::core::AsImpl::as_impl(&self.owner); + fn MoveNext(&self) -> ::windows_core::Result<bool> { + let owner: &StockVectorView<T> = unsafe { ::windows_core::AsImpl::as_impl(&self.owner) }; let current = self.current.load(::std::sync::atomic::Ordering::Relaxed); if current < owner.values.len() { @@ -106,8 +106,8 @@ where Ok(owner.values.len() > current + 1) } - fn GetMany(&self, values: &mut [T::Default]) -> ::windows::core::Result<u32> { - let owner: &StockVectorView<T> = ::windows::core::AsImpl::as_impl(&self.owner); + fn GetMany(&self, values: &mut [T::Default]) -> ::windows_core::Result<u32> { + let owner: &StockVectorView<T> = unsafe { ::windows_core::AsImpl::as_impl(&self.owner) }; let current = self.current.load(::std::sync::atomic::Ordering::Relaxed); let actual = std::cmp::min(owner.values.len() - current, values.len()); @@ -115,17 +115,17 @@ where values.clone_from_slice(&owner.values[current..current + actual]); self.current .fetch_add(actual, ::std::sync::atomic::Ordering::Relaxed); - Ok(actual as _) + Ok(actual as u32) } } impl<T> ::core::convert::TryFrom<::std::vec::Vec<T::Default>> for IVectorView<T> where - T: ::windows::core::RuntimeType, - <T as ::windows::core::Type<T>>::Default: std::clone::Clone + std::cmp::PartialEq, + T: ::windows_core::RuntimeType, + <T as ::windows_core::Type<T>>::Default: std::clone::Clone + std::cmp::PartialEq, { - type Error = ::windows::core::Error; - fn try_from(values: ::std::vec::Vec<T::Default>) -> ::windows::core::Result<Self> { + type Error = ::windows_core::Error; + fn try_from(values: ::std::vec::Vec<T::Default>) -> ::windows_core::Result<Self> { // TODO: should provide a fallible try_into or more explicit allocator Ok(StockVectorView { values }.into()) } diff --git a/vendor/windows-bindgen/src/rust/extensions/mod.rs b/vendor/windows-bindgen/src/rust/extensions/mod.rs new file mode 100644 index 000000000..8d8f71ed6 --- /dev/null +++ b/vendor/windows-bindgen/src/rust/extensions/mod.rs @@ -0,0 +1,31 @@ +use super::*; + +pub fn gen_mod(writer: &Writer, namespace: &str) -> TokenStream { + if namespace == "Windows.Win32.UI.WindowsAndMessaging" { + return include_str!("mod/Win32/UI/WindowsAndMessaging/WindowLong.rs").into(); + } + + if writer.sys { + return "".into(); + } + + match namespace { + "Windows.Foundation.Numerics" => concat!(include_str!("mod/Foundation/Numerics/Matrix3x2.rs"), include_str!("mod/Foundation/Numerics/Matrix4x4.rs"), include_str!("mod/Foundation/Numerics/Vector2.rs"), include_str!("mod/Foundation/Numerics/Vector3.rs"), include_str!("mod/Foundation/Numerics/Vector4.rs"),), + "Windows.Foundation" => concat!(include_str!("mod/Foundation/TimeSpan.rs"),), + "Windows.Win32.Foundation" => concat!(include_str!("mod/Win32/Foundation/BOOL.rs"), include_str!("mod/Win32/Foundation/BOOLEAN.rs"), include_str!("mod/Win32/Foundation/NTSTATUS.rs"), include_str!("mod/Win32/Foundation/VARIANT_BOOL.rs"), include_str!("mod/Win32/Foundation/WIN32_ERROR.rs"),), + "Windows.Win32.Networking.WinSock" => concat!(include_str!("mod/Win32/Networking/WinSock/IN_ADDR.rs"), include_str!("mod/Win32/Networking/WinSock/IN6_ADDR.rs"), include_str!("mod/Win32/Networking/WinSock/SOCKADDR_IN.rs"), include_str!("mod/Win32/Networking/WinSock/SOCKADDR_IN6.rs"), include_str!("mod/Win32/Networking/WinSock/SOCKADDR_INET.rs"),), + "Windows.Win32.UI.WindowsAndMessaging" => { + include_str!("mod/Win32/UI/WindowsAndMessaging/WindowLong.rs") + } + _ => "", + } + .into() +} + +pub fn gen_impl(namespace: &str) -> TokenStream { + match namespace { + "Windows.Foundation.Collections" => concat!(include_str!("impl/Foundation/Collections/Iterable.rs"), include_str!("impl/Foundation/Collections/MapView.rs"), include_str!("impl/Foundation/Collections/VectorView.rs"),), + _ => "", + } + .into() +} diff --git a/vendor/windows-bindgen/src/extensions/mod/Foundation/Numerics/Matrix3x2.rs b/vendor/windows-bindgen/src/rust/extensions/mod/Foundation/Numerics/Matrix3x2.rs index 98be80636..98be80636 100644 --- a/vendor/windows-bindgen/src/extensions/mod/Foundation/Numerics/Matrix3x2.rs +++ b/vendor/windows-bindgen/src/rust/extensions/mod/Foundation/Numerics/Matrix3x2.rs diff --git a/vendor/windows-bindgen/src/extensions/mod/Foundation/Numerics/Matrix4x4.rs b/vendor/windows-bindgen/src/rust/extensions/mod/Foundation/Numerics/Matrix4x4.rs index fb5d60866..fb5d60866 100644 --- a/vendor/windows-bindgen/src/extensions/mod/Foundation/Numerics/Matrix4x4.rs +++ b/vendor/windows-bindgen/src/rust/extensions/mod/Foundation/Numerics/Matrix4x4.rs diff --git a/vendor/windows-bindgen/src/extensions/mod/Foundation/Numerics/Vector2.rs b/vendor/windows-bindgen/src/rust/extensions/mod/Foundation/Numerics/Vector2.rs index f37b4620b..f37b4620b 100644 --- a/vendor/windows-bindgen/src/extensions/mod/Foundation/Numerics/Vector2.rs +++ b/vendor/windows-bindgen/src/rust/extensions/mod/Foundation/Numerics/Vector2.rs diff --git a/vendor/windows-bindgen/src/extensions/mod/Foundation/Numerics/Vector3.rs b/vendor/windows-bindgen/src/rust/extensions/mod/Foundation/Numerics/Vector3.rs index 58dcf9653..58dcf9653 100644 --- a/vendor/windows-bindgen/src/extensions/mod/Foundation/Numerics/Vector3.rs +++ b/vendor/windows-bindgen/src/rust/extensions/mod/Foundation/Numerics/Vector3.rs diff --git a/vendor/windows-bindgen/src/extensions/mod/Foundation/Numerics/Vector4.rs b/vendor/windows-bindgen/src/rust/extensions/mod/Foundation/Numerics/Vector4.rs index 69609d906..69609d906 100644 --- a/vendor/windows-bindgen/src/extensions/mod/Foundation/Numerics/Vector4.rs +++ b/vendor/windows-bindgen/src/rust/extensions/mod/Foundation/Numerics/Vector4.rs diff --git a/vendor/windows-bindgen/src/extensions/mod/Foundation/TimeSpan.rs b/vendor/windows-bindgen/src/rust/extensions/mod/Foundation/TimeSpan.rs index 814b3d45b..814b3d45b 100644 --- a/vendor/windows-bindgen/src/extensions/mod/Foundation/TimeSpan.rs +++ b/vendor/windows-bindgen/src/rust/extensions/mod/Foundation/TimeSpan.rs diff --git a/vendor/windows-bindgen/src/extensions/mod/Win32/Foundation/BOOL.rs b/vendor/windows-bindgen/src/rust/extensions/mod/Win32/Foundation/BOOL.rs index f09ae9111..2499fa964 100644 --- a/vendor/windows-bindgen/src/extensions/mod/Win32/Foundation/BOOL.rs +++ b/vendor/windows-bindgen/src/rust/extensions/mod/Win32/Foundation/BOOL.rs @@ -4,11 +4,11 @@ impl BOOL { self.0 != 0 } #[inline] - pub fn ok(self) -> ::windows::core::Result<()> { + pub fn ok(self) -> ::windows_core::Result<()> { if self.as_bool() { Ok(()) } else { - Err(::windows::core::Error::from_win32()) + Err(::windows_core::Error::from_win32()) } } #[inline] @@ -66,8 +66,8 @@ impl ::core::ops::Not for BOOL { } } } -impl windows::core::IntoParam<BOOL> for bool { - fn into_param(self) -> windows::core::Param<BOOL> { - windows::core::Param::Owned(self.into()) +impl ::windows_core::IntoParam<BOOL> for bool { + fn into_param(self) -> ::windows_core::Param<BOOL> { + ::windows_core::Param::Owned(self.into()) } } diff --git a/vendor/windows-bindgen/src/extensions/mod/Win32/Foundation/BOOLEAN.rs b/vendor/windows-bindgen/src/rust/extensions/mod/Win32/Foundation/BOOLEAN.rs index 44afc65c2..dd113d100 100644 --- a/vendor/windows-bindgen/src/extensions/mod/Win32/Foundation/BOOLEAN.rs +++ b/vendor/windows-bindgen/src/rust/extensions/mod/Win32/Foundation/BOOLEAN.rs @@ -4,11 +4,11 @@ impl BOOLEAN { self.0 != 0 } #[inline] - pub fn ok(self) -> ::windows::core::Result<()> { + pub fn ok(self) -> ::windows_core::Result<()> { if self.as_bool() { Ok(()) } else { - Err(::windows::core::Error::from_win32()) + Err(::windows_core::Error::from_win32()) } } #[inline] diff --git a/vendor/windows-bindgen/src/rust/extensions/mod/Win32/Foundation/NTSTATUS.rs b/vendor/windows-bindgen/src/rust/extensions/mod/Win32/Foundation/NTSTATUS.rs new file mode 100644 index 000000000..324b4e3d5 --- /dev/null +++ b/vendor/windows-bindgen/src/rust/extensions/mod/Win32/Foundation/NTSTATUS.rs @@ -0,0 +1,32 @@ +impl NTSTATUS { + #[inline] + pub const fn is_ok(self) -> bool { + self.0 >= 0 + } + #[inline] + pub const fn is_err(self) -> bool { + !self.is_ok() + } + #[inline] + pub const fn to_hresult(self) -> ::windows_core::HRESULT { + ::windows_core::HRESULT(self.0 | 0x1000_0000) + } + #[inline] + pub fn ok(self) -> ::windows_core::Result<()> { + if self.is_ok() { + Ok(()) + } else { + Err(self.to_hresult().into()) + } + } +} +impl ::core::convert::From<NTSTATUS> for ::windows_core::HRESULT { + fn from(value: NTSTATUS) -> Self { + value.to_hresult() + } +} +impl ::core::convert::From<NTSTATUS> for ::windows_core::Error { + fn from(value: NTSTATUS) -> Self { + value.to_hresult().into() + } +} diff --git a/vendor/windows-bindgen/src/extensions/mod/Win32/Foundation/VARIANT_BOOL.rs b/vendor/windows-bindgen/src/rust/extensions/mod/Win32/Foundation/VARIANT_BOOL.rs index 3015224ef..7952f005e 100644 --- a/vendor/windows-bindgen/src/extensions/mod/Win32/Foundation/VARIANT_BOOL.rs +++ b/vendor/windows-bindgen/src/rust/extensions/mod/Win32/Foundation/VARIANT_BOOL.rs @@ -4,11 +4,11 @@ impl VARIANT_BOOL { self.0 != 0 } #[inline] - pub fn ok(self) -> ::windows::core::Result<()> { + pub fn ok(self) -> ::windows_core::Result<()> { if self.as_bool() { Ok(()) } else { - Err(::windows::core::Error::from_win32()) + Err(::windows_core::Error::from_win32()) } } #[inline] diff --git a/vendor/windows-bindgen/src/extensions/mod/Win32/Foundation/WIN32_ERROR.rs b/vendor/windows-bindgen/src/rust/extensions/mod/Win32/Foundation/WIN32_ERROR.rs index d875953b2..2c9441efb 100644 --- a/vendor/windows-bindgen/src/extensions/mod/Win32/Foundation/WIN32_ERROR.rs +++ b/vendor/windows-bindgen/src/rust/extensions/mod/Win32/Foundation/WIN32_ERROR.rs @@ -8,11 +8,11 @@ impl WIN32_ERROR { !self.is_ok() } #[inline] - pub const fn to_hresult(self) -> ::windows::core::HRESULT { - ::windows::core::HRESULT(if self.0 == 0 { self.0 } else { (self.0 & 0x0000_FFFF) | (7 << 16) | 0x8000_0000 } as _) + pub const fn to_hresult(self) -> ::windows_core::HRESULT { + ::windows_core::HRESULT(if self.0 == 0 { self.0 } else { (self.0 & 0x0000_FFFF) | (7 << 16) | 0x8000_0000 } as i32) } #[inline] - pub fn from_error(error: &::windows::core::Error) -> ::core::option::Option<Self> { + pub fn from_error(error: &::windows_core::Error) -> ::core::option::Option<Self> { let hresult = error.code().0 as u32; if ((hresult >> 16) & 0x7FF) == 7 { Some(Self(hresult & 0xFFFF)) @@ -21,21 +21,21 @@ impl WIN32_ERROR { } } #[inline] - pub const fn ok(self) -> ::windows::core::Result<()> { + pub fn ok(self) -> ::windows_core::Result<()> { if self.is_ok() { Ok(()) } else { - Err(::windows::core::Error { code: self.to_hresult(), info: None }) + Err(self.to_hresult().into()) } } } -impl ::core::convert::From<WIN32_ERROR> for ::windows::core::HRESULT { +impl ::core::convert::From<WIN32_ERROR> for ::windows_core::HRESULT { fn from(value: WIN32_ERROR) -> Self { value.to_hresult() } } -impl ::core::convert::From<WIN32_ERROR> for ::windows::core::Error { +impl ::core::convert::From<WIN32_ERROR> for ::windows_core::Error { fn from(value: WIN32_ERROR) -> Self { - Self { code: value.to_hresult(), info: None } + value.to_hresult().into() } } diff --git a/vendor/windows-bindgen/src/extensions/mod/Win32/Networking/WinSock/IN6_ADDR.rs b/vendor/windows-bindgen/src/rust/extensions/mod/Win32/Networking/WinSock/IN6_ADDR.rs index f4290fba6..f4290fba6 100644 --- a/vendor/windows-bindgen/src/extensions/mod/Win32/Networking/WinSock/IN6_ADDR.rs +++ b/vendor/windows-bindgen/src/rust/extensions/mod/Win32/Networking/WinSock/IN6_ADDR.rs diff --git a/vendor/windows-bindgen/src/extensions/mod/Win32/Networking/WinSock/IN_ADDR.rs b/vendor/windows-bindgen/src/rust/extensions/mod/Win32/Networking/WinSock/IN_ADDR.rs index d12af968b..d12af968b 100644 --- a/vendor/windows-bindgen/src/extensions/mod/Win32/Networking/WinSock/IN_ADDR.rs +++ b/vendor/windows-bindgen/src/rust/extensions/mod/Win32/Networking/WinSock/IN_ADDR.rs diff --git a/vendor/windows-bindgen/src/extensions/mod/Win32/Networking/WinSock/SOCKADDR_IN.rs b/vendor/windows-bindgen/src/rust/extensions/mod/Win32/Networking/WinSock/SOCKADDR_IN.rs index 68bfdc76d..68bfdc76d 100644 --- a/vendor/windows-bindgen/src/extensions/mod/Win32/Networking/WinSock/SOCKADDR_IN.rs +++ b/vendor/windows-bindgen/src/rust/extensions/mod/Win32/Networking/WinSock/SOCKADDR_IN.rs diff --git a/vendor/windows-bindgen/src/extensions/mod/Win32/Networking/WinSock/SOCKADDR_IN6.rs b/vendor/windows-bindgen/src/rust/extensions/mod/Win32/Networking/WinSock/SOCKADDR_IN6.rs index 7b76f2f7d..7b76f2f7d 100644 --- a/vendor/windows-bindgen/src/extensions/mod/Win32/Networking/WinSock/SOCKADDR_IN6.rs +++ b/vendor/windows-bindgen/src/rust/extensions/mod/Win32/Networking/WinSock/SOCKADDR_IN6.rs diff --git a/vendor/windows-bindgen/src/extensions/mod/Win32/Networking/WinSock/SOCKADDR_INET.rs b/vendor/windows-bindgen/src/rust/extensions/mod/Win32/Networking/WinSock/SOCKADDR_INET.rs index ccaf570c0..ccaf570c0 100644 --- a/vendor/windows-bindgen/src/extensions/mod/Win32/Networking/WinSock/SOCKADDR_INET.rs +++ b/vendor/windows-bindgen/src/rust/extensions/mod/Win32/Networking/WinSock/SOCKADDR_INET.rs diff --git a/vendor/windows-bindgen/src/extensions/mod/Win32/UI/WindowsAndMessaging/WindowLong.rs b/vendor/windows-bindgen/src/rust/extensions/mod/Win32/UI/WindowsAndMessaging/WindowLong.rs index cf1cc08d9..cf1cc08d9 100644 --- a/vendor/windows-bindgen/src/extensions/mod/Win32/UI/WindowsAndMessaging/WindowLong.rs +++ b/vendor/windows-bindgen/src/rust/extensions/mod/Win32/UI/WindowsAndMessaging/WindowLong.rs diff --git a/vendor/windows-bindgen/src/rust/functions.rs b/vendor/windows-bindgen/src/rust/functions.rs new file mode 100644 index 000000000..2dd4e0157 --- /dev/null +++ b/vendor/windows-bindgen/src/rust/functions.rs @@ -0,0 +1,275 @@ +use super::*; + +pub fn writer(writer: &Writer, namespace: &str, def: MethodDef) -> TokenStream { + // TODO: remove inline functions from metadata + if writer.reader.method_def_module_name(def) == "forceinline" { + return quote! {}; + } + + // TODO: remove ordinal functions from metadata + if let Some(impl_map) = writer.reader.method_def_impl_map(def) { + if writer.reader.impl_map_import_name(impl_map).starts_with('#') { + return quote! {}; + } + } + + if writer.sys { + gen_sys_function(writer, namespace, def) + } else { + gen_win_function(writer, namespace, def) + } +} + +fn gen_sys_function(writer: &Writer, namespace: &str, def: MethodDef) -> TokenStream { + let signature = method_def_signature(writer.reader, namespace, def, &[]); + let cfg = signature_cfg(writer.reader, def); + let mut tokens = writer.cfg_features(&cfg); + tokens.combine(&gen_link(writer, namespace, &signature, &cfg)); + tokens +} + +fn gen_win_function(writer: &Writer, namespace: &str, def: MethodDef) -> TokenStream { + let name = to_ident(writer.reader.method_def_name(def)); + let signature = method_def_signature(writer.reader, namespace, def, &[]); + let generics = writer.constraint_generics(&signature.params); + let where_clause = writer.where_clause(&signature.params); + let abi_return_type = writer.return_sig(&signature); + let cfg = signature_cfg(writer.reader, def); + let doc = writer.cfg_doc(&cfg); + let features = writer.cfg_features(&cfg); + let link = gen_link(writer, namespace, &signature, &cfg); + + let kind = signature_kind(writer.reader, &signature); + match kind { + SignatureKind::Query(_) => { + let args = writer.win32_args(&signature.params, kind); + let params = writer.win32_params(&signature.params, kind); + let generics = expand_generics(generics, quote!(T)); + let where_clause = expand_where_clause(where_clause, quote!(T: ::windows_core::ComInterface)); + + quote! { + #doc + #features + #[inline] + pub unsafe fn #name<#generics>(#params) -> ::windows_core::Result<T> #where_clause { + #link + let mut result__ = ::std::ptr::null_mut(); + #name(#args).from_abi(result__) + } + } + } + SignatureKind::QueryOptional(_) => { + let args = writer.win32_args(&signature.params, kind); + let params = writer.win32_params(&signature.params, kind); + let generics = expand_generics(generics, quote!(T)); + let where_clause = expand_where_clause(where_clause, quote!(T: ::windows_core::ComInterface)); + + quote! { + #doc + #features + #[inline] + pub unsafe fn #name<#generics>(#params result__: *mut ::core::option::Option<T>) -> ::windows_core::Result<()> #where_clause { + #link + #name(#args).ok() + } + } + } + SignatureKind::ResultValue => { + let args = writer.win32_args(&signature.params, kind); + let params = writer.win32_params(&signature.params, kind); + let return_type = signature.params[signature.params.len() - 1].ty.deref(); + let return_type = writer.type_name(&return_type); + + quote! { + #doc + #features + #[inline] + pub unsafe fn #name<#generics>(#params) -> ::windows_core::Result<#return_type> #where_clause { + #link + let mut result__ = ::std::mem::zeroed(); + #name(#args).from_abi(result__) + } + } + } + SignatureKind::ResultVoid => { + let args = writer.win32_args(&signature.params, kind); + let params = writer.win32_params(&signature.params, kind); + + quote! { + #doc + #features + #[inline] + pub unsafe fn #name<#generics>(#params) -> ::windows_core::Result<()> #where_clause { + #link + #name(#args).ok() + } + } + } + SignatureKind::ReturnValue => { + let args = writer.win32_args(&signature.params, kind); + let params = writer.win32_params(&signature.params, kind); + let return_type = signature.params[signature.params.len() - 1].ty.deref(); + let is_nullable = type_is_nullable(writer.reader, &return_type); + let return_type = writer.type_name(&return_type); + + if is_nullable { + quote! { + #doc + #features + #[inline] + pub unsafe fn #name<#generics>(#params) -> ::windows_core::Result<#return_type> #where_clause { + #link + let mut result__ = ::std::mem::zeroed(); + #name(#args); + ::windows_core::from_abi(result__.assume_init()) + } + } + } else { + quote! { + #doc + #features + #[inline] + pub unsafe fn #name<#generics>(#params) -> #return_type #where_clause { + #link + let mut result__ = ::std::mem::zeroed(); + #name(#args); + ::std::mem::transmute(result__) + } + } + } + } + SignatureKind::ReturnStruct | SignatureKind::PreserveSig => { + if handle_last_error(writer, def, &signature) { + let args = writer.win32_args(&signature.params, kind); + let params = writer.win32_params(&signature.params, kind); + let return_type = writer.type_name(&signature.return_type); + + quote! { + #doc + #features + #[inline] + pub unsafe fn #name<#generics>(#params) -> ::windows_core::Result<#return_type> #where_clause { + #link + let result__ = #name(#args); + (!result__.is_invalid()).then(|| result__).ok_or_else(::windows_core::Error::from_win32) + } + } + } else { + let args = writer.win32_args(&signature.params, kind); + let params = writer.win32_params(&signature.params, kind); + + quote! { + #doc + #features + #[inline] + pub unsafe fn #name<#generics>(#params) #abi_return_type #where_clause { + #link + #name(#args) + } + } + } + } + SignatureKind::ReturnVoid => { + let args = writer.win32_args(&signature.params, kind); + let params = writer.win32_params(&signature.params, kind); + let does_not_return = does_not_return(writer, def); + + quote! { + #doc + #features + #[inline] + pub unsafe fn #name<#generics>(#params) #does_not_return #where_clause { + #link + #name(#args) + } + } + } + } +} + +fn gen_link(writer: &Writer, namespace: &str, signature: &Signature, cfg: &Cfg) -> TokenStream { + let name = writer.reader.method_def_name(signature.def); + let ident = to_ident(name); + let library = writer.reader.method_def_module_name(signature.def); + let abi = method_def_extern_abi(writer.reader, signature.def); + + let symbol = if let Some(impl_map) = writer.reader.method_def_impl_map(signature.def) { writer.reader.impl_map_import_name(impl_map) } else { name }; + + let link_name = if symbol != name { + quote! { #[link_name = #symbol] } + } else { + quote! {} + }; + + let params = signature.params.iter().map(|p| { + let name = writer.param_name(p.def); + let tokens = if p.kind == SignatureParamKind::ValueType { writer.type_default_name(&p.ty) } else { writer.type_abi_name(&p.ty) }; + quote! { #name: #tokens } + }); + + let return_type = writer.return_sig(signature); + + let vararg = if writer.sys && signature.call_flags.contains(MethodCallAttributes::VARARG) { + "...".into() + } else { + quote! {} + }; + + if writer.std || !namespace.starts_with("Windows.") { + let library = library.trim_end_matches(".dll"); + + quote! { + #[link(name = #library)] + extern #abi { + #link_name + pub fn #ident(#(#params,)* #vararg) #return_type; + } + } + } else if let Some(library) = method_def_static_lib(writer.reader, signature.def) { + quote! { + #[link(name = #library, kind = "static")] + extern #abi { + #link_name + pub fn #ident(#(#params,)* #vararg) #return_type; + } + } + } else { + let symbol = if symbol != name { format!(" \"{symbol}\"") } else { String::new() }; + + let doc = if writer.sys { writer.cfg_doc(cfg).0 } else { String::new() }; + + let mut tokens = String::new(); + for param in params { + tokens.push_str(&format!("{}, ", param.as_str())); + } + tokens.push_str(&vararg.0); + let tokens = tokens.trim_end_matches(", "); + format!(r#"::windows_targets::link!("{library}" "{abi}"{symbol}{doc} fn {name}({tokens}){return_type});"#).into() + } +} + +fn does_not_return(writer: &Writer, def: MethodDef) -> TokenStream { + if writer.reader.has_attribute(def, "DoesNotReturnAttribute") { + quote! { -> ! } + } else { + quote! {} + } +} + +fn handle_last_error(writer: &Writer, def: MethodDef, signature: &Signature) -> bool { + if let Some(map) = writer.reader.method_def_impl_map(def) { + if writer.reader.impl_map_flags(map).contains(PInvokeAttributes::SupportsLastError) { + if let Type::TypeDef(return_type, _) = &signature.return_type { + if type_def_is_handle(writer.reader, *return_type) { + if writer.reader.type_def_underlying_type(*return_type).is_pointer() { + return true; + } + if !type_def_invalid_values(writer.reader, *return_type).is_empty() { + return true; + } + } + } + } + } + false +} diff --git a/vendor/windows-bindgen/src/handles.rs b/vendor/windows-bindgen/src/rust/handles.rs index 9ace4a1b6..e213679e0 100644 --- a/vendor/windows-bindgen/src/handles.rs +++ b/vendor/windows-bindgen/src/rust/handles.rs @@ -1,27 +1,21 @@ use super::*; -pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream { - if gen.sys { - gen_sys_handle(gen, def) +pub fn writer(writer: &Writer, def: TypeDef) -> TokenStream { + if writer.sys { + gen_sys_handle(writer, def) } else { - gen_win_handle(gen, def) + gen_win_handle(writer, def) } } -pub fn gen_sys_handle(gen: &Gen, def: TypeDef) -> TokenStream { - let ident = to_ident(gen.reader.type_def_name(def)); - match gen.reader.type_def_underlying_type(def) { - Type::ISize if gen.std => quote! { +pub fn gen_sys_handle(writer: &Writer, def: TypeDef) -> TokenStream { + let ident = to_ident(writer.reader.type_def_name(def)); + match writer.reader.type_def_underlying_type(def) { + Type::ISize if writer.std => quote! { pub type #ident = *mut ::core::ffi::c_void; }, - Type::USize if gen.std => quote! { - #[cfg(target_pointer_width = "32")] - pub type #ident = u32; - #[cfg(target_pointer_width = "64")] - pub type #ident = u64; - }, underlying_type => { - let signature = gen.type_default_name(&underlying_type); + let signature = writer.type_default_name(&underlying_type); quote! { pub type #ident = #signature; @@ -30,11 +24,11 @@ pub fn gen_sys_handle(gen: &Gen, def: TypeDef) -> TokenStream { } } -pub fn gen_win_handle(gen: &Gen, def: TypeDef) -> TokenStream { - let name = gen.reader.type_def_name(def); +pub fn gen_win_handle(writer: &Writer, def: TypeDef) -> TokenStream { + let name = writer.reader.type_def_name(def); let ident = to_ident(name); - let underlying_type = gen.reader.type_def_underlying_type(def); - let signature = gen.type_default_name(&underlying_type); + let underlying_type = writer.reader.type_def_underlying_type(def); + let signature = writer.type_default_name(&underlying_type); let check = if underlying_type.is_pointer() { quote! { impl #ident { @@ -44,7 +38,7 @@ pub fn gen_win_handle(gen: &Gen, def: TypeDef) -> TokenStream { } } } else { - let invalid = gen.reader.type_def_invalid_values(def); + let invalid = type_def_invalid_values(writer.reader, def); if !invalid.is_empty() { let invalid = invalid.iter().map(|value| { @@ -90,18 +84,23 @@ pub fn gen_win_handle(gen: &Gen, def: TypeDef) -> TokenStream { f.debug_tuple(#name).field(&self.0).finish() } } - impl ::windows::core::TypeKind for #ident { - type TypeKind = ::windows::core::CopyType; + impl ::windows_core::TypeKind for #ident { + type TypeKind = ::windows_core::CopyType; } }; - if let Some(dependency) = gen.reader.type_def_usable_for(def) { - let type_name = gen.reader.type_def_type_name(dependency); - let mut dependency = gen.namespace(type_name.namespace); + if let Some(dependency) = type_def_usable_for(writer.reader, def) { + let type_name = writer.reader.type_def_type_name(dependency); + let mut dependency = writer.namespace(type_name.namespace); dependency.push_str(type_name.name); tokens.combine("e! { - impl windows::core::CanInto<#dependency> for #ident {} + impl ::windows_core::CanInto<#dependency> for #ident {} + impl ::core::convert::From<#ident> for #dependency { + fn from(value: #ident) -> Self { + Self(value.0) + } + } }); } diff --git a/vendor/windows-bindgen/src/implements.rs b/vendor/windows-bindgen/src/rust/implements.rs index 3a3184b51..742ae9984 100644 --- a/vendor/windows-bindgen/src/implements.rs +++ b/vendor/windows-bindgen/src/rust/implements.rs @@ -1,92 +1,85 @@ use super::*; -pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream { - if gen.reader.type_def_kind(def) != TypeKind::Interface - || (!gen.component && !gen.reader.type_def_can_implement(def)) - { +pub fn writer(writer: &Writer, def: TypeDef) -> TokenStream { + if writer.reader.type_def_kind(def) != TypeKind::Interface || (!writer.implement && writer.reader.has_attribute(def, "ExclusiveToAttribute")) { return quote! {}; } - let generics: &Vec<Type> = &gen.reader.type_def_generics(def).collect(); - let type_ident = to_ident(gen.reader.type_def_name(def)); + let generics = &type_def_generics(writer.reader, def); + let type_ident = to_ident(writer.reader.type_def_name(def)); let impl_ident = type_ident.join("_Impl"); let vtbl_ident = type_ident.join("_Vtbl"); let implvtbl_ident = impl_ident.join("Vtbl"); - let constraints = gen.generic_constraints(generics); - let generic_names = gen.generic_names(generics); - let named_phantoms = gen.generic_named_phantoms(generics); - let cfg = gen.reader.type_def_cfg_impl(def, generics); - let doc = gen.cfg_doc(&cfg); - let features = gen.cfg_features(&cfg); + let constraints = writer.generic_constraints(generics); + let generic_names = writer.generic_names(generics); + let named_phantoms = writer.generic_named_phantoms(generics); + let cfg = type_def_cfg_impl(writer.reader, def, generics); + let doc = writer.cfg_doc(&cfg); + let features = writer.cfg_features(&cfg); let mut requires = quote! {}; let type_ident = quote! { #type_ident<#generic_names> }; - let vtables = gen.reader.type_def_vtables(def); + let vtables = type_def_vtables(writer.reader, def); let has_unknown_base = matches!(vtables.first(), Some(Type::IUnknown)); - fn gen_required_trait(gen: &Gen, def: TypeDef, generics: &[Type]) -> TokenStream { - let name = gen.type_def_name_imp(def, generics, "_Impl"); + fn gen_required_trait(writer: &Writer, def: TypeDef, generics: &[Type]) -> TokenStream { + let name = writer.type_def_name_imp(def, generics, "_Impl"); quote! { + #name } } - let mut matches = quote! { iid == &<#type_ident as ::windows::core::ComInterface>::IID }; + let mut matches = quote! { iid == &<#type_ident as ::windows_core::ComInterface>::IID }; - if let Some(Type::TypeDef((def, _))) = vtables.last() { - requires.combine(&gen_required_trait(gen, *def, &[])) + if let Some(Type::TypeDef(def, _)) = vtables.last() { + requires.combine(&gen_required_trait(writer, *def, &[])) } for def in &vtables { - if let Type::TypeDef((def, generics)) = def { - let name = gen.type_def_name(*def, generics); + if let Type::TypeDef(def, generics) = def { + let name = writer.type_def_name(*def, generics); matches.combine("e! { - || iid == &<#name as ::windows::core::ComInterface>::IID + || iid == &<#name as ::windows_core::ComInterface>::IID }) } } - if gen - .reader - .type_def_flags(def) - .contains(TypeAttributes::WINRT) - { + if writer.reader.type_def_flags(def).contains(TypeAttributes::WindowsRuntime) { // TODO: this awkward wrapping of TypeDefs needs fixing - for interface in gen - .reader - .type_interfaces(&Type::TypeDef((def, generics.to_vec()))) - { - if let Type::TypeDef((def, generics)) = interface.ty { - requires.combine(&gen_required_trait(gen, def, &generics)); + for interface in type_interfaces(writer.reader, &Type::TypeDef(def, generics.to_vec())) { + if let Type::TypeDef(def, generics) = interface.ty { + requires.combine(&gen_required_trait(writer, def, &generics)); } } } - let runtime_name = gen.runtime_name_trait(def, generics, &type_ident, &constraints, &features); + let runtime_name = writer.runtime_name_trait(def, generics, &type_ident, &constraints, &features); let mut method_names = MethodNames::new(); - method_names.add_vtable_types(gen, def); + method_names.add_vtable_types(writer, def); - let method_traits = gen.reader.type_def_methods(def).map(|method| { - let name = method_names.add(gen, method); - let signature = gen.reader.method_def_signature(method, generics); - let signature_tokens = gen.impl_signature(def, &signature); + let method_traits = writer.reader.type_def_methods(def).map(|method| { + let name = method_names.add(writer, method); + + let signature = method_def_signature(writer.reader, writer.reader.type_def_namespace(def), method, generics); + + let signature_tokens = writer.impl_signature(def, &signature); quote! { fn #name #signature_tokens; } }); let mut method_names = MethodNames::new(); - method_names.add_vtable_types(gen, def); + method_names.add_vtable_types(writer, def); - let method_impls = gen.reader.type_def_methods(def).map(|method| { - let name = method_names.add(gen, method); - let signature = gen.reader.method_def_signature(method, generics); - let vtbl_signature = gen.vtbl_signature(def, generics, &signature); + let method_impls = writer.reader.type_def_methods(def).map(|method| { + let name = method_names.add(writer, method); + let signature = method_def_signature(writer.reader, writer.reader.type_def_namespace(def), method, generics); + let vtbl_signature = writer.vtbl_signature(def, generics, &signature); - let invoke_upcall = if gen.reader.type_def_flags(def).contains(TypeAttributes::WINRT) { winrt_methods::gen_upcall(gen, &signature, quote! { this.#name }) } else { com_methods::gen_upcall(gen, &signature, quote! { this.#name }) }; + let invoke_upcall = if writer.reader.type_def_flags(def).contains(TypeAttributes::WindowsRuntime) { winrt_methods::gen_upcall(writer, &signature, quote! { this.#name }) } else { com_methods::gen_upcall(writer, &signature, quote! { this.#name }) }; if has_unknown_base { quote! { - unsafe extern "system" fn #name<#constraints Identity: ::windows::core::IUnknownImpl<Impl = Impl>, Impl: #impl_ident<#generic_names>, const OFFSET: isize> #vtbl_signature { + unsafe extern "system" fn #name<#constraints Identity: ::windows_core::IUnknownImpl<Impl = Impl>, Impl: #impl_ident<#generic_names>, const OFFSET: isize> #vtbl_signature { // offset the `this` pointer by `OFFSET` times the size of a pointer and cast it as an IUnknown implementation let this = (this as *const *const ()).offset(OFFSET) as *const Identity; let this = (*this).get_impl(); @@ -96,7 +89,7 @@ pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream { } else { quote! { unsafe extern "system" fn #name<Impl: #impl_ident> #vtbl_signature { - let this = (this as *mut *mut ::core::ffi::c_void) as *const ::windows::core::ScopedHeap; + let this = (this as *mut *mut ::core::ffi::c_void) as *const ::windows_core::ScopedHeap; let this = &*((*this).this as *const Impl); #invoke_upcall } @@ -107,10 +100,10 @@ pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream { let mut methods = quote! {}; match vtables.last() { - Some(Type::IUnknown) => methods.combine("e! { base__: ::windows::core::IUnknown_Vtbl::new::<Identity, OFFSET>(), }), - Some(Type::IInspectable) => methods.combine("e! { base__: ::windows::core::IInspectable_Vtbl::new::<Identity, #type_ident, OFFSET>(), }), - Some(Type::TypeDef((def, generics))) => { - let name = gen.type_def_name_imp(*def, generics, "_Vtbl"); + Some(Type::IUnknown) => methods.combine("e! { base__: ::windows_core::IUnknown_Vtbl::new::<Identity, OFFSET>(), }), + Some(Type::IInspectable) => methods.combine("e! { base__: ::windows_core::IInspectable_Vtbl::new::<Identity, #type_ident, OFFSET>(), }), + Some(Type::TypeDef(def, generics)) => { + let name = writer.type_def_name_imp(*def, generics, "_Vtbl"); if has_unknown_base { methods.combine("e! { base__: #name::new::<Identity, Impl, OFFSET>(), }); } else { @@ -121,10 +114,10 @@ pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream { } let mut method_names = MethodNames::new(); - method_names.add_vtable_types(gen, def); + method_names.add_vtable_types(writer, def); - for method in gen.reader.type_def_methods(def) { - let name = method_names.add(gen, method); + for method in writer.reader.type_def_methods(def) { + let name = method_names.add(writer, method); if has_unknown_base { methods.combine("e! { #name: #name::<#generic_names Identity, Impl, OFFSET>, }); } else { @@ -142,14 +135,14 @@ pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream { #runtime_name #features impl<#constraints> #vtbl_ident<#generic_names> { - pub const fn new<Identity: ::windows::core::IUnknownImpl<Impl = Impl>, Impl: #impl_ident<#generic_names>, const OFFSET: isize>() -> #vtbl_ident<#generic_names> { + pub const fn new<Identity: ::windows_core::IUnknownImpl<Impl = Impl>, Impl: #impl_ident<#generic_names>, const OFFSET: isize>() -> #vtbl_ident<#generic_names> { #(#method_impls)* Self{ #methods #(#named_phantoms)* } } - pub fn matches(iid: &windows::core::GUID) -> bool { + pub fn matches(iid: &::windows_core::GUID) -> bool { #matches } } @@ -180,10 +173,10 @@ pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream { } #features impl #type_ident { - pub fn new<'a, T: #impl_ident>(this: &'a T) -> ::windows::core::ScopedInterface<'a, Self> { - let this = ::windows::core::ScopedHeap { vtable: &#implvtbl_ident::<T>::VTABLE as *const _ as *const _, this: this as *const _ as *const _ }; + pub fn new<'a, T: #impl_ident>(this: &'a T) -> ::windows_core::ScopedInterface<'a, Self> { + let this = ::windows_core::ScopedHeap { vtable: &#implvtbl_ident::<T>::VTABLE as *const _ as *const _, this: this as *const _ as *const _ }; let this = ::std::mem::ManuallyDrop::new(::std::boxed::Box::new(this)); - unsafe { ::windows::core::ScopedInterface::new(::std::mem::transmute(&this.vtable)) } + unsafe { ::windows_core::ScopedInterface::new(::std::mem::transmute(&this.vtable)) } } } } diff --git a/vendor/windows-bindgen/src/rust/interfaces.rs b/vendor/windows-bindgen/src/rust/interfaces.rs new file mode 100644 index 000000000..a552af433 --- /dev/null +++ b/vendor/windows-bindgen/src/rust/interfaces.rs @@ -0,0 +1,149 @@ +use super::*; + +pub fn writer(writer: &Writer, def: TypeDef) -> TokenStream { + if writer.sys { + gen_sys_interface(writer, def) + } else { + gen_win_interface(writer, def) + } +} + +fn gen_sys_interface(writer: &Writer, def: TypeDef) -> TokenStream { + let name = writer.reader.type_def_name(def); + let ident = to_ident(name); + + if type_def_is_exclusive(writer.reader, def) { + quote! {} + } else { + quote! { + pub type #ident = *mut ::core::ffi::c_void; + } + } +} + +fn gen_win_interface(writer: &Writer, def: TypeDef) -> TokenStream { + let generics = &type_def_generics(writer.reader, def); + let ident = writer.type_def_name(def, generics); + let is_exclusive = type_def_is_exclusive(writer.reader, def); + let phantoms = writer.generic_phantoms(generics); + let constraints = writer.generic_constraints(generics); + let cfg = type_def_cfg(writer.reader, def, &[]); + let doc = writer.cfg_doc(&cfg); + let features = writer.cfg_features(&cfg); + let interfaces = type_interfaces(writer.reader, &Type::TypeDef(def, generics.to_vec())); + let vtables = type_def_vtables(writer.reader, def); + let has_unknown_base = matches!(vtables.first(), Some(Type::IUnknown)); + + let mut tokens = if is_exclusive { + quote! { #[doc(hidden)] } + } else { + quote! { #doc } + }; + + if has_unknown_base { + tokens.combine("e! { + #features + #[repr(transparent)] + pub struct #ident(::windows_core::IUnknown, #phantoms) where #constraints; + }); + } else { + tokens.combine("e! { + #features + #[repr(transparent)] + pub struct #ident(::std::ptr::NonNull<::std::ffi::c_void>); + }); + } + + if !is_exclusive { + let mut methods = quote! {}; + // We need to distinguish between public and virtual methods because some WinRT type hierarchies inherit colliding (overloaded) + // methods that must be distinguishable. + let method_names = &mut MethodNames::new(); + let virtual_names = &mut MethodNames::new(); + + if writer.reader.type_def_flags(def).contains(TypeAttributes::WindowsRuntime) { + for method in writer.reader.type_def_methods(def) { + methods.combine(&winrt_methods::writer(writer, def, generics, InterfaceKind::Default, method, method_names, virtual_names)); + } + for interface in &interfaces { + if let Type::TypeDef(def, generics) = &interface.ty { + for method in writer.reader.type_def_methods(*def) { + methods.combine(&winrt_methods::writer(writer, *def, generics, InterfaceKind::None, method, method_names, virtual_names)); + } + } + } + } else { + let mut bases = vtables.len(); + for ty in &vtables { + match ty { + Type::IUnknown | Type::IInspectable => {} + Type::TypeDef(def, _) => { + let kind = if writer.reader.type_def_type_name(*def) == TypeName::IDispatch { InterfaceKind::None } else { InterfaceKind::Default }; + for method in writer.reader.type_def_methods(*def) { + methods.combine(&com_methods::writer(writer, *def, kind, method, method_names, virtual_names, bases)); + } + } + rest => unimplemented!("{rest:?}"), + } + + bases -= 1; + } + for method in writer.reader.type_def_methods(def) { + methods.combine(&com_methods::writer(writer, def, InterfaceKind::Default, method, method_names, virtual_names, 0)); + } + } + + tokens.combine("e! { + #features + impl<#constraints> #ident { + #methods + } + }); + + if !vtables.is_empty() && generics.is_empty() { + let mut hierarchy = format!("::windows_core::imp::interface_hierarchy!({ident}"); + let mut hierarchy_cfg = cfg.clone(); + + for ty in &vtables { + let into = writer.type_name(ty); + + write!(&mut hierarchy, ", {into}").unwrap(); + hierarchy_cfg = hierarchy_cfg.union(&type_cfg(writer.reader, ty)); + } + + hierarchy.push_str(");"); + tokens.combine(&writer.cfg_features(&hierarchy_cfg)); + tokens.push_str(&hierarchy); + } else { + for ty in &vtables { + let into = writer.type_name(ty); + let cfg = writer.cfg_features(&cfg.union(&type_cfg(writer.reader, ty))); + tokens.combine("e! { + #cfg + impl<#constraints> ::windows_core::CanInto<#into> for #ident {} + }); + } + } + + if writer.reader.type_def_flags(def).contains(TypeAttributes::WindowsRuntime) { + for interface in &interfaces { + let into = writer.type_name(&interface.ty); + let cfg = writer.cfg_features(&cfg.union(&type_cfg(writer.reader, &interface.ty))); + tokens.combine("e! { + #cfg + impl<#constraints> ::windows_core::CanTryInto<#into> for #ident {} + }); + } + } + + tokens.combine(&writer.interface_core_traits(def, generics, &ident, &constraints, &phantoms, &features)); + tokens.combine(&writer.interface_winrt_trait(def, generics, &ident, &constraints, &phantoms, &features)); + tokens.combine(&writer.async_get(def, generics, &ident, &constraints, &phantoms, &features)); + tokens.combine(&iterators::writer(writer, def, generics, &ident, &constraints, &phantoms, &cfg)); + tokens.combine(&writer.agile(def, &ident, &constraints, &features)); + } + + tokens.combine(&writer.interface_trait(def, generics, &ident, &constraints, &features, has_unknown_base)); + tokens.combine(&writer.interface_vtbl(def, generics, &ident, &constraints, &features)); + tokens +} diff --git a/vendor/windows-bindgen/src/iterators.rs b/vendor/windows-bindgen/src/rust/iterators.rs index 49a90adf2..63ba56aaf 100644 --- a/vendor/windows-bindgen/src/iterators.rs +++ b/vendor/windows-bindgen/src/rust/iterators.rs @@ -1,19 +1,11 @@ use super::*; -pub fn gen( - gen: &Gen, - def: TypeDef, - generics: &[Type], - ident: &TokenStream, - constraints: &TokenStream, - _phantoms: &TokenStream, - cfg: &Cfg, -) -> TokenStream { - match gen.reader.type_def_type_name(def) { +pub fn writer(writer: &Writer, def: TypeDef, generics: &[Type], ident: &TokenStream, constraints: &TokenStream, _phantoms: &TokenStream, cfg: &Cfg) -> TokenStream { + match writer.reader.type_def_type_name(def) { // If the type is IIterator<T> then simply implement the Iterator trait over top. TypeName::IIterator => { return quote! { - impl<T: ::windows::core::RuntimeType> ::core::iter::Iterator for IIterator<T> { + impl<T: ::windows_core::RuntimeType> ::core::iter::Iterator for IIterator<T> { type Item = T; fn next(&mut self) -> ::core::option::Option<Self::Item> { @@ -32,7 +24,7 @@ pub fn gen( // IIterator<T> returned by first() to implement the Iterator trait. TypeName::IIterable => { return quote! { - impl<T: ::windows::core::RuntimeType> ::core::iter::IntoIterator for IIterable<T> { + impl<T: ::windows_core::RuntimeType> ::core::iter::IntoIterator for IIterable<T> { type Item = T; type IntoIter = IIterator<Self::Item>; @@ -40,7 +32,7 @@ pub fn gen( ::core::iter::IntoIterator::into_iter(&self) } } - impl<T: ::windows::core::RuntimeType> ::core::iter::IntoIterator for &IIterable<T> { + impl<T: ::windows_core::RuntimeType> ::core::iter::IntoIterator for &IIterable<T> { type Item = T; type IntoIter = IIterator<Self::Item>; @@ -54,18 +46,18 @@ pub fn gen( // If the type is IVectorView<T> then provide the VectorViewIterator fast iterator. TypeName::IVectorView => { return quote! { - pub struct VectorViewIterator<T: ::windows::core::RuntimeType + 'static> { + pub struct VectorViewIterator<T: ::windows_core::RuntimeType + 'static> { vector: ::core::option::Option<IVectorView<T>>, current: u32, } - impl<T: ::windows::core::RuntimeType> VectorViewIterator<T> { + impl<T: ::windows_core::RuntimeType> VectorViewIterator<T> { pub fn new(vector: ::core::option::Option<IVectorView<T>>) -> Self { Self { vector, current: 0 } } } - impl<T: ::windows::core::RuntimeType> ::core::iter::Iterator for VectorViewIterator<T> { + impl<T: ::windows_core::RuntimeType> ::core::iter::Iterator for VectorViewIterator<T> { type Item = T; fn next(&mut self) -> ::core::option::Option<Self::Item> { @@ -80,7 +72,7 @@ pub fn gen( } } - impl<T: ::windows::core::RuntimeType> ::core::iter::IntoIterator for IVectorView<T> { + impl<T: ::windows_core::RuntimeType> ::core::iter::IntoIterator for IVectorView<T> { type Item = T; type IntoIter = VectorViewIterator<Self::Item>; @@ -88,7 +80,7 @@ pub fn gen( ::core::iter::IntoIterator::into_iter(&self) } } - impl<T: ::windows::core::RuntimeType> ::core::iter::IntoIterator for &IVectorView<T> { + impl<T: ::windows_core::RuntimeType> ::core::iter::IntoIterator for &IVectorView<T> { type Item = T; type IntoIter = VectorViewIterator<Self::Item>; @@ -101,18 +93,18 @@ pub fn gen( } TypeName::IVector => { return quote! { - pub struct VectorIterator<T: ::windows::core::RuntimeType + 'static> { + pub struct VectorIterator<T: ::windows_core::RuntimeType + 'static> { vector: ::core::option::Option<IVector<T>>, current: u32, } - impl<T: ::windows::core::RuntimeType> VectorIterator<T> { + impl<T: ::windows_core::RuntimeType> VectorIterator<T> { pub fn new(vector: ::core::option::Option<IVector<T>>) -> Self { Self { vector, current: 0 } } } - impl<T: ::windows::core::RuntimeType> ::core::iter::Iterator for VectorIterator<T> { + impl<T: ::windows_core::RuntimeType> ::core::iter::Iterator for VectorIterator<T> { type Item = T; fn next(&mut self) -> ::core::option::Option<Self::Item> { @@ -127,7 +119,7 @@ pub fn gen( } } - impl<T: ::windows::core::RuntimeType> ::core::iter::IntoIterator for IVector<T> { + impl<T: ::windows_core::RuntimeType> ::core::iter::IntoIterator for IVector<T> { type Item = T; type IntoIter = VectorIterator<Self::Item>; @@ -135,7 +127,7 @@ pub fn gen( ::core::iter::IntoIterator::into_iter(&self) } } - impl<T: ::windows::core::RuntimeType> ::core::iter::IntoIterator for &IVector<T> { + impl<T: ::windows_core::RuntimeType> ::core::iter::IntoIterator for &IVector<T> { type Item = T; type IntoIter = VectorIterator<Self::Item>; @@ -149,23 +141,20 @@ pub fn gen( _ => {} } - let wfc = gen.namespace("Windows.Foundation.Collections"); + let wfc = writer.namespace("Windows.Foundation.Collections"); let mut iterable = None; - let interfaces = gen - .reader - .type_interfaces(&Type::TypeDef((def, generics.to_vec()))); + let interfaces = type_interfaces(writer.reader, &Type::TypeDef(def, generics.to_vec())); // If the class or interface is not one of the well-known collection interfaces, we then see whether it // implements any one of them. Here is where we favor IVectorView/IVector over IIterable. for interface in interfaces { - if let Type::TypeDef((interface, interface_generics)) = &interface.ty { - match gen.reader.type_def_type_name(*interface) { + if let Type::TypeDef(interface, interface_generics) = &interface.ty { + match writer.reader.type_def_type_name(*interface) { TypeName::IVectorView => { - let item = gen.type_name(&interface_generics[0]); + let item = writer.type_name(&interface_generics[0]); let mut cfg = cfg.clone(); - gen.reader - .type_def_cfg_combine(*interface, interface_generics, &mut cfg); - let features = gen.cfg_features(&cfg); + type_def_cfg_combine(writer.reader, *interface, interface_generics, &mut cfg); + let features = writer.cfg_features(&cfg); return quote! { #features @@ -183,17 +172,16 @@ pub fn gen( type IntoIter = #wfc VectorViewIterator<Self::Item>; fn into_iter(self) -> Self::IntoIter { - #wfc VectorViewIterator::new(::windows::core::ComInterface::cast(self).ok()) + #wfc VectorViewIterator::new(::windows_core::ComInterface::cast(self).ok()) } } }; } TypeName::IVector => { - let item = gen.type_name(&interface_generics[0]); + let item = writer.type_name(&interface_generics[0]); let mut cfg = cfg.clone(); - gen.reader - .type_def_cfg_combine(*interface, interface_generics, &mut cfg); - let features = gen.cfg_features(&cfg); + type_def_cfg_combine(writer.reader, *interface, interface_generics, &mut cfg); + let features = writer.cfg_features(&cfg); return quote! { #features @@ -211,7 +199,7 @@ pub fn gen( type IntoIter = #wfc VectorIterator<Self::Item>; fn into_iter(self) -> Self::IntoIter { - #wfc VectorIterator::new(::windows::core::ComInterface::cast(self).ok()) + #wfc VectorIterator::new(::windows_core::ComInterface::cast(self).ok()) } } }; @@ -227,11 +215,10 @@ pub fn gen( match iterable { None => TokenStream::new(), Some((interface, interface_generics)) => { - let item = gen.type_name(&interface_generics[0]); + let item = writer.type_name(&interface_generics[0]); let mut cfg = cfg.clone(); - gen.reader - .type_def_cfg_combine(interface, &interface_generics, &mut cfg); - let features = gen.cfg_features(&cfg); + type_def_cfg_combine(writer.reader, interface, &interface_generics, &mut cfg); + let features = writer.cfg_features(&cfg); quote! { #features diff --git a/vendor/windows-bindgen/src/rust/method_names.rs b/vendor/windows-bindgen/src/rust/method_names.rs new file mode 100644 index 000000000..2d5a508ae --- /dev/null +++ b/vendor/windows-bindgen/src/rust/method_names.rs @@ -0,0 +1,30 @@ +use super::*; + +pub struct MethodNames(BTreeMap<String, u32>); + +impl MethodNames { + pub fn new() -> Self { + Self(BTreeMap::new()) + } + + pub fn add(&mut self, writer: &Writer, method: MethodDef) -> TokenStream { + let name = method_def_special_name(writer.reader, method); + let overload = self.0.entry(name.to_string()).or_insert(0); + *overload += 1; + if *overload > 1 { + format!("{name}{overload}").into() + } else { + to_ident(&name) + } + } + + pub fn add_vtable_types(&mut self, writer: &Writer, def: TypeDef) { + for def in type_def_vtables(writer.reader, def) { + if let Type::TypeDef(def, _) = def { + for method in writer.reader.type_def_methods(def) { + self.add(writer, method); + } + } + } + } +} diff --git a/vendor/windows-bindgen/src/rust/mod.rs b/vendor/windows-bindgen/src/rust/mod.rs new file mode 100644 index 000000000..0f781c8f8 --- /dev/null +++ b/vendor/windows-bindgen/src/rust/mod.rs @@ -0,0 +1,280 @@ +mod cfg; +mod classes; +mod com_methods; +mod constants; +mod delegates; +mod enums; +mod extensions; +mod functions; +mod handles; +mod implements; +mod interfaces; +mod iterators; +mod method_names; +mod standalone; +mod structs; +mod try_format; +mod winrt_methods; +mod writer; +use super::*; +use crate::{Error, Result, Tree}; +use cfg::*; +use rayon::prelude::*; + +pub fn from_reader(reader: &metadata::Reader, filter: &metadata::Filter, mut config: std::collections::BTreeMap<&str, &str>, output: &str) -> Result<()> { + let mut writer = Writer::new(reader, filter, output); + writer.package = config.remove("package").is_some(); + writer.flatten = config.remove("flatten").is_some(); + writer.std = config.remove("std").is_some(); + writer.sys = writer.std || config.remove("sys").is_some(); + writer.implement = config.remove("implement").is_some(); + writer.minimal = config.remove("minimal").is_some(); + + if writer.package && writer.flatten { + return Err(Error::new("cannot combine `package` and `flatten` configuration values")); + } + + if writer.implement && writer.sys { + return Err(Error::new("cannot combine `implement` and `sys` configuration values")); + } + + if let Some((key, _)) = config.first_key_value() { + return Err(Error::new(&format!("invalid configuration value `{key}`"))); + } + + if writer.package { + gen_package(&writer) + } else { + gen_file(&writer) + } +} + +fn gen_file(writer: &Writer) -> Result<()> { + // TODO: harmonize this output code so we don't need these two wildly differnt code paths + // there should be a simple way to generate the with or without namespaces. + + if writer.flatten { + let tokens = standalone::standalone_imp(writer); + crate::write_to_file(writer.output, try_format(writer, &tokens)) + } else { + let mut tokens = String::new(); + let root = Tree::new(writer.reader, writer.filter); + + for tree in root.nested.values() { + tokens.push_str(&namespace(writer, tree)); + } + + crate::write_to_file(writer.output, try_format(writer, &tokens)) + } +} + +fn gen_package(writer: &Writer) -> Result<()> { + let directory = crate::directory(writer.output); + let root = Tree::new(writer.reader, writer.filter); + let mut root_len = 0; + + for tree in root.nested.values() { + root_len = tree.namespace.len(); + _ = std::fs::remove_dir_all(format!("{directory}/{}", tree.namespace)); + } + + let trees = root.flatten(); + + trees.par_iter().try_for_each(|tree| { + let directory = format!("{directory}/{}", tree.namespace.replace('.', "/")); + let mut tokens = namespace(writer, tree); + + let tokens_impl = if !writer.sys { namespace_impl(writer, tree) } else { String::new() }; + + if !writer.sys && !tokens_impl.is_empty() { + tokens.push_str("#[cfg(feature = \"implement\")]\n::core::include!(\"impl.rs\");\n"); + } + + let output = format!("{directory}/mod.rs"); + crate::write_to_file(&output, try_format(writer, &tokens))?; + + if !writer.sys && !tokens_impl.is_empty() { + let output = format!("{directory}/impl.rs"); + crate::write_to_file(&output, try_format(writer, &tokens_impl))?; + } + + Ok::<(), Error>(()) + })?; + + let cargo_toml = format!("{}/Cargo.toml", crate::directory(directory)); + let mut toml = String::new(); + + for line in crate::read_file_lines(&cargo_toml)? { + toml.push_str(&line); + toml.push('\n'); + + if line == "# generated features" { + break; + } + } + + for tree in trees.iter().skip(1) { + let feature = tree.namespace[root_len + 1..].replace('.', "_"); + + if let Some(pos) = feature.rfind('_') { + let dependency = &feature[..pos]; + + toml.push_str(&format!("{feature} = [\"{dependency}\"]\n")); + } else { + toml.push_str(&format!("{feature} = []\n")); + } + } + + crate::write_to_file(&cargo_toml, toml) +} + +use crate::tokens::*; +use metadata::*; +use method_names::*; +use std::collections::*; +use std::fmt::Write; +use try_format::*; +use writer::*; + +fn namespace(writer: &Writer, tree: &Tree) -> String { + let writer = &mut writer.clone(); + writer.namespace = tree.namespace; + let mut tokens = TokenStream::new(); + + for (name, tree) in &tree.nested { + let name = to_ident(name); + let namespace_feature = tree.namespace[tree.namespace.find('.').unwrap() + 1..].replace('.', "_"); + if writer.package { + tokens.combine("e! { + #[cfg(feature = #namespace_feature)] + pub mod #name; + }); + } else { + tokens.combine("e! { pub mod #name }); + tokens.push_str("{"); + tokens.push_str(&namespace(writer, tree)); + tokens.push_str("}"); + } + } + + let mut functions = BTreeMap::<&str, TokenStream>::new(); + let mut types = BTreeMap::<TypeKind, BTreeMap<&str, TokenStream>>::new(); + + for item in writer.reader.namespace_items(writer.namespace, writer.filter) { + match item { + Item::Type(def) => { + let type_name = writer.reader.type_def_type_name(def); + if REMAP_TYPES.iter().any(|(x, _)| x == &type_name) { + continue; + } + if CORE_TYPES.iter().any(|(x, _)| x == &type_name) { + continue; + } + let name = type_name.name; + let kind = writer.reader.type_def_kind(def); + match kind { + TypeKind::Class => { + if writer.reader.type_def_flags(def).contains(TypeAttributes::WindowsRuntime) { + types.entry(kind).or_default().insert(name, classes::writer(writer, def)); + } + } + TypeKind::Interface => types.entry(kind).or_default().entry(name).or_default().combine(&interfaces::writer(writer, def)), + TypeKind::Enum => types.entry(kind).or_default().entry(name).or_default().combine(&enums::writer(writer, def)), + TypeKind::Struct => { + if writer.reader.type_def_fields(def).next().is_none() { + if let Some(guid) = type_def_guid(writer.reader, def) { + let ident = to_ident(name); + let value = writer.guid(&guid); + let guid = writer.type_name(&Type::GUID); + let cfg = type_def_cfg(writer.reader, def, &[]); + let doc = writer.cfg_doc(&cfg); + let constant = quote! { + #doc + pub const #ident: #guid = #value; + }; + types.entry(TypeKind::Class).or_default().entry(name).or_default().combine(&constant); + continue; + } + } + types.entry(kind).or_default().entry(name).or_default().combine(&structs::writer(writer, def)); + } + TypeKind::Delegate => types.entry(kind).or_default().entry(name).or_default().combine(&delegates::writer(writer, def)), + } + } + Item::Fn(def, namespace) => { + let name = writer.reader.method_def_name(def); + functions.entry(name).or_default().combine(&functions::writer(writer, &namespace, def)); + } + Item::Const(def) => { + let name = writer.reader.field_name(def); + types.entry(TypeKind::Class).or_default().entry(name).or_default().combine(&constants::writer(writer, def)); + } + } + } + + for function in functions.values() { + tokens.combine(function); + } + + for ty in types.values().flat_map(|v| v.values()) { + tokens.combine(ty); + } + + tokens.combine(&extensions::gen_mod(writer, tree.namespace)); + + if writer.implement { + tokens.push_str(&namespace_impl(writer, tree)); + } + + tokens.into_string() +} + +fn namespace_impl(writer: &Writer, tree: &Tree) -> String { + let writer = &mut writer.clone(); + writer.namespace = tree.namespace; + let mut types = BTreeMap::<&str, TokenStream>::new(); + + for item in writer.reader.namespace_items(writer.namespace, writer.filter) { + if let Item::Type(def) = item { + let type_name = writer.reader.type_def_type_name(def); + if CORE_TYPES.iter().any(|(x, _)| x == &type_name) { + continue; + } + if writer.reader.type_def_kind(def) != TypeKind::Interface { + continue; + } + let tokens = implements::writer(writer, def); + + if !tokens.is_empty() { + types.insert(type_name.name, tokens); + } + } + } + + let types = types.values(); + + let mut tokens = quote! { + #(#types)* + }; + + tokens.combine(&extensions::gen_impl(tree.namespace)); + tokens.into_string() +} + +/// Expand a possibly empty generics list with a new generic +fn expand_generics(generics: TokenStream, new: TokenStream) -> TokenStream { + if generics.is_empty() { + quote!(#new) + } else { + quote!(#generics, #new) + } +} + +/// Expand a possibly emppty where clause with a new generic constraint +fn expand_where_clause(where_clause: TokenStream, generic: TokenStream) -> TokenStream { + if where_clause.is_empty() { + quote!(where #generic) + } else { + quote!(#where_clause #generic) + } +} diff --git a/vendor/windows-bindgen/src/rust/standalone.rs b/vendor/windows-bindgen/src/rust/standalone.rs new file mode 100644 index 000000000..f74c34647 --- /dev/null +++ b/vendor/windows-bindgen/src/rust/standalone.rs @@ -0,0 +1,217 @@ +use super::*; + +pub fn standalone_imp(writer: &Writer) -> String { + let mut types = BTreeSet::new(); + let mut functions = BTreeSet::new(); + let mut constants = BTreeSet::new(); + + for item in writer.reader.items(writer.filter) { + item_collect_standalone(writer.reader, item.clone(), &mut types); + + match item { + Item::Type(_) => {} + Item::Fn(def, namespace) => _ = functions.insert((def, namespace.clone())), + Item::Const(def) => _ = constants.insert(def), + } + } + + let mut sorted = SortedTokens::default(); + + for ty in types { + match ty { + Type::HRESULT if writer.sys => sorted.insert("HRESULT", quote! { pub type HRESULT = i32; }), + Type::String if writer.sys => sorted.insert("HSTRING", quote! { pub type HSTRING = *mut ::core::ffi::c_void; }), + Type::IUnknown if writer.sys => sorted.insert("IUnknown", quote! { pub type IUnknown = *mut ::core::ffi::c_void; }), + Type::IInspectable if writer.sys => sorted.insert("IInspectable", quote! { pub type IInspectable = *mut ::core::ffi::c_void; }), + Type::PSTR if writer.sys => sorted.insert("PSTR", quote! { pub type PSTR = *mut u8; }), + Type::PWSTR if writer.sys => sorted.insert("PWSTR", quote! { pub type PWSTR = *mut u16; }), + Type::PCSTR if writer.sys => sorted.insert("PCSTR", quote! { pub type PCSTR = *const u8; }), + Type::PCWSTR if writer.sys => sorted.insert("PCWSTR", quote! { pub type PCWSTR = *const u16; }), + Type::BSTR if writer.sys => sorted.insert("BSTR", quote! { pub type BSTR = *const u16; }), + Type::GUID if writer.sys => { + sorted.insert( + "GUID", + quote! { + #[repr(C)] + pub struct GUID { + pub data1: u32, + pub data2: u16, + pub data3: u16, + pub data4: [u8; 8], + } + impl ::core::marker::Copy for GUID {} + impl ::core::clone::Clone for GUID { + fn clone(&self) -> Self { + *self + } + } + impl GUID { + pub const fn from_u128(uuid: u128) -> Self { + Self { data1: (uuid >> 96) as u32, data2: (uuid >> 80 & 0xffff) as u16, data3: (uuid >> 64 & 0xffff) as u16, data4: (uuid as u64).to_be_bytes() } + } + } + }, + ); + } + Type::TypeDef(def, _) => { + let kind = writer.reader.type_def_kind(def); + match kind { + TypeKind::Class => { + let name = writer.reader.type_def_name(def); + if writer.sys { + let ident = to_ident(name); + sorted.insert(name, quote! { pub type #ident = *mut ::core::ffi::c_void; }); + } else { + sorted.insert(name, classes::writer(writer, def)); + } + } + TypeKind::Interface => { + let name = writer.reader.type_def_name(def); + if writer.sys { + let ident = to_ident(name); + sorted.insert(name, quote! { pub type #ident = *mut ::core::ffi::c_void; }); + } else { + sorted.insert(name, interfaces::writer(writer, def)); + } + } + TypeKind::Enum => { + sorted.insert(writer.reader.type_def_name(def), enums::writer(writer, def)); + } + TypeKind::Struct => { + let name = writer.reader.type_def_name(def); + if writer.reader.type_def_fields(def).next().is_none() { + if let Some(guid) = type_def_guid(writer.reader, def) { + let ident = to_ident(name); + let value = writer.guid(&guid); + let guid = writer.type_name(&Type::GUID); + sorted.insert( + name, + quote! { + pub const #ident: #guid = #value; + }, + ); + continue; + } + } + sorted.insert(name, structs::writer(writer, def)); + } + TypeKind::Delegate => { + sorted.insert(writer.reader.type_def_name(def), delegates::writer(writer, def)); + } + } + } + _ => {} + } + } + + for (function, namespace) in functions { + sorted.insert(&format!(".{}.{}", writer.reader.method_def_module_name(function), writer.reader.method_def_name(function)), functions::writer(writer, &namespace, function)); + } + + for constant in constants { + sorted.insert(writer.reader.field_name(constant), constants::writer(writer, constant)); + } + + let mut tokens = TokenStream::new(); + sorted.0.values().for_each(|value| tokens.combine(value)); + tokens.into_string() +} + +#[derive(Default)] +struct SortedTokens(BTreeMap<String, TokenStream>); + +impl SortedTokens { + fn insert(&mut self, key: &str, tokens: TokenStream) { + self.0.entry(key.to_string()).or_default().combine(&tokens); + } +} + +fn item_collect_standalone(reader: &Reader, item: Item, set: &mut BTreeSet<Type>) { + match item { + Item::Type(def) => type_collect_standalone(reader, &Type::TypeDef(def, vec![]), set), + Item::Const(def) => type_collect_standalone(reader, &reader.field_type(def, None).to_const_type(), set), + Item::Fn(def, namespace) => { + let signature = method_def_signature(reader, &namespace, def, &[]); + type_collect_standalone(reader, &signature.return_type, set); + signature.params.iter().for_each(|param| type_collect_standalone(reader, ¶m.ty, set)); + } + } +} +// TODO: remove or move to riddle +fn type_collect_standalone(reader: &Reader, ty: &Type, set: &mut BTreeSet<Type>) { + let ty = ty.to_underlying_type(); + if !set.insert(ty.clone()) { + return; + } + + let Type::TypeDef(def, generics) = &ty else { + return; + }; + + let def = *def; + + // Ensure that we collect all the typedefs of the same name. We need to + // do this in the case where the user specifies a top level item that + // references a typedef by name, but that name resolves to more than 1 + // Type based on target architecture (typically) + // + // Note this is a bit overeager as we can collect a typedef that is used + // by one architecture but not by another + let type_name = reader.type_def_type_name(def); + if !type_name.namespace.is_empty() { + for row in reader.get_type_def(type_name) { + if def != row { + type_collect_standalone(reader, &Type::TypeDef(row, Vec::new()), set); + } + } + } + + for generic in generics { + type_collect_standalone(reader, generic, set); + } + for field in reader.type_def_fields(def) { + let ty = reader.field_type(field, Some(def)); + if let Type::TypeDef(def, _) = &ty { + if reader.type_def_namespace(*def).is_empty() { + continue; + } + } + type_collect_standalone(reader, &ty, set); + } + for method in reader.type_def_methods(def) { + // Skip delegate pseudo-constructors. + if reader.method_def_name(method) == ".ctor" { + continue; + } + let signature = method_def_signature(reader, reader.type_def_namespace(def), method, generics); + type_collect_standalone(reader, &signature.return_type, set); + signature.params.iter().for_each(|param| type_collect_standalone(reader, ¶m.ty, set)); + } + for interface in type_interfaces(reader, &ty) { + type_collect_standalone(reader, &interface.ty, set); + } + if reader.type_def_kind(def) == TypeKind::Struct && reader.type_def_fields(def).next().is_none() && type_def_guid(reader, def).is_some() { + set.insert(Type::GUID); + } + + type_collect_standalone_nested(reader, def, set); +} + +fn type_collect_standalone_nested(reader: &Reader, td: TypeDef, set: &mut BTreeSet<Type>) { + for nested in reader.nested_types(td) { + type_collect_standalone_nested(reader, nested, set); + + for field in reader.type_def_fields(nested) { + let ty = reader.field_type(field, Some(nested)); + if let Type::TypeDef(def, _) = &ty { + // Skip the fields that actually refer to the anonymous nested + // type, otherwise it will get added to the typeset and emitted + if reader.type_def_namespace(*def).is_empty() { + continue; + } + + type_collect_standalone(reader, &ty, set); + } + } + } +} diff --git a/vendor/windows-bindgen/src/rust/structs.rs b/vendor/windows-bindgen/src/rust/structs.rs new file mode 100644 index 000000000..249b293dc --- /dev/null +++ b/vendor/windows-bindgen/src/rust/structs.rs @@ -0,0 +1,288 @@ +use super::*; + +pub fn writer(writer: &Writer, def: TypeDef) -> TokenStream { + if writer.reader.has_attribute(def, "ApiContractAttribute") { + return quote! {}; + } + + if type_def_is_handle(writer.reader, def) { + return handles::writer(writer, def); + } + + gen_struct_with_name(writer, def, writer.reader.type_def_name(def), &Cfg::default()) +} + +fn gen_struct_with_name(writer: &Writer, def: TypeDef, struct_name: &str, cfg: &Cfg) -> TokenStream { + let name = to_ident(struct_name); + + if writer.reader.type_def_fields(def).next().is_none() { + let mut tokens = quote! { + #[repr(C)] + pub struct #name(pub u8); + impl ::core::marker::Copy for #name {} + impl ::core::clone::Clone for #name { + fn clone(&self) -> Self { + *self + } + } + }; + if !writer.sys { + tokens.combine("e! { + impl ::windows_core::TypeKind for #name { + type TypeKind = ::windows_core::CopyType; + } + }); + } + return tokens; + } + + let flags = writer.reader.type_def_flags(def); + let cfg = cfg.union(&type_def_cfg(writer.reader, def, &[])); + + let repr = if let Some(layout) = writer.reader.type_def_class_layout(def) { + let packing = Literal::usize_unsuffixed(writer.reader.class_layout_packing_size(layout)); + quote! { #[repr(C, packed(#packing))] } + } else { + quote! { #[repr(C)] } + }; + + let fields = writer.reader.type_def_fields(def).map(|f| { + let name = to_ident(writer.reader.field_name(f)); + let ty = writer.reader.field_type(f, Some(def)); + + if writer.reader.field_flags(f).contains(FieldAttributes::Literal) { + quote! {} + } else if !writer.sys && flags.contains(TypeAttributes::ExplicitLayout) && !field_is_copyable(writer.reader, f, def) { + let ty = writer.type_default_name(&ty); + quote! { pub #name: ::std::mem::ManuallyDrop<#ty>, } + } else if !writer.sys && !flags.contains(TypeAttributes::WindowsRuntime) && !field_is_blittable(writer.reader, f, def) { + if let Type::Win32Array(ty, len) = ty { + let ty = writer.type_default_name(&ty); + quote! { pub #name: [::std::mem::ManuallyDrop<#ty>; #len], } + } else { + let ty = writer.type_default_name(&ty); + quote! { pub #name: ::std::mem::ManuallyDrop<#ty>, } + } + } else { + let ty = writer.type_default_name(&ty); + quote! { pub #name: #ty, } + } + }); + + let struct_or_union = if flags.contains(TypeAttributes::ExplicitLayout) { + quote! { union } + } else { + quote! { struct } + }; + + let doc = writer.cfg_doc(&cfg); + let features = writer.cfg_features(&cfg); + + let mut tokens = quote! { + #repr + #doc + #features + pub #struct_or_union #name {#(#fields)*} + }; + + tokens.combine(&gen_struct_constants(writer, def, &name, &cfg)); + tokens.combine(&gen_copy_clone(writer, def, &name, &cfg)); + tokens.combine(&gen_debug(writer, def, &name, &cfg)); + tokens.combine(&gen_windows_traits(writer, def, &name, &cfg)); + tokens.combine(&gen_compare_traits(writer, def, &name, &cfg)); + + if !writer.sys { + tokens.combine("e! { + #features + impl ::core::default::Default for #name { + fn default() -> Self { + unsafe { ::core::mem::zeroed() } + } + } + }); + } + + for (index, nested_type) in writer.reader.nested_types(def).enumerate() { + let nested_name = format!("{struct_name}_{index}"); + tokens.combine(&gen_struct_with_name(writer, nested_type, &nested_name, &cfg)); + } + + tokens +} + +fn gen_windows_traits(writer: &Writer, def: TypeDef, name: &TokenStream, cfg: &Cfg) -> TokenStream { + if writer.sys { + quote! {} + } else { + let features = writer.cfg_features(cfg); + let is_copy = type_def_is_blittable(writer.reader, def); + + let type_kind = if is_copy { + quote! { CopyType } + } else { + quote! { ValueType } + }; + + let mut tokens = quote! { + #features + impl ::windows_core::TypeKind for #name { + type TypeKind = ::windows_core::#type_kind; + } + }; + + if writer.reader.type_def_flags(def).contains(TypeAttributes::WindowsRuntime) { + let signature = Literal::byte_string(type_def_signature(writer.reader, def, &[]).as_bytes()); + + tokens.combine("e! { + #features + impl ::windows_core::RuntimeType for #name { + const SIGNATURE: ::windows_core::imp::ConstBuffer = ::windows_core::imp::ConstBuffer::from_slice(#signature); + } + }); + } + + tokens + } +} + +fn gen_compare_traits(writer: &Writer, def: TypeDef, name: &TokenStream, cfg: &Cfg) -> TokenStream { + let features = writer.cfg_features(cfg); + + if writer.sys || type_def_has_explicit_layout(writer.reader, def) || type_def_has_packing(writer.reader, def) || type_def_has_callback(writer.reader, def) { + quote! {} + } else { + let fields = writer.reader.type_def_fields(def).filter_map(|f| { + let name = to_ident(writer.reader.field_name(f)); + if writer.reader.field_flags(f).contains(FieldAttributes::Literal) { + None + } else { + Some(quote! { self.#name == other.#name }) + } + }); + + quote! { + #features + impl ::core::cmp::PartialEq for #name { + fn eq(&self, other: &Self) -> bool { + #(#fields)&&* + } + } + #features + impl ::core::cmp::Eq for #name {} + } + } +} + +fn gen_debug(writer: &Writer, def: TypeDef, ident: &TokenStream, cfg: &Cfg) -> TokenStream { + if writer.sys || type_def_has_explicit_layout(writer.reader, def) || type_def_has_packing(writer.reader, def) { + quote! {} + } else { + let name = ident.as_str(); + let features = writer.cfg_features(cfg); + + let fields = writer.reader.type_def_fields(def).filter_map(|f| { + if writer.reader.field_flags(f).contains(FieldAttributes::Literal) { + None + } else { + let name = writer.reader.field_name(f); + let ident = to_ident(name); + let ty = writer.reader.field_type(f, Some(def)); + if type_has_callback(writer.reader, &ty) { + None + } else { + Some(quote! { .field(#name, &self.#ident) }) + } + } + }); + + quote! { + #features + impl ::core::fmt::Debug for #ident { + fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { + f.debug_struct(#name) #(#fields)* .finish() + } + } + } + } +} + +fn gen_copy_clone(writer: &Writer, def: TypeDef, name: &TokenStream, cfg: &Cfg) -> TokenStream { + let features = writer.cfg_features(cfg); + + if writer.sys || type_def_is_copyable(writer.reader, def) { + quote! { + #features + impl ::core::marker::Copy for #name {} + #features + impl ::core::clone::Clone for #name { + fn clone(&self) -> Self { + *self + } + } + } + } else if writer.reader.type_def_class_layout(def).is_some() { + // Don't support copy/clone of packed structs: https://github.com/rust-lang/rust/issues/82523 + quote! {} + } else if !writer.reader.type_def_flags(def).contains(TypeAttributes::WindowsRuntime) { + quote! { + #features + impl ::core::clone::Clone for #name { + fn clone(&self) -> Self { + unsafe { ::core::mem::transmute_copy(self) } + } + } + } + } else { + let fields = writer.reader.type_def_fields(def).map(|f| { + let name = to_ident(writer.reader.field_name(f)); + if writer.reader.field_flags(f).contains(FieldAttributes::Literal) { + quote! {} + } else if field_is_blittable(writer.reader, f, def) { + quote! { #name: self.#name } + } else { + quote! { #name: self.#name.clone() } + } + }); + + quote! { + #features + impl ::core::clone::Clone for #name { + fn clone(&self) -> Self { + Self { #(#fields),* } + } + } + } + } +} + +fn gen_struct_constants(writer: &Writer, def: TypeDef, struct_name: &TokenStream, cfg: &Cfg) -> TokenStream { + let features = writer.cfg_features(cfg); + + let constants = writer.reader.type_def_fields(def).filter_map(|f| { + if writer.reader.field_flags(f).contains(FieldAttributes::Literal) { + if let Some(constant) = writer.reader.field_constant(f) { + let name = to_ident(writer.reader.field_name(f)); + let value = writer.typed_value(&writer.reader.constant_value(constant)); + + return Some(quote! { + pub const #name: #value; + }); + } + } + + None + }); + + let mut tokens = quote! { #(#constants)* }; + + if !tokens.is_empty() { + tokens = quote! { + #features + impl #struct_name { + #tokens + } + }; + } + + tokens +} diff --git a/vendor/windows-bindgen/src/rust/try_format.rs b/vendor/windows-bindgen/src/rust/try_format.rs new file mode 100644 index 000000000..c871517b1 --- /dev/null +++ b/vendor/windows-bindgen/src/rust/try_format.rs @@ -0,0 +1,49 @@ +use std::io::Write; + +pub fn try_format(writer: &super::Writer, tokens: &str) -> String { + let preamble = if writer.package { + String::new() + } else { + let name = std::env!("CARGO_PKG_NAME"); + let version = std::env!("CARGO_PKG_VERSION"); + + format!( + r#"// Bindings generated by `{name}` {version} + + +"# + ) + }; + + // Packaging - e.g. windows/windows-sys crates - assumes the crate will allow whatever warnings it deems fit. + let allow = if writer.package { "" } else { "#![allow(non_snake_case, non_upper_case_globals, non_camel_case_types, dead_code, clippy::all)]\n" }; + let tokens = format!("{preamble}{allow}{tokens}"); + + let Ok(mut child) = std::process::Command::new("rustfmt").stdin(std::process::Stdio::piped()).stdout(std::process::Stdio::piped()).stderr(std::process::Stdio::null()).spawn() else { + return tokens; + }; + + let Some(mut stdin) = child.stdin.take() else { + return tokens; + }; + + if stdin.write_all(tokens.as_bytes()).is_err() { + return tokens; + } + + drop(stdin); + + let Ok(output) = child.wait_with_output() else { + return tokens; + }; + + if !output.status.success() { + return tokens; + } + + if let Ok(result) = String::from_utf8(output.stdout) { + result + } else { + tokens + } +} diff --git a/vendor/windows-bindgen/src/rust/winrt_methods.rs b/vendor/windows-bindgen/src/rust/winrt_methods.rs new file mode 100644 index 000000000..f98843e66 --- /dev/null +++ b/vendor/windows-bindgen/src/rust/winrt_methods.rs @@ -0,0 +1,242 @@ +use super::*; + +// TODO take Signature instead of MethodDef (wherever MethodDef is found) +pub fn writer(writer: &Writer, def: TypeDef, generic_types: &[Type], kind: InterfaceKind, method: MethodDef, method_names: &mut MethodNames, virtual_names: &mut MethodNames) -> TokenStream { + let signature = method_def_signature(writer.reader, writer.reader.type_def_namespace(def), method, generic_types); + let params = &signature.params; + let name = method_names.add(writer, method); + let interface_name = writer.type_def_name(def, generic_types); + let vname = virtual_names.add(writer, method); + let generics = writer.constraint_generics(params); + let where_clause = writer.where_clause(params); + let mut cfg = signature_cfg(writer.reader, method); + type_def_cfg_combine(writer.reader, def, generic_types, &mut cfg); + let doc = writer.cfg_method_doc(&cfg); + let features = writer.cfg_features(&cfg); + let args = gen_winrt_abi_args(writer, params); + let params = gen_winrt_params(writer, params); + + let return_type_tokens = match &signature.return_type { + Type::Void => quote! { () }, + _ => { + let tokens = writer.type_name(&signature.return_type); + if signature.return_type.is_winrt_array() { + quote! { ::windows_core::Array<#tokens> } + } else { + quote! { #tokens } + } + } + }; + + let return_arg = match &signature.return_type { + Type::Void => quote! {}, + _ => { + if signature.return_type.is_winrt_array() { + let return_type = writer.type_name(&signature.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__ } + } + } + }; + + let vcall = match &signature.return_type { + Type::Void => { + quote! { + (::windows_core::Interface::vtable(this).#vname)(::windows_core::Interface::as_raw(this), #args).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) + .and_then(|| result__.assume_init()) + } + } + _ => { + quote! { + let mut result__ = ::std::mem::zeroed(); + (::windows_core::Interface::vtable(this).#vname)(::windows_core::Interface::as_raw(this), #args #return_arg) + .from_abi(result__) + } + } + }; + + 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(writer: &Writer, params: &[SignatureParam]) -> TokenStream { + let mut result = quote! {}; + + let mut generic_params = writer.generic_params(params); + for param in params.iter() { + let name = writer.param_name(param.def); + let kind = writer.type_name(¶m.ty); + let default_type = writer.type_default_name(¶m.ty); + + if writer.reader.param_flags(param.def).contains(ParamAttributes::In) { + if param.ty.is_winrt_array() { + result.combine("e! { #name: &[#default_type], }); + } else if signature_param_is_convertible(writer.reader, param) { + let (position, _) = generic_params.next().unwrap(); + let kind: TokenStream = format!("P{position}").into(); + result.combine("e! { #name: #kind, }); + } else if type_is_blittable(writer.reader, ¶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(writer: &Writer, params: &[SignatureParam]) -> TokenStream { + let mut tokens = TokenStream::new(); + for param in params { + let name = writer.param_name(param.def); + + let param = if writer.reader.param_flags(param.def).contains(ParamAttributes::In) { + if param.ty.is_winrt_array() { + if type_is_blittable(writer.reader, ¶m.ty) { + quote! { #name.len() as u32, #name.as_ptr(), } + } else { + quote! { #name.len() as u32, ::core::mem::transmute(#name.as_ptr()), } + } + } else if type_is_non_exclusive_winrt_interface(writer.reader, ¶m.ty) { + quote! { #name.try_into_param()?.abi(), } + } else if signature_param_is_borrowed(writer.reader, param) { + quote! { #name.into_param().abi(), } + } else if type_is_blittable(writer.reader, ¶m.ty) { + if param.ty.is_const_ref() { + quote! { &#name, } + } else { + quote! { #name, } + } + } else { + quote! { ::core::mem::transmute_copy(#name), } + } + } else if param.ty.is_winrt_array() { + if type_is_blittable(writer.reader, ¶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 type_is_blittable(writer.reader, ¶m.ty) { + quote! { #name, } + } else { + quote! { #name as *mut _ as _, } + }; + tokens.combine(¶m); + } + tokens +} + +pub fn gen_upcall(writer: &Writer, sig: &Signature, inner: TokenStream) -> TokenStream { + let invoke_args = sig.params.iter().map(|param| gen_winrt_invoke_arg(writer, param)); + + match &sig.return_type { + Type::Void => quote! { + #inner(#(#invoke_args,)*).into() + }, + _ if sig.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() + } + } + } + _ => { + let forget = if type_is_blittable(writer.reader, &sig.return_type) { + quote! {} + } else { + quote! { ::core::mem::forget(ok__); } + }; + + 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__)); + #forget + ::windows_core::HRESULT(0) + } + ::core::result::Result::Err(err) => err.into() + } + } + } + } +} + +fn gen_winrt_invoke_arg(writer: &Writer, param: &SignatureParam) -> TokenStream { + let name = writer.param_name(param.def); + let abi_size_name: TokenStream = format!("{}_array_size", writer.reader.param_name(param.def)).into(); + + if writer.reader.param_flags(param.def).contains(ParamAttributes::In) { + if param.ty.is_winrt_array() { + quote! { ::core::slice::from_raw_parts(::core::mem::transmute_copy(&#name), #abi_size_name as usize) } + } else if type_is_primitive(writer.reader, ¶m.ty) { + quote! { #name } + } else if param.ty.is_const_ref() { + quote! { ::core::mem::transmute_copy(&#name) } + } else if type_is_nullable(writer.reader, ¶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 usize) } + } 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) } + } +} diff --git a/vendor/windows-bindgen/src/gen.rs b/vendor/windows-bindgen/src/rust/writer.rs index 30d4150e6..9d81c9951 100644 --- a/vendor/windows-bindgen/src/gen.rs +++ b/vendor/windows-bindgen/src/rust/writer.rs @@ -1,28 +1,28 @@ use super::*; -pub struct Gen<'a> { +#[derive(Clone)] +pub struct Writer<'a> { pub reader: &'a Reader<'a>, + pub filter: &'a metadata::Filter<'a>, + pub output: &'a str, pub namespace: &'a str, - pub sys: bool, - pub cfg: bool, - pub doc: bool, - pub component: bool, - pub standalone: bool, - pub std: bool, + pub implement: bool, // TODO: ideally we can use this to generate implementation traits on the fly and + // and have a single interface definition macro for consumption that expands to include + // impl traits when the `implement` cfg flag is set and then this writer option would be + // unecessary. + // + // Maybe this macro is the embedable version of the IDL format?! like a more intelligient + // version of the existing interface macro... + pub std: bool, // tweaks for internal std library support + pub sys: bool, // writer sys-style bindings + pub flatten: bool, // strips out namespaces - implies !package + pub package: bool, // default is single file with no cfg - implies !flatten + pub minimal: bool, // strips out enumerators - in future possibly other helpers as well } -impl<'a> Gen<'a> { - pub fn new(reader: &'a Reader) -> Self { - Self { - reader, - namespace: "", - sys: false, - cfg: false, - doc: false, - component: false, - standalone: false, - std: false, - } +impl<'a> Writer<'a> { + pub fn new(reader: &'a Reader, filter: &'a metadata::Filter, output: &'a str) -> Self { + Self { reader, filter, output, namespace: "", implement: false, std: false, sys: false, flatten: false, package: false, minimal: false } } // @@ -72,8 +72,8 @@ impl<'a> Gen<'a> { let kind = self.type_name(ty); if ty.is_generic() { - quote! { <#kind as ::windows::core::Type<#kind>>::Default } - } else if self.reader.type_is_nullable(ty) && !self.sys { + quote! { <#kind as ::windows_core::Type<#kind>>::Default } + } else if type_is_nullable(self.reader, ty) && !self.sys { quote! { ::core::option::Option<#kind> } } else { kind @@ -138,38 +138,42 @@ impl<'a> Gen<'a> { let crate_name = self.crate_name(); quote! { #crate_name PCWSTR } } - Type::Win32Array((ty, len)) => { + Type::Win32Array(ty, len) => { let name = self.type_default_name(ty); let len = Literal::usize_unsuffixed(*len); quote! { [#name; #len] } } Type::GenericParam(generic) => self.reader.generic_param_name(*generic).into(), - Type::TypeDef((def, generics)) => self.type_def_name(*def, generics), - Type::MutPtr((ty, pointers)) => { + Type::TypeDef(def, generics) => self.type_def_name(*def, generics), + Type::MutPtr(ty, pointers) => { let pointers = mut_ptrs(*pointers); let ty = self.type_default_name(ty); quote! { #pointers #ty } } - Type::ConstPtr((ty, pointers)) => { + Type::ConstPtr(ty, pointers) => { let pointers = const_ptrs(*pointers); let ty = self.type_default_name(ty); quote! { #pointers #ty } } Type::WinrtArray(ty) => self.type_name(ty), Type::WinrtArrayRef(ty) => self.type_name(ty), - Type::WinrtConstRef(ty) => self.type_name(ty), - _ => unimplemented!(), + Type::ConstRef(ty) => self.type_name(ty), + Type::PrimitiveOrEnum(_, ty) => self.type_name(ty), + rest => unimplemented!("{rest:?}"), } } pub fn type_vtbl_name(&self, ty: &Type) -> TokenStream { match ty { - Type::TypeDef((def, generics)) => self.type_def_vtbl_name(*def, generics), - _ => unimplemented!(), + Type::TypeDef(def, generics) => self.type_def_vtbl_name(*def, generics), + rest => unimplemented!("{rest:?}"), } } pub fn type_abi_name(&self, ty: &Type) -> TokenStream { if self.sys { - return self.type_default_name(ty); + return match ty { + Type::PrimitiveOrEnum(ty, _) => self.type_default_name(ty), + _ => self.type_default_name(ty), + }; } match ty { @@ -177,36 +181,32 @@ impl<'a> Gen<'a> { quote! { *mut ::core::ffi::c_void } } Type::String => { - quote! { ::std::mem::MaybeUninit<::windows::core::HSTRING> } + quote! { ::std::mem::MaybeUninit<::windows_core::HSTRING> } } Type::BSTR => { - quote! { ::std::mem::MaybeUninit<::windows::core::BSTR> } + quote! { ::std::mem::MaybeUninit<::windows_core::BSTR> } } - Type::Win32Array((kind, len)) => { + Type::Win32Array(kind, len) => { let name = self.type_abi_name(kind); let len = Literal::usize_unsuffixed(*len); quote! { [#name; #len] } } Type::GenericParam(generic) => { let name = to_ident(self.reader.generic_param_name(*generic)); - quote! { ::windows::core::AbiType<#name> } + quote! { ::windows_core::AbiType<#name> } } - Type::TypeDef((def, _)) => match self.reader.type_def_kind(*def) { + Type::TypeDef(def, _) => match self.reader.type_def_kind(*def) { TypeKind::Enum => self.type_def_name(*def, &[]), TypeKind::Struct => { let tokens = self.type_def_name(*def, &[]); - if self.reader.type_def_is_blittable(*def) { + if type_def_is_blittable(self.reader, *def) { tokens } else { quote! { ::std::mem::MaybeUninit<#tokens> } } } TypeKind::Delegate => { - if self - .reader - .type_def_flags(*def) - .contains(TypeAttributes::WINRT) - { + if self.reader.type_def_flags(*def).contains(TypeAttributes::WindowsRuntime) { quote! { *mut ::core::ffi::c_void } } else { self.type_def_name(*def, &[]) @@ -214,26 +214,19 @@ impl<'a> Gen<'a> { } _ => quote! { *mut ::core::ffi::c_void }, }, - Type::MutPtr((kind, pointers)) => { + Type::MutPtr(kind, pointers) => { let pointers_tokens = gen_mut_ptrs(*pointers); - let kind = if *pointers > 1 { - self.type_name(kind) - } else { - self.type_abi_name(kind) - }; + let kind = if *pointers > 1 { self.type_name(kind) } else { self.type_abi_name(kind) }; quote! { #pointers_tokens #kind } } - Type::ConstPtr((kind, pointers)) => { + Type::ConstPtr(kind, pointers) => { let pointers_tokens = gen_const_ptrs(*pointers); - let kind = if *pointers > 1 { - self.type_name(kind) - } else { - self.type_abi_name(kind) - }; + let kind = if *pointers > 1 { self.type_name(kind) } else { self.type_abi_name(kind) }; quote! { #pointers_tokens #kind } } Type::WinrtArray(kind) => self.type_abi_name(kind), Type::WinrtArrayRef(kind) => self.type_abi_name(kind), + Type::PrimitiveOrEnum(ty, _) => self.type_name(ty), _ => self.type_name(ty), } } @@ -263,7 +256,7 @@ impl<'a> Gen<'a> { let mut tokens = TokenStream::new(); for generic in generics { let generic = self.type_name(generic); - tokens.combine("e! { #generic: ::windows::core::RuntimeType + 'static, }); + tokens.combine("e! { #generic: ::windows_core::RuntimeType + 'static, }); } tokens } @@ -276,21 +269,12 @@ impl<'a> Gen<'a> { tokens } /// The signature params which are generic (along with their relative index) - pub fn generic_params<'b>( - &'b self, - params: &'b [SignatureParam], - ) -> impl Iterator<Item = (usize, &SignatureParam)> + 'b { - params - .iter() - .filter(move |param| self.reader.signature_param_is_convertible(param)) - .enumerate() + pub fn generic_params<'b>(&'b self, params: &'b [SignatureParam]) -> impl Iterator<Item = (usize, &SignatureParam)> + 'b { + params.iter().filter(move |param| signature_param_is_convertible(self.reader, param)).enumerate() } /// The generic param names (i.e., `T` in `fn foo<T>()`) pub fn constraint_generics(&self, params: &[SignatureParam]) -> TokenStream { - let mut generics = self - .generic_params(params) - .map(|(position, _)| -> TokenStream { format!("P{position}").into() }) - .peekable(); + let mut generics = self.generic_params(params).map(|(position, _)| -> TokenStream { format!("P{position}").into() }).peekable(); if generics.peek().is_some() { quote!(#(#generics),*) @@ -319,12 +303,12 @@ impl<'a> Gen<'a> { SignatureParamKind::TryInto => { let name: TokenStream = gen_name(position); let into = self.type_name(¶m.ty); - tokens.combine("e! { #name: ::windows::core::TryIntoParam<#into>, }); + tokens.combine("e! { #name: ::windows_core::TryIntoParam<#into>, }); } SignatureParamKind::IntoParam => { let name: TokenStream = gen_name(position); let into = self.type_name(¶m.ty); - tokens.combine("e! { #name: ::windows::core::IntoParam<#into>, }); + tokens.combine("e! { #name: ::windows_core::IntoParam<#into>, }); } _ => {} } @@ -338,7 +322,7 @@ impl<'a> Gen<'a> { /// Generates doc comments for types, free functions, and constants. pub(crate) fn cfg_doc(&self, cfg: &Cfg) -> TokenStream { - if !self.doc { + if !self.package { quote! {} } else { let mut tokens = format!(r#"`\"{}\"`"#, to_feature(self.namespace)); @@ -359,7 +343,7 @@ impl<'a> Gen<'a> { /// Generates doc comments for member functions (methods) and avoids redundantly declaring the /// enclosing module feature required by the method's type. pub(crate) fn cfg_method_doc(&self, cfg: &Cfg) -> TokenStream { - if !self.doc { + if !self.package { quote! {} } else { let features = self.cfg_features_imp(cfg, self.namespace); @@ -407,7 +391,7 @@ impl<'a> Gen<'a> { fn cfg_features_imp(&self, cfg: &'a Cfg, namespace: &'a str) -> Vec<&'a str> { let mut compact = Vec::<&'static str>::new(); - if !self.standalone && !self.component { + if self.package { for feature in cfg.types.keys() { if !feature.is_empty() && !starts_with(namespace, feature) { for pos in 0..compact.len() { @@ -447,11 +431,10 @@ impl<'a> Gen<'a> { // pub(crate) fn namespace(&self, namespace: &str) -> TokenStream { - if self.standalone || namespace == self.namespace { + if self.flatten || namespace == self.namespace { quote! {} } else { - let is_external = - namespace.starts_with("Windows.") && !self.namespace.starts_with("Windows"); + let is_external = namespace.starts_with("Windows.") && !self.namespace.starts_with("Windows"); let mut relative = self.namespace.split('.').peekable(); let mut namespace = namespace.split('.').peekable(); @@ -483,12 +466,14 @@ impl<'a> Gen<'a> { } } pub fn crate_name(&self) -> TokenStream { - if self.standalone { - TokenStream::new() - } else if self.sys { - "::windows_sys::core::".into() + if self.sys { + if self.flatten { + TokenStream::new() + } else { + "::windows_sys::core::".into() + } } else { - "::windows::core::".into() + "::windows_core::".into() } } fn scoped_name(&self, def: TypeDef) -> String { @@ -524,7 +509,7 @@ impl<'a> Gen<'a> { tokens.push('\"'); tokens.into() } - _ => unimplemented!(), + rest => unimplemented!("{rest:?}"), } } pub fn typed_value(&self, value: &Value) -> TokenStream { @@ -544,7 +529,7 @@ impl<'a> Gen<'a> { Value::String(_) => { quote! { &str = #literal } } - _ => unimplemented!(), + rest => unimplemented!("{rest:?}"), } } @@ -552,16 +537,8 @@ impl<'a> Gen<'a> { let guid = self.type_name(&Type::GUID); format!("{}::from_u128(0x{:08x?}_{:04x?}_{:04x?}_{:02x?}{:02x?}_{:02x?}{:02x?}{:02x?}{:02x?}{:02x?}{:02x?})", guid.into_string(), value.0, value.1, value.2, value.3, value.4, value.5, value.6, value.7, value.8, value.9, value.10).into() } - pub fn interface_core_traits( - &self, - def: TypeDef, - _generics: &[Type], - ident: &TokenStream, - constraints: &TokenStream, - _phantoms: &TokenStream, - features: &TokenStream, - ) -> TokenStream { - let name = trim_tick(self.reader.type_def_name(def)); + pub fn interface_core_traits(&self, def: TypeDef, _generics: &[Type], ident: &TokenStream, constraints: &TokenStream, _phantoms: &TokenStream, features: &TokenStream) -> TokenStream { + let name = crate::trim_tick(self.reader.type_def_name(def)); quote! { #features impl<#constraints> ::core::cmp::PartialEq for #ident { @@ -579,14 +556,8 @@ impl<'a> Gen<'a> { } } } - pub fn agile( - &self, - def: TypeDef, - ident: &TokenStream, - constraints: &TokenStream, - features: &TokenStream, - ) -> TokenStream { - if self.reader.type_def_is_agile(def) { + pub fn agile(&self, def: TypeDef, ident: &TokenStream, constraints: &TokenStream, features: &TokenStream) -> TokenStream { + if type_def_is_agile(self.reader, def) { quote! { #features unsafe impl<#constraints> ::core::marker::Send for #ident {} @@ -597,22 +568,14 @@ impl<'a> Gen<'a> { quote! {} } } - pub fn async_get( - &self, - def: TypeDef, - generics: &[Type], - ident: &TokenStream, - constraints: &TokenStream, - _phantoms: &TokenStream, - features: &TokenStream, - ) -> TokenStream { - let mut kind = self.reader.type_def_async_kind(def); + pub fn async_get(&self, def: TypeDef, generics: &[Type], ident: &TokenStream, constraints: &TokenStream, _phantoms: &TokenStream, features: &TokenStream) -> TokenStream { + let mut kind = type_def_async_kind(self.reader, def); let mut async_generics = generics.to_vec(); if kind == AsyncKind::None { - for interface in self.reader.type_def_interfaces(def, generics) { - if let Type::TypeDef((interface_def, interface_generics)) = &interface.ty { - kind = self.reader.type_def_async_kind(*interface_def); + for interface in type_def_interfaces(self.reader, def, generics) { + if let Type::TypeDef(interface_def, interface_generics) = &interface { + kind = type_def_async_kind(self.reader, *interface_def); if kind != AsyncKind::None { async_generics = interface_generics.to_vec(); break; @@ -625,9 +588,7 @@ impl<'a> Gen<'a> { quote! {} } else { let return_type = match kind { - AsyncKind::Operation | AsyncKind::OperationWithProgress => { - self.type_name(&async_generics[0]) - } + AsyncKind::Operation | AsyncKind::OperationWithProgress => self.type_name(&async_generics[0]), _ => quote! { () }, }; @@ -638,7 +599,7 @@ impl<'a> Gen<'a> { AsyncKind::OperationWithProgress => { quote! { AsyncOperationWithProgressCompletedHandler } } - _ => unimplemented!(), + rest => unimplemented!("{rest:?}"), }; let namespace = self.namespace("Windows.Foundation"); @@ -646,9 +607,9 @@ impl<'a> Gen<'a> { quote! { #features impl<#constraints> #ident { - pub fn get(&self) -> ::windows::core::Result<#return_type> { + pub fn get(&self) -> ::windows_core::Result<#return_type> { if self.Status()? == #namespace AsyncStatus::Started { - let (_waiter, signaler) = ::windows::imp::Waiter::new()?; + let (_waiter, signaler) = ::windows_core::imp::Waiter::new()?; self.SetCompleted(&#namespace #handler::new(move |_sender, _args| { // Safe because the waiter will only be dropped after being signaled. unsafe { signaler.signal(); } @@ -660,7 +621,7 @@ impl<'a> Gen<'a> { } #features impl<#constraints> ::std::future::Future for #ident { - type Output = ::windows::core::Result<#return_type>; + type Output = ::windows_core::Result<#return_type>; fn poll(self: ::std::pin::Pin<&mut Self>, context: &mut ::std::task::Context) -> ::std::task::Poll<Self::Output> { if self.Status()? == #namespace AsyncStatus::Started { @@ -680,31 +641,19 @@ impl<'a> Gen<'a> { } } } - pub fn interface_winrt_trait( - &self, - def: TypeDef, - generics: &[Type], - ident: &TokenStream, - constraints: &TokenStream, - _phantoms: &TokenStream, - features: &TokenStream, - ) -> TokenStream { - if self - .reader - .type_def_flags(def) - .contains(TypeAttributes::WINRT) - { + pub fn interface_winrt_trait(&self, def: TypeDef, generics: &[Type], ident: &TokenStream, constraints: &TokenStream, _phantoms: &TokenStream, features: &TokenStream) -> TokenStream { + if self.reader.type_def_flags(def).contains(TypeAttributes::WindowsRuntime) { let type_signature = if self.reader.type_def_kind(def) == TypeKind::Class { - let type_signature = - Literal::byte_string(self.reader.type_def_signature(def, generics).as_bytes()); - quote! { ::windows::imp::ConstBuffer::from_slice(#type_signature) } + let type_signature = Literal::byte_string(type_def_signature(self.reader, def, generics).as_bytes()); + quote! { ::windows_core::imp::ConstBuffer::from_slice(#type_signature) } } else { let signature = Literal::byte_string( - format!("{{{:#?}}}", self.reader.type_def_guid(def).unwrap()).as_bytes(), + // TODO: workaround for riddle winmd generation (no attribute support) + if let Some(guid) = type_def_guid(self.reader, def) { format!("{{{:#?}}}", guid) } else { "TODO".to_string() }.as_bytes(), ); if generics.is_empty() { - quote! { ::windows::imp::ConstBuffer::from_slice(#signature) } + quote! { ::windows_core::imp::ConstBuffer::from_slice(#signature) } } else { let generics = generics.iter().enumerate().map(|(index, g)| { let g = self.type_name(g); @@ -717,14 +666,14 @@ impl<'a> Gen<'a> { }; quote! { - .push_other(<#g as ::windows::core::RuntimeType>::SIGNATURE) + .push_other(<#g as ::windows_core::RuntimeType>::SIGNATURE) #semi } }); quote! { { - ::windows::imp::ConstBuffer::new() + ::windows_core::imp::ConstBuffer::new() .push_slice(b"pinterface(") .push_slice(#signature) .push_slice(b";") @@ -737,54 +686,35 @@ impl<'a> Gen<'a> { quote! { #features - impl<#constraints> ::windows::core::RuntimeType for #ident { - const SIGNATURE: ::windows::imp::ConstBuffer = #type_signature; + impl<#constraints> ::windows_core::RuntimeType for #ident { + const SIGNATURE: ::windows_core::imp::ConstBuffer = #type_signature; } } } else { quote! {} } } - pub fn runtime_name_trait( - &self, - def: TypeDef, - _generics: &[Type], - name: &TokenStream, - constraints: &TokenStream, - features: &TokenStream, - ) -> TokenStream { - if self - .reader - .type_def_flags(def) - .contains(TypeAttributes::WINRT) - { + pub fn runtime_name_trait(&self, def: TypeDef, _generics: &[Type], name: &TokenStream, constraints: &TokenStream, features: &TokenStream) -> TokenStream { + if self.reader.type_def_flags(def).contains(TypeAttributes::WindowsRuntime) { // TODO: this needs to use a ConstBuffer-like facility to accomodate generics let runtime_name = format!("{}", self.reader.type_def_type_name(def)); quote! { #features - impl<#constraints> ::windows::core::RuntimeName for #name { + impl<#constraints> ::windows_core::RuntimeName for #name { const NAME: &'static str = #runtime_name; } } } else { quote! { #features - impl ::windows::core::RuntimeName for #name {} + impl ::windows_core::RuntimeName for #name {} } } } - pub fn interface_trait( - &self, - def: TypeDef, - generics: &[Type], - ident: &TokenStream, - constraints: &TokenStream, - features: &TokenStream, - has_unknown_base: bool, - ) -> TokenStream { - if let Some(default) = self.reader.type_def_default_interface(def) { + pub fn interface_trait(&self, def: TypeDef, generics: &[Type], ident: &TokenStream, constraints: &TokenStream, features: &TokenStream, has_unknown_base: bool) -> TokenStream { + if let Some(default) = type_def_default_interface(self.reader, def) { let default_name = self.type_name(&default); let vtbl = self.type_vtbl_name(&default); quote! { @@ -795,28 +725,28 @@ impl<'a> Gen<'a> { } } #features - unsafe impl ::windows::core::Interface for #ident { + unsafe impl ::windows_core::Interface for #ident { type Vtable = #vtbl; } #features - unsafe impl ::windows::core::ComInterface for #ident { - const IID: ::windows::core::GUID = <#default_name as ::windows::core::ComInterface>::IID; + unsafe impl ::windows_core::ComInterface for #ident { + const IID: ::windows_core::GUID = <#default_name as ::windows_core::ComInterface>::IID; } } } else { let vtbl = self.type_def_vtbl_name(def, generics); let guid = if generics.is_empty() { - match self.reader.type_def_guid(def) { + match type_def_guid(self.reader, def) { Some(guid) => self.guid(&guid), None => { quote! { - ::windows::core::GUID::zeroed() + ::windows_core::GUID::zeroed() } } } } else { quote! { - ::windows::core::GUID::from_signature(<Self as ::windows::core::RuntimeType>::SIGNATURE) + ::windows_core::GUID::from_signature(<Self as ::windows_core::RuntimeType>::SIGNATURE) } }; @@ -824,7 +754,7 @@ impl<'a> Gen<'a> { let mut tokens = quote! { #features - unsafe impl<#constraints> ::windows::core::Interface for #ident { + unsafe impl<#constraints> ::windows_core::Interface for #ident { type Vtable = #vtbl; } #features @@ -838,8 +768,8 @@ impl<'a> Gen<'a> { if has_unknown_base { tokens.combine("e! { #features - unsafe impl<#constraints> ::windows::core::ComInterface for #ident { - const IID: ::windows::core::GUID = #guid; + unsafe impl<#constraints> ::windows_core::ComInterface for #ident { + const IID: ::windows_core::GUID = #guid; } }); } @@ -847,28 +777,17 @@ impl<'a> Gen<'a> { tokens } } - pub fn interface_vtbl( - &self, - def: TypeDef, - generics: &[Type], - _ident: &TokenStream, - constraints: &TokenStream, - features: &TokenStream, - ) -> TokenStream { + pub fn interface_vtbl(&self, def: TypeDef, generics: &[Type], _ident: &TokenStream, constraints: &TokenStream, features: &TokenStream) -> TokenStream { let vtbl = self.type_def_vtbl_name(def, generics); let mut methods = quote! {}; let mut method_names = MethodNames::new(); method_names.add_vtable_types(self, def); let phantoms = self.generic_named_phantoms(generics); - match self.reader.type_def_vtables(def).last() { - Some(Type::IUnknown) => { - methods.combine("e! { pub base__: ::windows::core::IUnknown_Vtbl, }) - } - Some(Type::IInspectable) => { - methods.combine("e! { pub base__: ::windows::core::IInspectable_Vtbl, }) - } - Some(Type::TypeDef((def, _))) => { + match type_def_vtables(self.reader, def).last() { + Some(Type::IUnknown) => methods.combine("e! { pub base__: ::windows_core::IUnknown_Vtbl, }), + Some(Type::IInspectable) => methods.combine("e! { pub base__: ::windows_core::IInspectable_Vtbl, }), + Some(Type::TypeDef(def, _)) => { let vtbl = self.type_def_vtbl_name(*def, &[]); methods.combine("e! { pub base__: #vtbl, }); } @@ -880,8 +799,8 @@ impl<'a> Gen<'a> { continue; } let name = method_names.add(self, method); - let signature = self.reader.method_def_signature(method, generics); - let mut cfg = self.reader.signature_cfg(&signature); + let signature = method_def_signature(self.reader, self.reader.type_def_namespace(def), method, generics); + let mut cfg = signature_cfg(self.reader, method); let signature = self.vtbl_signature(def, generics, &signature); cfg.add_feature(self.reader.type_def_namespace(def)); let cfg_all = self.cfg_features(&cfg); @@ -909,65 +828,42 @@ impl<'a> Gen<'a> { } } } - pub fn vtbl_signature( - &self, - def: TypeDef, - _generics: &[Type], - signature: &Signature, - ) -> TokenStream { - let is_winrt = self - .reader - .type_def_flags(def) - .contains(TypeAttributes::WINRT); - let hresult = self.type_name(&Type::HRESULT); - - let (trailing_return_type, return_type, udt_return_type) = if is_winrt { - if let Some(return_type) = &signature.return_type { - if let Type::WinrtArray(kind) = return_type { - let tokens = self.type_abi_name(kind); - ( - quote! { result_size__: *mut u32, result__: *mut *mut #tokens }, - quote! { -> #hresult }, - quote! {}, - ) - } else { - let tokens = self.type_abi_name(return_type); - ( - quote! { result__: *mut #tokens }, - quote! { -> #hresult }, - quote! {}, - ) - } - } else { - (quote! {}, quote! { -> #hresult }, quote! {}) + pub fn vtbl_signature(&self, def: TypeDef, _generics: &[Type], signature: &Signature) -> TokenStream { + let is_winrt = self.reader.type_def_flags(def).contains(TypeAttributes::WindowsRuntime); + + let crate_name = self.crate_name(); + + let (trailing_return_type, return_type, udt_return_type) = match &signature.return_type { + Type::Void if is_winrt => (quote! {}, quote! { -> #crate_name HRESULT }, quote! {}), + Type::Void => (quote! {}, quote! {}, quote! {}), + Type::WinrtArray(kind) => { + let tokens = self.type_abi_name(kind); + (quote! { result_size__: *mut u32, result__: *mut *mut #tokens }, quote! { -> #crate_name HRESULT }, quote! {}) } - } else if let Some(return_type) = &signature.return_type { - if self.reader.type_is_struct(return_type) { - let tokens = self.type_abi_name(return_type); + _ if is_winrt => { + let tokens = self.type_abi_name(&signature.return_type); + (quote! { result__: *mut #tokens }, quote! { -> #crate_name HRESULT }, quote! {}) + } + _ if type_is_struct(self.reader, &signature.return_type) => { + let tokens = self.type_abi_name(&signature.return_type); (quote! {}, quote! {}, quote! { result__: *mut #tokens, }) - } else { - let tokens = self.type_default_name(return_type); + } + _ => { + let tokens = self.type_default_name(&signature.return_type); (quote! {}, quote! { -> #tokens }, quote! {}) } - } else { - (quote! {}, quote! {}, quote! {}) }; let params = signature.params.iter().map(|p| { let name = self.param_name(p.def); if is_winrt { let abi = self.type_abi_name(&p.ty); - let abi_size_name: TokenStream = - format!("{}_array_size", self.reader.param_name(p.def)).into(); - - if self - .reader - .param_flags(p.def) - .contains(ParamAttributes::INPUT) - { + let abi_size_name: TokenStream = format!("{}_array_size", self.reader.param_name(p.def)).into(); + + if self.reader.param_flags(p.def).contains(ParamAttributes::In) { if p.ty.is_winrt_array() { quote! { #abi_size_name: u32, #name: *const #abi, } - } else if p.ty.is_winrt_const_ref() { + } else if p.ty.is_const_ref() { quote! { #name: &#abi, } } else { quote! { #name: #abi, } @@ -1001,13 +897,13 @@ impl<'a> Gen<'a> { to_ident(&self.reader.param_name(param).to_lowercase()) } pub fn return_sig(&self, signature: &Signature) -> TokenStream { - if let Some(return_type) = &signature.return_type { - let tokens = self.type_default_name(return_type); - format!(" -> {}", tokens.as_str()).into() - } else if self.reader.method_def_does_not_return(signature.def) { - " -> !".into() - } else { - " -> ()".into() + match &signature.return_type { + Type::Void if self.reader.has_attribute(signature.def, "DoesNotReturnAttribute") => " -> !".into(), + Type::Void => " -> ()".into(), + _ => { + let tokens = self.type_default_name(&signature.return_type); + format!(" -> {}", tokens.as_str()).into() + } } } pub fn win32_args(&self, params: &[SignatureParam], kind: SignatureKind) -> TokenStream { @@ -1018,27 +914,21 @@ impl<'a> Gen<'a> { SignatureKind::Query(query) if query.object == position => { quote! { &mut result__, } } - SignatureKind::ReturnValue | SignatureKind::ResultValue - if params.len() - 1 == position => - { + SignatureKind::ReturnValue | SignatureKind::ResultValue if params.len() - 1 == position => { quote! { &mut result__, } } SignatureKind::QueryOptional(query) if query.object == position => { quote! { result__ as *mut _ as *mut _, } } - SignatureKind::Query(query) | SignatureKind::QueryOptional(query) - if query.guid == position => - { - quote! { &<T as ::windows::core::ComInterface>::IID, } + SignatureKind::Query(query) | SignatureKind::QueryOptional(query) if query.guid == position => { + quote! { &<T as ::windows_core::ComInterface>::IID, } } _ => { let name = self.param_name(param.def); let flags = self.reader.param_flags(param.def); match param.kind { - SignatureParamKind::ArrayFixed(_) - | SignatureParamKind::ArrayRelativeLen(_) - | SignatureParamKind::ArrayRelativeByteLen(_) => { - let map = if flags.contains(ParamAttributes::OPTIONAL) { + SignatureParamKind::ArrayFixed(_) | SignatureParamKind::ArrayRelativeLen(_) | SignatureParamKind::ArrayRelativeByteLen(_) => { + let map = if flags.contains(ParamAttributes::Optional) { quote! { #name.as_deref().map_or(::core::ptr::null(), |slice|slice.as_ptr()) } } else { quote! { #name.as_ptr() } @@ -1048,7 +938,7 @@ impl<'a> Gen<'a> { SignatureParamKind::ArrayRelativePtr(relative) => { let name = self.param_name(params[relative].def); let flags = self.reader.param_flags(params[relative].def); - if flags.contains(ParamAttributes::OPTIONAL) { + if flags.contains(ParamAttributes::Optional) { quote! { #name.as_deref().map_or(0, |slice|slice.len() as _), } } else { quote! { #name.len() as _, } @@ -1061,7 +951,7 @@ impl<'a> Gen<'a> { quote! { #name.into_param().abi(), } } SignatureParamKind::OptionalPointer => { - if flags.contains(ParamAttributes::OUTPUT) { + if flags.contains(ParamAttributes::Out) { quote! { ::core::mem::transmute(#name.unwrap_or(::std::ptr::null_mut())), } } else { quote! { ::core::mem::transmute(#name.unwrap_or(::std::ptr::null())), } @@ -1071,7 +961,11 @@ impl<'a> Gen<'a> { quote! { #name, } } SignatureParamKind::Blittable => { - quote! { ::core::mem::transmute(#name), } + if matches!(param.ty, Type::PrimitiveOrEnum(_, _)) { + quote! { #name.0 as _, } + } else { + quote! { ::core::mem::transmute(#name), } + } } SignatureParamKind::Other => { quote! { ::core::mem::transmute_copy(#name), } @@ -1095,9 +989,7 @@ impl<'a> Gen<'a> { continue; } } - SignatureKind::ReturnValue | SignatureKind::ResultValue - if params.len() - 1 == position => - { + SignatureKind::ReturnValue | SignatureKind::ResultValue if params.len() - 1 == position => { continue; } _ => {} @@ -1109,21 +1001,13 @@ impl<'a> Gen<'a> { SignatureParamKind::ArrayFixed(fixed) => { let ty = param.ty.deref(); let ty = self.type_default_name(&ty); - let len = Literal::u32_unsuffixed(fixed as _); - let ty = if self - .reader - .param_flags(param.def) - .contains(ParamAttributes::OUTPUT) - { + let len = Literal::u32_unsuffixed(fixed as u32); + let ty = if self.reader.param_flags(param.def).contains(ParamAttributes::Out) { quote! { &mut [#ty; #len] } } else { quote! { &[#ty; #len] } }; - if self - .reader - .param_flags(param.def) - .contains(ParamAttributes::OPTIONAL) - { + if self.reader.param_flags(param.def).contains(ParamAttributes::Optional) { tokens.combine("e! { #name: ::core::option::Option<#ty>, }); } else { tokens.combine("e! { #name: #ty, }); @@ -1132,40 +1016,24 @@ impl<'a> Gen<'a> { SignatureParamKind::ArrayRelativeLen(_) => { let ty = param.ty.deref(); let ty = self.type_default_name(&ty); - let ty = if self - .reader - .param_flags(param.def) - .contains(ParamAttributes::OUTPUT) - { + let ty = if self.reader.param_flags(param.def).contains(ParamAttributes::Out) { quote! { &mut [#ty] } } else { quote! { &[#ty] } }; - if self - .reader - .param_flags(param.def) - .contains(ParamAttributes::OPTIONAL) - { + if self.reader.param_flags(param.def).contains(ParamAttributes::Optional) { tokens.combine("e! { #name: ::core::option::Option<#ty>, }); } else { tokens.combine("e! { #name: #ty, }); } } SignatureParamKind::ArrayRelativeByteLen(_) => { - let ty = if self - .reader - .param_flags(param.def) - .contains(ParamAttributes::OUTPUT) - { + let ty = if self.reader.param_flags(param.def).contains(ParamAttributes::Out) { quote! { &mut [u8] } } else { quote! { &[u8] } }; - if self - .reader - .param_flags(param.def) - .contains(ParamAttributes::OPTIONAL) - { + if self.reader.param_flags(param.def).contains(ParamAttributes::Optional) { tokens.combine("e! { #name: ::core::option::Option<#ty>, }); } else { tokens.combine("e! { #name: #ty, }); @@ -1196,27 +1064,21 @@ impl<'a> Gen<'a> { } pub fn impl_signature(&self, def: TypeDef, signature: &Signature) -> TokenStream { - if self - .reader - .type_def_flags(def) - .contains(TypeAttributes::WINRT) - { + if self.reader.type_def_flags(def).contains(TypeAttributes::WindowsRuntime) { let is_delegate = self.reader.type_def_kind(def) == TypeKind::Delegate; - let params = signature - .params - .iter() - .map(|p| self.winrt_produce_type(p, !is_delegate)); + let params = signature.params.iter().map(|p| self.winrt_produce_type(p, !is_delegate)); - let return_type = if let Some(return_type) = &signature.return_type { - let tokens = self.type_name(return_type); + let return_type = match &signature.return_type { + Type::Void => quote! { () }, + _ => { + let tokens = self.type_name(&signature.return_type); - if 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 + } } - } else { - quote! { () } }; let this = if is_delegate { @@ -1225,9 +1087,9 @@ impl<'a> Gen<'a> { quote! { &self, } }; - quote! { (#this #(#params),*) -> ::windows::core::Result<#return_type> } + quote! { (#this #(#params),*) -> ::windows_core::Result<#return_type> } } else { - let signature_kind = self.reader.signature_kind(signature); + let signature_kind = signature_kind(self.reader, signature); let mut params = quote! {}; if signature_kind == SignatureKind::ResultValue { @@ -1242,14 +1104,12 @@ impl<'a> Gen<'a> { let return_type = match signature_kind { SignatureKind::ReturnVoid => quote! {}, - SignatureKind::Query(_) - | SignatureKind::QueryOptional(_) - | SignatureKind::ResultVoid => quote! { -> ::windows::core::Result<()> }, + SignatureKind::Query(_) | SignatureKind::QueryOptional(_) | SignatureKind::ResultVoid => quote! { -> ::windows_core::Result<()> }, SignatureKind::ResultValue => { let return_type = signature.params[signature.params.len() - 1].ty.deref(); let return_type = self.type_name(&return_type); - quote! { -> ::windows::core::Result<#return_type> } + quote! { -> ::windows_core::Result<#return_type> } } _ => self.return_sig(signature), }; @@ -1260,16 +1120,12 @@ impl<'a> Gen<'a> { fn winrt_produce_type(&self, param: &SignatureParam, include_param_names: bool) -> TokenStream { let default_type = self.type_default_name(¶m.ty); - let sig = if self - .reader - .param_flags(param.def) - .contains(ParamAttributes::INPUT) - { + let sig = if self.reader.param_flags(param.def).contains(ParamAttributes::In) { if param.ty.is_winrt_array() { quote! { &[#default_type] } - } else if self.reader.type_is_primitive(¶m.ty) { + } else if type_is_primitive(self.reader, ¶m.ty) { quote! { #default_type } - } else if self.reader.type_is_nullable(¶m.ty) { + } else if type_is_nullable(self.reader, ¶m.ty) { let type_name = self.type_name(¶m.ty); quote! { ::core::option::Option<&#type_name> } } else { @@ -1279,7 +1135,7 @@ impl<'a> Gen<'a> { quote! { &mut [#default_type] } } else if param.ty.is_winrt_array_ref() { let kind = self.type_name(¶m.ty); - quote! { &mut ::windows::core::Array<#kind> } + quote! { &mut ::windows_core::Array<#kind> } } else { quote! { &mut #default_type } }; @@ -1295,14 +1151,10 @@ impl<'a> Gen<'a> { let name = self.param_name(param.def); let kind = self.type_default_name(¶m.ty); - if self - .reader - .param_flags(param.def) - .contains(ParamAttributes::INPUT) - { - if self.reader.type_is_primitive(¶m.ty) { + if self.reader.param_flags(param.def).contains(ParamAttributes::In) { + if type_is_primitive(self.reader, ¶m.ty) { quote! { #name: #kind, } - } else if self.reader.type_is_nullable(¶m.ty) { + } else if type_is_nullable(self.reader, ¶m.ty) { let kind = self.type_name(¶m.ty); quote! { #name: ::core::option::Option<&#kind>, } } else { @@ -1314,21 +1166,6 @@ impl<'a> Gen<'a> { } } -pub fn to_ident(name: &str) -> TokenStream { - // keywords list based on https://doc.rust-lang.org/reference/keywords.html - match name { - "abstract" | "as" | "become" | "box" | "break" | "const" | "continue" | "crate" | "do" - | "else" | "enum" | "extern" | "false" | "final" | "fn" | "for" | "if" | "impl" | "in" - | "let" | "loop" | "macro" | "match" | "mod" | "move" | "mut" | "override" | "priv" - | "pub" | "ref" | "return" | "static" | "struct" | "super" | "trait" | "true" | "type" - | "typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" | "while" | "yield" - | "try" | "async" | "await" | "dyn" => format!("r#{name}").into(), - "Self" | "self" => format!("{name}_").into(), - "_" => "unused".into(), - _ => trim_tick(name).into(), - } -} - fn mut_ptrs(pointers: usize) -> TokenStream { "*mut ".repeat(pointers).into() } @@ -1380,21 +1217,9 @@ mod tests { #[test] fn test_starts_with() { - assert!(starts_with( - "Windows.Win32.Graphics.Direct3D11on12", - "Windows.Win32.Graphics.Direct3D11on12" - )); - assert!(starts_with( - "Windows.Win32.Graphics.Direct3D11on12", - "Windows.Win32.Graphics" - )); - assert!(!starts_with( - "Windows.Win32.Graphics.Direct3D11on12", - "Windows.Win32.Graphics.Direct3D11" - )); - assert!(!starts_with( - "Windows.Win32.Graphics.Direct3D", - "Windows.Win32.Graphics.Direct3D11" - )); + assert!(starts_with("Windows.Win32.Graphics.Direct3D11on12", "Windows.Win32.Graphics.Direct3D11on12")); + assert!(starts_with("Windows.Win32.Graphics.Direct3D11on12", "Windows.Win32.Graphics")); + assert!(!starts_with("Windows.Win32.Graphics.Direct3D11on12", "Windows.Win32.Graphics.Direct3D11")); + assert!(!starts_with("Windows.Win32.Graphics.Direct3D", "Windows.Win32.Graphics.Direct3D11")); } } diff --git a/vendor/windows-bindgen/src/standalone.rs b/vendor/windows-bindgen/src/standalone.rs deleted file mode 100644 index e8db2fca7..000000000 --- a/vendor/windows-bindgen/src/standalone.rs +++ /dev/null @@ -1,266 +0,0 @@ -use super::*; - -/// Generates standalone Windows bindings. -pub fn standalone(names: &[&str]) -> String { - let files = &File::with_default(&[]).unwrap(); - let reader = &Reader::new(files); - let gen = &mut Gen::new(reader); - standalone_imp(gen, names) -} - -/// Generates standalone Windows bindings for the Rust Standard Library. -pub fn standalone_std(names: &[&str]) -> String { - let files = &File::with_default(&[]).unwrap(); - let reader = &Reader::new(files); - let gen = &mut Gen::new(reader); - gen.std = true; - standalone_imp(gen, names) -} - -fn standalone_imp(gen: &mut Gen, names: &[&str]) -> String { - gen.namespace = "Windows."; - gen.standalone = true; - gen.sys = true; - - let mut type_names = BTreeSet::new(); - let mut core_types = BTreeSet::new(); - let mut enums = BTreeSet::new(); - - for name in names { - let type_name = TypeName::parse(name); - let mut found = false; - - if let Some(def) = gen.reader.get(type_name).next() { - found = true; - type_names.insert(type_name); - let mut cfg = gen.reader.type_def_cfg(def, &[]); - core_types.append(&mut cfg.core_types); - for def in cfg.types.values().flatten() { - type_names.insert(gen.reader.type_def_type_name(*def)); - } - if gen.reader.type_def_kind(def) == TypeKind::Struct - && gen.reader.type_def_fields(def).next().is_none() - && gen.reader.type_def_guid(def).is_some() - { - core_types.insert(Type::GUID); - } - } - - if !found { - for method in gen.reader.namespace_functions(type_name.namespace) { - if found { - break; - } - let name = gen.reader.method_def_name(method); - if name == type_name.name { - found = true; - type_names.insert(type_name); - let mut cfg = gen - .reader - .signature_cfg(&gen.reader.method_def_signature(method, &[])); - core_types.append(&mut cfg.core_types); - for def in cfg.types.values().flatten() { - type_names.insert(gen.reader.type_def_type_name(*def)); - } - } - } - for field in gen.reader.namespace_constants(type_name.namespace) { - if found { - break; - } - let name = gen.reader.field_name(field); - if name == type_name.name { - found = true; - type_names.insert(type_name); - let mut cfg = gen.reader.field_cfg(field); - core_types.append(&mut cfg.core_types); - for def in cfg.types.values().flatten() { - type_names.insert(gen.reader.type_def_type_name(*def)); - } - } - } - } - - if !found { - for def in gen - .reader - .namespace_types(type_name.namespace, &Default::default()) - { - if found { - break; - } - if gen.reader.type_def_kind(def) == TypeKind::Enum { - for field in gen.reader.type_def_fields(def) { - if found { - break; - } - let name = gen.reader.field_name(field); - if name == type_name.name { - found = true; - let enum_name = gen.reader.type_def_type_name(def); - type_names.insert(enum_name); - enums.insert((enum_name, type_name.name)); - } - } - } - } - } - } - - let mut sorted = SortedTokens::default(); - - for ty in core_types { - match ty { - Type::HRESULT => sorted.insert("HRESULT", quote! { pub type HRESULT = i32; }), - Type::String => sorted.insert( - "HSTRING", - quote! { pub type HSTRING = *mut ::core::ffi::c_void; }, - ), - Type::IUnknown => sorted.insert( - "IUnknown", - quote! { pub type IUnknown = *mut ::core::ffi::c_void; }, - ), - Type::IInspectable => sorted.insert( - "IInspectable", - quote! { pub type IInspectable = *mut ::core::ffi::c_void; }, - ), - Type::PSTR => sorted.insert("PSTR", quote! { pub type PSTR = *mut u8; }), - Type::PWSTR => sorted.insert("PWSTR", quote! { pub type PWSTR = *mut u16; }), - Type::PCSTR => sorted.insert("PCSTR", quote! { pub type PCSTR = *const u8; }), - Type::PCWSTR => sorted.insert("PCWSTR", quote! { pub type PCWSTR = *const u16; }), - Type::BSTR => sorted.insert("BSTR", quote! { pub type BSTR = *const u16; }), - Type::GUID => { - sorted.insert("GUID", quote! { - #[repr(C)] - pub struct GUID { - pub data1: u32, - pub data2: u16, - pub data3: u16, - pub data4: [u8; 8], - } - impl GUID { - pub const fn from_u128(uuid: u128) -> Self { - Self { data1: (uuid >> 96) as u32, data2: (uuid >> 80 & 0xffff) as u16, data3: (uuid >> 64 & 0xffff) as u16, data4: (uuid as u64).to_be_bytes() } - } - } - impl ::core::marker::Copy for GUID {} - impl ::core::clone::Clone for GUID { - fn clone(&self) -> Self { - *self - } - } - }); - } - _ => {} - } - } - - for type_name in type_names { - let mut found = false; - - for def in gen.reader.get(type_name) { - found = true; - let kind = gen.reader.type_def_kind(def); - - match kind { - TypeKind::Class | TypeKind::Interface => unimplemented!(), - TypeKind::Enum => { - sorted.insert(gen.reader.type_def_name(def), enums::gen(gen, def)); - } - TypeKind::Struct => { - if gen.reader.type_def_fields(def).next().is_none() { - if let Some(guid) = gen.reader.type_def_guid(def) { - let ident = to_ident(type_name.name); - let value = gen.guid(&guid); - let guid = gen.type_name(&Type::GUID); - sorted.insert( - type_name.name, - quote! { - pub const #ident: #guid = #value; - }, - ); - continue; - } - } - sorted.insert(gen.reader.type_def_name(def), structs::gen(gen, def)); - } - TypeKind::Delegate => { - sorted.insert(gen.reader.type_def_name(def), delegates::gen(gen, def)); - } - } - } - - if !found { - for method in gen.reader.namespace_functions(type_name.namespace) { - if found { - break; - } - let name = gen.reader.method_def_name(method); - if name == type_name.name { - found = true; - sorted.insert( - &format!(".{}.{name}", gen.reader.method_def_module_name(method)), - functions::gen(gen, method), - ); - } - } - for field in gen.reader.namespace_constants(type_name.namespace) { - if found { - break; - } - let name = gen.reader.field_name(field); - if name == type_name.name { - found = true; - sorted.insert(name, constants::gen(gen, field)); - } - } - } - } - - for (enum_type, field_name) in enums { - if let Some(def) = gen.reader.get(enum_type).next() { - for field in gen.reader.type_def_fields(def) { - if gen.reader.field_name(field) == field_name { - let ident = to_ident(field_name); - let ty = to_ident(enum_type.name); - let constant = gen.reader.field_constant(field).unwrap(); - let value = gen.value(&gen.reader.constant_value(constant)); - - sorted.insert( - field_name, - quote! { - pub const #ident: #ty = #value; - }, - ); - - break; - } - } - } - } - - let mut tokens: TokenStream = format!( - r#"// Bindings generated by `windows-bindgen` {} - -"#, - std::env!("CARGO_PKG_VERSION") - ) - .into(); - - tokens.combine(&allow()); - - for value in sorted.0.values() { - tokens.combine(value); - } - - try_format(tokens.into_string()) -} - -#[derive(Default)] -struct SortedTokens(BTreeMap<String, TokenStream>); - -impl SortedTokens { - fn insert(&mut self, key: &str, tokens: TokenStream) { - self.0.entry(key.to_string()).or_default().combine(&tokens); - } -} diff --git a/vendor/windows-bindgen/src/structs.rs b/vendor/windows-bindgen/src/structs.rs deleted file mode 100644 index 89670bdb5..000000000 --- a/vendor/windows-bindgen/src/structs.rs +++ /dev/null @@ -1,316 +0,0 @@ -use super::*; - -pub fn gen(gen: &Gen, def: TypeDef) -> TokenStream { - if gen.reader.type_def_is_contract(def) { - return quote! {}; - } - - if gen.reader.type_def_is_handle(def) { - return handles::gen(gen, def); - } - - gen_struct_with_name(gen, def, gen.reader.type_def_name(def), &Cfg::default()) -} - -fn gen_struct_with_name(gen: &Gen, def: TypeDef, struct_name: &str, cfg: &Cfg) -> TokenStream { - let name = to_ident(struct_name); - - if gen.reader.type_def_fields(def).next().is_none() { - let mut tokens = quote! { - #[repr(C)] - pub struct #name(pub u8); - impl ::core::marker::Copy for #name {} - impl ::core::clone::Clone for #name { - fn clone(&self) -> Self { - *self - } - } - }; - if !gen.sys { - tokens.combine("e! { - impl ::windows::core::TypeKind for #name { - type TypeKind = ::windows::core::CopyType; - } - }); - } - return tokens; - } - - let flags = gen.reader.type_def_flags(def); - let cfg = cfg.union(&gen.reader.type_def_cfg(def, &[])); - - let repr = if let Some(layout) = gen.reader.type_def_class_layout(def) { - let packing = Literal::usize_unsuffixed(gen.reader.class_layout_packing_size(layout)); - quote! { #[repr(C, packed(#packing))] } - } else { - quote! { #[repr(C)] } - }; - - let fields = gen.reader.type_def_fields(def).map(|f| { - let name = to_ident(gen.reader.field_name(f)); - let ty = gen.reader.field_type(f, Some(def)); - - if gen.reader.field_flags(f).contains(FieldAttributes::LITERAL) { - quote! {} - } else if !gen.sys - && flags.contains(TypeAttributes::EXPLICIT_LAYOUT) - && !gen.reader.field_is_copyable(f, def) - { - // Rust can't tell that the type is copyable and won't accept windows::core::ManuallyDrop - let ty = gen.type_default_name(&ty); - quote! { pub #name: ::std::mem::ManuallyDrop<#ty>, } - } else if !gen.sys - && !flags.contains(TypeAttributes::WINRT) - && !gen.reader.field_is_blittable(f, def) - { - if let Type::Win32Array((ty, len)) = ty { - let ty = gen.type_default_name(&ty); - quote! { pub #name: [::std::mem::ManuallyDrop<#ty>; #len], } - } else { - let ty = gen.type_default_name(&ty); - quote! { pub #name: ::std::mem::ManuallyDrop<#ty>, } - } - } else { - let ty = gen.type_default_name(&ty); - quote! { pub #name: #ty, } - } - }); - - let struct_or_union = if flags.contains(TypeAttributes::EXPLICIT_LAYOUT) { - quote! { union } - } else { - quote! { struct } - }; - - let doc = gen.cfg_doc(&cfg); - let features = gen.cfg_features(&cfg); - - let mut tokens = quote! { - #repr - #doc - #features - pub #struct_or_union #name {#(#fields)*} - }; - - tokens.combine(&gen_struct_constants(gen, def, &name, &cfg)); - tokens.combine(&gen_copy_clone(gen, def, &name, &cfg)); - tokens.combine(&gen_debug(gen, def, &name, &cfg)); - tokens.combine(&gen_windows_traits(gen, def, &name, &cfg)); - tokens.combine(&gen_compare_traits(gen, def, &name, &cfg)); - - if !gen.sys { - tokens.combine("e! { - #features - impl ::core::default::Default for #name { - fn default() -> Self { - unsafe { ::core::mem::zeroed() } - } - } - }); - } - - for (index, nested_type) in gen.reader.nested_types(def).enumerate() { - let nested_name = format!("{struct_name}_{index}"); - tokens.combine(&gen_struct_with_name(gen, nested_type, &nested_name, &cfg)); - } - - tokens -} - -fn gen_windows_traits(gen: &Gen, def: TypeDef, name: &TokenStream, cfg: &Cfg) -> TokenStream { - if gen.sys { - quote! {} - } else { - let features = gen.cfg_features(cfg); - let is_copy = gen.reader.type_def_is_blittable(def); - - let type_kind = if is_copy { - quote! { CopyType } - } else { - quote! { ValueType } - }; - - let mut tokens = quote! { - #features - impl ::windows::core::TypeKind for #name { - type TypeKind = ::windows::core::#type_kind; - } - }; - - if gen - .reader - .type_def_flags(def) - .contains(TypeAttributes::WINRT) - { - let signature = - Literal::byte_string(gen.reader.type_def_signature(def, &[]).as_bytes()); - - tokens.combine("e! { - #features - impl ::windows::core::RuntimeType for #name { - const SIGNATURE: ::windows::imp::ConstBuffer = ::windows::imp::ConstBuffer::from_slice(#signature); - } - }); - } - - tokens - } -} - -fn gen_compare_traits(gen: &Gen, def: TypeDef, name: &TokenStream, cfg: &Cfg) -> TokenStream { - let features = gen.cfg_features(cfg); - - if gen.sys - || gen.reader.type_def_has_explicit_layout(def) - || gen.reader.type_def_has_packing(def) - || gen.reader.type_def_has_callback(def) - { - quote! {} - } else { - let fields = gen.reader.type_def_fields(def).filter_map(|f| { - let name = to_ident(gen.reader.field_name(f)); - if gen.reader.field_flags(f).contains(FieldAttributes::LITERAL) { - None - } else { - Some(quote! { self.#name == other.#name }) - } - }); - - quote! { - #features - impl ::core::cmp::PartialEq for #name { - fn eq(&self, other: &Self) -> bool { - #(#fields)&&* - } - } - #features - impl ::core::cmp::Eq for #name {} - } - } -} - -fn gen_debug(gen: &Gen, def: TypeDef, ident: &TokenStream, cfg: &Cfg) -> TokenStream { - if gen.sys - || gen.reader.type_def_has_explicit_layout(def) - || gen.reader.type_def_has_packing(def) - { - quote! {} - } else { - let name = ident.as_str(); - let features = gen.cfg_features(cfg); - - let fields = gen.reader.type_def_fields(def).filter_map(|f| { - if gen.reader.field_flags(f).contains(FieldAttributes::LITERAL) { - None - } else { - let name = gen.reader.field_name(f); - let ident = to_ident(name); - let ty = gen.reader.field_type(f, Some(def)); - if gen.reader.type_has_callback(&ty) { - None - } else { - Some(quote! { .field(#name, &self.#ident) }) - } - } - }); - - quote! { - #features - impl ::core::fmt::Debug for #ident { - fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result { - f.debug_struct(#name) #(#fields)* .finish() - } - } - } - } -} - -fn gen_copy_clone(gen: &Gen, def: TypeDef, name: &TokenStream, cfg: &Cfg) -> TokenStream { - let features = gen.cfg_features(cfg); - - if gen.sys || gen.reader.type_def_is_copyable(def) { - quote! { - #features - impl ::core::marker::Copy for #name {} - #features - impl ::core::clone::Clone for #name { - fn clone(&self) -> Self { - *self - } - } - } - } else if gen.reader.type_def_class_layout(def).is_some() { - // Don't support copy/clone of packed structs: https://github.com/rust-lang/rust/issues/82523 - quote! {} - } else if !gen - .reader - .type_def_flags(def) - .contains(TypeAttributes::WINRT) - { - quote! { - #features - impl ::core::clone::Clone for #name { - fn clone(&self) -> Self { - unsafe { ::core::mem::transmute_copy(self) } - } - } - } - } else { - let fields = gen.reader.type_def_fields(def).map(|f| { - let name = to_ident(gen.reader.field_name(f)); - if gen.reader.field_flags(f).contains(FieldAttributes::LITERAL) { - quote! {} - } else if gen.reader.field_is_blittable(f, def) { - quote! { #name: self.#name } - } else { - quote! { #name: self.#name.clone() } - } - }); - - quote! { - #features - impl ::core::clone::Clone for #name { - fn clone(&self) -> Self { - Self { #(#fields),* } - } - } - } - } -} - -fn gen_struct_constants( - gen: &Gen, - def: TypeDef, - struct_name: &TokenStream, - cfg: &Cfg, -) -> TokenStream { - let features = gen.cfg_features(cfg); - - let constants = gen.reader.type_def_fields(def).filter_map(|f| { - if gen.reader.field_flags(f).contains(FieldAttributes::LITERAL) { - if let Some(constant) = gen.reader.field_constant(f) { - let name = to_ident(gen.reader.field_name(f)); - let value = gen.typed_value(&gen.reader.constant_value(constant)); - - return Some(quote! { - pub const #name: #value; - }); - } - } - - None - }); - - let mut tokens = quote! { #(#constants)* }; - - if !tokens.is_empty() { - tokens = quote! { - #features - impl #struct_name { - #tokens - } - }; - } - - tokens -} diff --git a/vendor/windows-bindgen/src/tokens/mod.rs b/vendor/windows-bindgen/src/tokens/mod.rs new file mode 100644 index 000000000..e5f019a8b --- /dev/null +++ b/vendor/windows-bindgen/src/tokens/mod.rs @@ -0,0 +1,443 @@ +#![allow(dead_code)] + +mod to_tokens; +mod token_stream; + +pub mod runtime; +pub use to_tokens::*; +pub use token_stream::*; + +/// The whole point. +/// +/// Performs variable interpolation against the input and produces it as +/// [`TokenStream`]. +/// +/// # Interpolation +/// +/// Variable interpolation is done with `#var` (similar to `$var` in +/// `macro_rules!` macros). This grabs the `var` variable that is currently in +/// scope and inserts it in that location in the output tokens. Any type +/// implementing the [`ToTokens`] trait can be interpolated. This includes most +/// Rust primitive types. +/// +/// [`ToTokens`]: trait.ToTokens.html +/// +/// Repetition is done using `#(...)*` or `#(...),*` again similar to +/// `macro_rules!`. This iterates through the elements of any variable +/// interpolated within the repetition and inserts a copy of the repetition body +/// for each one. The variables in an interpolation may be a `Vec`, slice, +/// `BTreeSet`, or any `Iterator`. +/// +/// - `#(#var)*` — no separators +/// - `#(#var),*` — the character before the asterisk is used as a separator +/// - `#( struct #var; )*` — the repetition can contain other tokens +/// - `#( #k => println!("{}", #v), )*` — even multiple interpolations +#[macro_export] +#[doc(hidden)] +macro_rules! quote { + () => { + $crate::tokens::TokenStream::new() + }; + ($($tt:tt)*) => {{ + let mut _s = $crate::tokens::TokenStream::new(); + $crate::quote_each_token!(_s $($tt)*); + _s + }}; +} + +pub use quote; + +/// Formatting macro for constructing a `TokenStream`. +/// +/// <br> +/// +/// # Syntax +/// +/// Syntax is copied from the [`format!`] macro, supporting both positional and +/// named arguments. +#[macro_export] +#[doc(hidden)] +macro_rules! format_token { + ($($fmt:tt)*) => { + $crate::TokenStream::from(format!($($fmt)*)) + }; +} + +// Extract the names of all #metavariables and pass them to the $call macro. +// +// in: pounded_var_names!(then!(...) a #b c #( #d )* #e) +// out: then!(... b); +// then!(... d); +// then!(... e); +#[macro_export] +#[doc(hidden)] +macro_rules! pounded_var_names { + ($call:ident! $extra:tt $($tts:tt)*) => { + $crate::pounded_var_names_with_context!($call! $extra + (@ $($tts)*) + ($($tts)* @) + ) + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! pounded_var_names_with_context { + ($call:ident! $extra:tt ($($b1:tt)*) ($($curr:tt)*)) => { + $( + $crate::pounded_var_with_context!($call! $extra $b1 $curr); + )* + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! pounded_var_with_context { + ($call:ident! $extra:tt $b1:tt ( $($inner:tt)* )) => { + $crate::pounded_var_names!($call! $extra $($inner)*); + }; + + ($call:ident! $extra:tt $b1:tt [ $($inner:tt)* ]) => { + $crate::pounded_var_names!($call! $extra $($inner)*); + }; + + ($call:ident! $extra:tt $b1:tt { $($inner:tt)* }) => { + $crate::pounded_var_names!($call! $extra $($inner)*); + }; + + ($call:ident!($($extra:tt)*) # $var:ident) => { + $crate::$call!($($extra)* $var); + }; + + ($call:ident! $extra:tt $b1:tt $curr:tt) => {}; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! quote_bind_into_iter { + ($has_iter:ident $var:ident) => { + // `mut` may be unused if $var occurs multiple times in the list. + #[allow(unused_mut)] + let (mut $var, i) = $var.quote_into_iter(); + let $has_iter = $has_iter | i; + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! quote_bind_next_or_break { + ($var:ident) => { + let $var = match $var.next() { + Some(_x) => $crate::tokens::runtime::RepInterp(_x), + None => break, + }; + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! quote_each_token { + ($tokens:ident $($tts:tt)*) => { + $crate::quote_tokens_with_context!($tokens + (@ @ @ @ @ @ $($tts)*) + (@ @ @ @ @ $($tts)* @) + (@ @ @ @ $($tts)* @ @) + (@ @ @ $(($tts))* @ @ @) + (@ @ $($tts)* @ @ @ @) + (@ $($tts)* @ @ @ @ @) + ($($tts)* @ @ @ @ @ @) + ); + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! quote_tokens_with_context { + ($tokens:ident + ($($b3:tt)*) ($($b2:tt)*) ($($b1:tt)*) + ($($curr:tt)*) + ($($a1:tt)*) ($($a2:tt)*) ($($a3:tt)*) + ) => { + $( + $crate::quote_token_with_context!($tokens $b3 $b2 $b1 $curr $a1 $a2 $a3); + )* + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! quote_token_with_context { + ($tokens:ident $b3:tt $b2:tt $b1:tt @ $a1:tt $a2:tt $a3:tt) => {}; + + ($tokens:ident $b3:tt $b2:tt $b1:tt (#) ( $($inner:tt)* ) * $a3:tt) => {{ + use $crate::tokens::runtime::ext::*; + let has_iter = $crate::tokens::runtime::ThereIsNoIteratorInRepetition; + $crate::pounded_var_names!(quote_bind_into_iter!(has_iter) () $($inner)*); + let _: $crate::tokens::runtime::HasIterator = has_iter; + // This is `while true` instead of `loop` because if there are no + // iterators used inside of this repetition then the body would not + // contain any `break`, so the compiler would emit unreachable code + // warnings on anything below the loop. We use has_iter to detect and + // fail to compile when there are no iterators, so here we just work + // around the unneeded extra warning. + while true { + $crate::pounded_var_names!(quote_bind_next_or_break!() () $($inner)*); + $crate::quote_each_token!($tokens $($inner)*); + } + }}; + ($tokens:ident $b3:tt $b2:tt # (( $($inner:tt)* )) * $a2:tt $a3:tt) => {}; + ($tokens:ident $b3:tt # ( $($inner:tt)* ) (*) $a1:tt $a2:tt $a3:tt) => {}; + + ($tokens:ident $b3:tt $b2:tt $b1:tt (#) ( $($inner:tt)* ) $sep:tt *) => {{ + use $crate::tokens::runtime::ext::*; + let mut _i = 0usize; + let has_iter = $crate::tokens::runtime::ThereIsNoIteratorInRepetition; + $crate::pounded_var_names!(quote_bind_into_iter!(has_iter) () $($inner)*); + let _: $crate::tokens::runtime::HasIterator = has_iter; + while true { + $crate::pounded_var_names!(quote_bind_next_or_break!() () $($inner)*); + if _i > 0 { + $crate::quote_token!($tokens $sep); + } + _i += 1; + $crate::quote_each_token!($tokens $($inner)*); + } + }}; + ($tokens:ident $b3:tt $b2:tt # (( $($inner:tt)* )) $sep:tt * $a3:tt) => {}; + ($tokens:ident $b3:tt # ( $($inner:tt)* ) ($sep:tt) * $a2:tt $a3:tt) => {}; + ($tokens:ident # ( $($inner:tt)* ) * (*) $a1:tt $a2:tt $a3:tt) => { + // https://github.com/dtolnay/quote/issues/130 + $crate::quote_token!($tokens *); + }; + ($tokens:ident # ( $($inner:tt)* ) $sep:tt (*) $a1:tt $a2:tt $a3:tt) => {}; + + ($tokens:ident $b3:tt $b2:tt $b1:tt (#) $var:ident $a2:tt $a3:tt) => { + $crate::tokens::ToTokens::to_tokens(&$var, &mut $tokens); + }; + ($tokens:ident $b3:tt $b2:tt # ($var:ident) $a1:tt $a2:tt $a3:tt) => {}; + ($tokens:ident $b3:tt $b2:tt $b1:tt ($curr:tt) $a1:tt $a2:tt $a3:tt) => { + $crate::quote_token!($tokens $curr); + }; +} + +#[macro_export] +#[doc(hidden)] +macro_rules! quote_token { + ($tokens:ident ( $($inner:tt)* )) => { + $crate::tokens::runtime::push_group( + &mut $tokens, + $crate::tokens::Delimiter::Parenthesis, + $crate::quote!($($inner)*), + ); + }; + + ($tokens:ident [ $($inner:tt)* ]) => { + $crate::tokens::runtime::push_group( + &mut $tokens, + $crate::tokens::Delimiter::Bracket, + $crate::quote!($($inner)*), + ); + }; + + ($tokens:ident { $($inner:tt)* }) => { + $crate::tokens::runtime::push_group( + &mut $tokens, + $crate::tokens::Delimiter::Brace, + $crate::quote!($($inner)*), + ); + }; + + ($tokens:ident +) => { + $crate::tokens::runtime::push_add(&mut $tokens); + }; + + ($tokens:ident +=) => { + $crate::tokens::runtime::push_add_eq(&mut $tokens); + }; + + ($tokens:ident &) => { + $crate::tokens::runtime::push_and(&mut $tokens); + }; + + ($tokens:ident &&) => { + $crate::tokens::runtime::push_and_and(&mut $tokens); + }; + + ($tokens:ident &=) => { + $crate::tokens::runtime::push_and_eq(&mut $tokens); + }; + + ($tokens:ident @) => { + $crate::tokens::runtime::push_at(&mut $tokens); + }; + + ($tokens:ident !) => { + $crate::tokens::runtime::push_bang(&mut $tokens); + }; + + ($tokens:ident ^) => { + $crate::tokens::runtime::push_caret(&mut $tokens); + }; + + ($tokens:ident ^=) => { + $crate::tokens::runtime::push_caret_eq(&mut $tokens); + }; + + ($tokens:ident :) => { + $crate::tokens::runtime::push_colon(&mut $tokens); + }; + + ($tokens:ident ::) => { + $crate::tokens::runtime::push_colon2(&mut $tokens); + }; + + ($tokens:ident ,) => { + $crate::tokens::runtime::push_comma(&mut $tokens); + }; + + ($tokens:ident /) => { + $crate::tokens::runtime::push_div(&mut $tokens); + }; + + ($tokens:ident /=) => { + $crate::tokens::runtime::push_div_eq(&mut $tokens); + }; + + ($tokens:ident .) => { + $crate::tokens::runtime::push_dot(&mut $tokens); + }; + + ($tokens:ident ..) => { + $crate::tokens::runtime::push_dot2(&mut $tokens); + }; + + ($tokens:ident ...) => { + $crate::tokens::runtime::push_dot3(&mut $tokens); + }; + + ($tokens:ident ..=) => { + $crate::tokens::runtime::push_dot_dot_eq(&mut $tokens); + }; + + ($tokens:ident =) => { + $crate::tokens::runtime::push_eq(&mut $tokens); + }; + + ($tokens:ident ==) => { + $crate::tokens::runtime::push_eq_eq(&mut $tokens); + }; + + ($tokens:ident >=) => { + $crate::tokens::runtime::push_ge(&mut $tokens); + }; + + ($tokens:ident >) => { + $crate::tokens::runtime::push_gt(&mut $tokens); + }; + + ($tokens:ident <=) => { + $crate::tokens::runtime::push_le(&mut $tokens); + }; + + ($tokens:ident <) => { + $crate::tokens::runtime::push_lt(&mut $tokens); + }; + + ($tokens:ident *=) => { + $crate::tokens::runtime::push_mul_eq(&mut $tokens); + }; + + ($tokens:ident !=) => { + $crate::tokens::runtime::push_ne(&mut $tokens); + }; + + ($tokens:ident |) => { + $crate::tokens::runtime::push_or(&mut $tokens); + }; + + ($tokens:ident |=) => { + $crate::tokens::runtime::push_or_eq(&mut $tokens); + }; + + ($tokens:ident ||) => { + $crate::tokens::runtime::push_or_or(&mut $tokens); + }; + + ($tokens:ident #) => { + $crate::tokens::runtime::push_pound(&mut $tokens); + }; + + ($tokens:ident ?) => { + $crate::tokens::runtime::push_question(&mut $tokens); + }; + + ($tokens:ident ->) => { + $crate::tokens::runtime::push_rarrow(&mut $tokens); + }; + + ($tokens:ident <-) => { + $crate::tokens::runtime::push_larrow(&mut $tokens); + }; + + ($tokens:ident %) => { + $crate::tokens::runtime::push_rem(&mut $tokens); + }; + + ($tokens:ident %=) => { + $crate::tokens::runtime::push_rem_eq(&mut $tokens); + }; + + ($tokens:ident =>) => { + $crate::tokens::runtime::push_fat_arrow(&mut $tokens); + }; + + ($tokens:ident ;) => { + $crate::tokens::runtime::push_semi(&mut $tokens); + }; + + ($tokens:ident <<) => { + $crate::tokens::runtime::push_shl(&mut $tokens); + }; + + ($tokens:ident <<=) => { + $crate::tokens::runtime::push_shl_eq(&mut $tokens); + }; + + ($tokens:ident >>) => { + $crate::tokens::runtime::push_shr(&mut $tokens); + }; + + ($tokens:ident >>=) => { + $crate::tokens::runtime::push_shr_eq(&mut $tokens); + }; + + ($tokens:ident *) => { + $crate::tokens::runtime::push_star(&mut $tokens); + }; + + ($tokens:ident -) => { + $crate::tokens::runtime::push_sub(&mut $tokens); + }; + + ($tokens:ident -=) => { + $crate::tokens::runtime::push_sub_eq(&mut $tokens); + }; + + ($tokens:ident $ident:ident) => { + $crate::tokens::runtime::push_ident(&mut $tokens, stringify!($ident)); + }; + + ($tokens:ident $other:tt) => { + $crate::tokens::runtime::parse(&mut $tokens, stringify!($other)); + }; +} + +pub fn to_ident(name: &str) -> TokenStream { + // keywords list based on https://doc.rust-lang.org/reference/keywords.html + match name { + "abstract" | "as" | "become" | "box" | "break" | "const" | "continue" | "crate" | "do" | "else" | "enum" | "extern" | "false" | "final" | "fn" | "for" | "if" | "impl" | "in" | "let" | "loop" | "macro" | "match" | "mod" | "move" | "mut" | "override" | "priv" | "pub" | "ref" | "return" | "static" | "struct" | "super" | "trait" | "true" | "type" | "typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" | "while" | "yield" | "try" | "async" | "await" | "dyn" => format!("r#{name}").into(), + "Self" | "self" => format!("{name}_").into(), + "_" => "unused".into(), + _ => crate::trim_tick(name).into(), + } +} diff --git a/vendor/windows-bindgen/src/tokens/runtime.rs b/vendor/windows-bindgen/src/tokens/runtime.rs new file mode 100644 index 000000000..83bc42a04 --- /dev/null +++ b/vendor/windows-bindgen/src/tokens/runtime.rs @@ -0,0 +1,274 @@ +use super::{Delimiter, ToTokens, TokenStream}; +use core::ops::BitOr; + +pub struct HasIterator; // True +pub struct ThereIsNoIteratorInRepetition; // False + +impl BitOr<ThereIsNoIteratorInRepetition> for ThereIsNoIteratorInRepetition { + type Output = ThereIsNoIteratorInRepetition; + fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> ThereIsNoIteratorInRepetition { + ThereIsNoIteratorInRepetition + } +} + +impl BitOr<ThereIsNoIteratorInRepetition> for HasIterator { + type Output = HasIterator; + fn bitor(self, _rhs: ThereIsNoIteratorInRepetition) -> HasIterator { + HasIterator + } +} + +impl BitOr<HasIterator> for ThereIsNoIteratorInRepetition { + type Output = HasIterator; + fn bitor(self, _rhs: HasIterator) -> HasIterator { + HasIterator + } +} + +impl BitOr<HasIterator> for HasIterator { + type Output = HasIterator; + fn bitor(self, _rhs: HasIterator) -> HasIterator { + HasIterator + } +} + +/// Extension traits used by the implementation of `quote!`. These are defined +/// in separate traits, rather than as a single trait due to ambiguity issues. +/// +/// These traits expose a `quote_into_iter` method which should allow calling +/// whichever impl happens to be applicable. Calling that method repeatedly on +/// the returned value should be idempotent. +pub mod ext { + use super::RepInterp; + use super::ToTokens; + use super::{HasIterator as HasIter, ThereIsNoIteratorInRepetition as DoesNotHaveIter}; + use core::slice; + use std::collections::btree_set::{self, BTreeSet}; + + /// Extension trait providing the `quote_into_iter` method on iterators. + pub trait RepIteratorExt: Iterator + Sized { + fn quote_into_iter(self) -> (Self, HasIter) { + (self, HasIter) + } + } + + impl<T: Iterator> RepIteratorExt for T {} + + /// Extension trait providing the `quote_into_iter` method for + /// non-iterable types. These types interpolate the same value in each + /// iteration of the repetition. + pub trait RepToTokensExt { + /// Pretend to be an iterator for the purposes of `quote_into_iter`. + /// This allows repeated calls to `quote_into_iter` to continue + /// correctly returning DoesNotHaveIter. + fn next(&self) -> Option<&Self> { + Some(self) + } + + fn quote_into_iter(&self) -> (&Self, DoesNotHaveIter) { + (self, DoesNotHaveIter) + } + } + + impl<T: ToTokens + ?Sized> RepToTokensExt for T {} + + /// Extension trait providing the `quote_into_iter` method for types that + /// can be referenced as an iterator. + pub trait RepAsIteratorExt<'q> { + type Iter: Iterator; + + fn quote_into_iter(&'q self) -> (Self::Iter, HasIter); + } + + impl<'q, 'a, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &'a T { + type Iter = T::Iter; + + fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) { + <T as RepAsIteratorExt>::quote_into_iter(*self) + } + } + + impl<'q, 'a, T: RepAsIteratorExt<'q> + ?Sized> RepAsIteratorExt<'q> for &'a mut T { + type Iter = T::Iter; + + fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) { + <T as RepAsIteratorExt>::quote_into_iter(*self) + } + } + + impl<'q, T: 'q> RepAsIteratorExt<'q> for [T] { + type Iter = slice::Iter<'q, T>; + + fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) { + (self.iter(), HasIter) + } + } + + impl<'q, T: 'q> RepAsIteratorExt<'q> for Vec<T> { + type Iter = slice::Iter<'q, T>; + + fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) { + (self.iter(), HasIter) + } + } + + impl<'q, T: 'q> RepAsIteratorExt<'q> for BTreeSet<T> { + type Iter = btree_set::Iter<'q, T>; + + fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) { + (self.iter(), HasIter) + } + } + + macro_rules! array_rep_slice { + ($($l:tt)*) => { + $( + impl<'q, T: 'q> RepAsIteratorExt<'q> for [T; $l] { + type Iter = slice::Iter<'q, T>; + + fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) { + (self.iter(), HasIter) + } + } + )* + } + } + + array_rep_slice!( + 0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 + 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 + ); + + impl<'q, T: RepAsIteratorExt<'q>> RepAsIteratorExt<'q> for RepInterp<T> { + type Iter = T::Iter; + + fn quote_into_iter(&'q self) -> (Self::Iter, HasIter) { + self.0.quote_into_iter() + } + } +} + +// Helper type used within interpolations to allow for repeated binding names. +// Implements the relevant traits, and exports a dummy `next()` method. +#[derive(Copy, Clone)] +pub struct RepInterp<T>(pub T); + +impl<T> RepInterp<T> { + // This method is intended to look like `Iterator::next`, and is called when + // a name is bound multiple times, as the previous binding will shadow the + // original `Iterator` object. This allows us to avoid advancing the + // iterator multiple times per iteration. + pub fn next(self) -> Option<T> { + Some(self.0) + } +} + +impl<T: Iterator> Iterator for RepInterp<T> { + type Item = T::Item; + + fn next(&mut self) -> Option<Self::Item> { + self.0.next() + } +} + +impl<T: ToTokens> ToTokens for RepInterp<T> { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.0.to_tokens(tokens); + } +} + +pub fn push_group(tokens: &mut TokenStream, delimiter: Delimiter, inner: TokenStream) { + tokens.push_space(); + tokens.push(delimiter.open()); + tokens.combine(&inner); + tokens.push_space(); + tokens.push(delimiter.close()); +} + +pub fn parse(tokens: &mut TokenStream, s: &str) { + tokens.push_space(); + tokens.push_str(s); +} + +pub fn push_ident(tokens: &mut TokenStream, s: &str) { + match tokens.0.chars().last() { + None | Some(':') => {} + _ => tokens.0.push(' '), + } + tokens.push_str(s); +} + +pub fn push_colon2(tokens: &mut TokenStream) { + match tokens.0.chars().last() { + Some(':') => tokens.push_str(" ::"), + _ => tokens.push_str("::"), + } +} + +macro_rules! push_punct { + ($name:ident $char1:tt) => { + pub fn $name(tokens: &mut TokenStream) { + tokens.push_space(); + tokens.push($char1); + } + }; + ($name:ident $char1:tt $char2:tt) => { + pub fn $name(tokens: &mut TokenStream) { + tokens.push_space(); + tokens.push($char1); + tokens.push($char2); + } + }; + ($name:ident $char1:tt $char2:tt $char3:tt) => { + pub fn $name(tokens: &mut TokenStream) { + tokens.push(' '); + tokens.push($char1); + tokens.push($char2); + tokens.push($char3); + } + }; +} + +push_punct!(push_add '+'); +push_punct!(push_add_eq '+' '='); +push_punct!(push_and '&'); +push_punct!(push_and_and '&' '&'); +push_punct!(push_and_eq '&' '='); +push_punct!(push_at '@'); +push_punct!(push_bang '!'); +push_punct!(push_caret '^'); +push_punct!(push_caret_eq '^' '='); +push_punct!(push_colon ':'); +push_punct!(push_comma ','); +push_punct!(push_div '/'); +push_punct!(push_div_eq '/' '='); +push_punct!(push_dot '.'); +push_punct!(push_dot2 '.' '.'); +push_punct!(push_dot3 '.' '.' '.'); +push_punct!(push_dot_dot_eq '.' '.' '='); +push_punct!(push_eq '='); +push_punct!(push_eq_eq '=' '='); +push_punct!(push_ge '>' '='); +push_punct!(push_gt '>'); +push_punct!(push_le '<' '='); +push_punct!(push_lt '<'); +push_punct!(push_mul_eq '*' '='); +push_punct!(push_ne '!' '='); +push_punct!(push_or '|'); +push_punct!(push_or_eq '|' '='); +push_punct!(push_or_or '|' '|'); +push_punct!(push_pound '#'); +push_punct!(push_question '?'); +push_punct!(push_rarrow '-' '>'); +push_punct!(push_larrow '<' '-'); +push_punct!(push_rem '%'); +push_punct!(push_rem_eq '%' '='); +push_punct!(push_fat_arrow '=' '>'); +push_punct!(push_semi ';'); +push_punct!(push_shl '<' '<'); +push_punct!(push_shl_eq '<' '<' '='); +push_punct!(push_shr '>' '>'); +push_punct!(push_shr_eq '>' '>' '='); +push_punct!(push_star '*'); +push_punct!(push_sub '-'); +push_punct!(push_sub_eq '-' '='); diff --git a/vendor/windows-bindgen/src/tokens/to_tokens.rs b/vendor/windows-bindgen/src/tokens/to_tokens.rs new file mode 100644 index 000000000..cb614f33d --- /dev/null +++ b/vendor/windows-bindgen/src/tokens/to_tokens.rs @@ -0,0 +1,149 @@ +use std::borrow::Cow; +use std::rc::Rc; + +use super::{Literal, TokenStream}; + +/// Types that can be interpolated inside a `quote!` invocation. +/// +/// [`quote!`]: macro.quote.html +pub trait ToTokens { + /// Write `self` to the given `TokenStream`. + fn to_tokens(&self, tokens: &mut TokenStream); + + /// Convert `self` directly into a `TokenStream` object. + /// + /// This method is implicitly implemented using `to_tokens`, and acts as a + /// convenience method for consumers of the `ToTokens` trait. + fn to_token_stream(&self) -> TokenStream { + let mut tokens = TokenStream::new(); + self.to_tokens(&mut tokens); + tokens + } + + /// Convert `self` directly into a `TokenStream` object. + /// + /// This method is implicitly implemented using `to_tokens`, and acts as a + /// convenience method for consumers of the `ToTokens` trait. + fn into_token_stream(self) -> TokenStream + where + Self: Sized, + { + self.to_token_stream() + } +} + +impl<'a, T: ?Sized + ToTokens> ToTokens for &'a T { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens); + } +} + +impl<'a, T: ?Sized + ToTokens> ToTokens for &'a mut T { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens); + } +} + +impl<'a, T: ?Sized + ToOwned + ToTokens> ToTokens for Cow<'a, T> { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens); + } +} + +impl<T: ?Sized + ToTokens> ToTokens for Box<T> { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens); + } +} + +impl<T: ?Sized + ToTokens> ToTokens for Rc<T> { + fn to_tokens(&self, tokens: &mut TokenStream) { + (**self).to_tokens(tokens); + } +} + +impl<T: ToTokens> ToTokens for Option<T> { + fn to_tokens(&self, tokens: &mut TokenStream) { + if let Some(ref t) = *self { + t.to_tokens(tokens); + } + } +} + +impl ToTokens for str { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.push_str(" \""); + tokens.push_str(self); + tokens.push('"'); + } +} + +impl ToTokens for String { + fn to_tokens(&self, tokens: &mut TokenStream) { + self.as_str().to_tokens(tokens); + } +} + +macro_rules! primitive { + ($($t:ident => $name:ident)*) => ($( + impl ToTokens for $t { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.push_space(); + tokens.push_str(&self.to_string()); + tokens.push_str(stringify!($t)); + } + } + )*) +} + +primitive! { + i8 => i8_suffixed + i16 => i16_suffixed + i32 => i32_suffixed + i64 => i64_suffixed + i128 => i128_suffixed + isize => isize_suffixed + + u8 => u8_suffixed + u16 => u16_suffixed + u32 => u32_suffixed + u64 => u64_suffixed + u128 => u128_suffixed + usize => usize_suffixed + + f32 => f32_suffixed + f64 => f64_suffixed +} + +impl ToTokens for char { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.push_space(); + tokens.push('\''); + tokens.push(*self); + tokens.push('\''); + } +} + +impl ToTokens for bool { + fn to_tokens(&self, tokens: &mut TokenStream) { + let word = if *self { "true" } else { "false" }; + tokens.push_space(); + tokens.push_str(word); + } +} + +impl ToTokens for Literal { + fn to_tokens(&self, tokens: &mut TokenStream) { + tokens.push_str(self.as_str()); + } +} + +impl ToTokens for TokenStream { + fn to_tokens(&self, dst: &mut TokenStream) { + dst.combine(self); + } + + fn into_token_stream(self) -> TokenStream { + self + } +} diff --git a/vendor/windows-bindgen/src/tokens/token_stream.rs b/vendor/windows-bindgen/src/tokens/token_stream.rs new file mode 100644 index 000000000..3b3a09bdd --- /dev/null +++ b/vendor/windows-bindgen/src/tokens/token_stream.rs @@ -0,0 +1,164 @@ +/// A stream of tokens +#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)] +pub struct TokenStream(pub String); + +impl From<String> for TokenStream { + fn from(tokens: String) -> Self { + Self(tokens) + } +} + +impl From<&String> for TokenStream { + fn from(tokens: &String) -> Self { + Self(tokens.to_string()) + } +} + +impl From<&str> for TokenStream { + fn from(tokens: &str) -> Self { + Self(tokens.to_string()) + } +} + +impl TokenStream { + pub fn new() -> Self { + Self(String::new()) + } + + /// Appends another stream to the stream + /// + /// note: a space will be inserted before the other stream + pub fn combine(&mut self, other: &TokenStream) { + self.push_space(); + self.0.push_str(&other.0) + } + + #[must_use] + pub fn join(&self, value: &str) -> Self { + Self(format!("{}{value}", self.0)) + } + + pub fn is_empty(&self) -> bool { + self.0.is_empty() + } + + /// View the stream as a string + pub fn as_str(&self) -> &str { + &self.0 + } + + /// Convert the stream into a `String` + pub fn into_string(self) -> String { + self.0 + } + + /// Parse the token stream as something + /// + /// Mostly used with `proc_macro2::TokenStream` or `proc_macro::TokenStream` + pub fn parse<T: core::str::FromStr>(self) -> Result<T, T::Err> { + self.into_string().parse() + } + + pub(crate) fn push_space(&mut self) { + match self.last_char() { + None | Some(' ') => {} + _ => self.0.push(' '), + } + } + + pub fn push(&mut self, c: char) { + self.0.push(c) + } + + pub fn push_str(&mut self, str: &str) { + self.0.push_str(str) + } + + fn last_char(&self) -> Option<char> { + self.0.chars().last() + } +} + +impl Default for TokenStream { + fn default() -> Self { + Self::new() + } +} + +impl core::iter::FromIterator<TokenStream> for TokenStream { + fn from_iter<I: IntoIterator<Item = TokenStream>>(iter: I) -> Self { + iter.into_iter() + .fold(None, |accum: Option<TokenStream>, n| { + let mut ts = accum.unwrap_or_default(); + ts.combine(&n); + Some(ts) + }) + .unwrap_or_else(TokenStream::new) + } +} + +/// A delimiter around a block of code +#[derive(Copy, Clone)] +pub enum Delimiter { + /// `[]` + Bracket, + /// `{}` + Brace, + /// `()` + Parenthesis, +} + +impl Delimiter { + /// The opening delimiter + pub fn open(self) -> char { + match self { + Delimiter::Bracket => '[', + Delimiter::Brace => '{', + Delimiter::Parenthesis => '(', + } + } + + /// The closing delimiter + pub fn close(self) -> char { + match self { + Delimiter::Bracket => ']', + Delimiter::Brace => '}', + Delimiter::Parenthesis => ')', + } + } +} + +/// A literal of some sort +pub struct Literal { + inner: String, +} + +macro_rules! unsuffixed { + ($ty:ty => $name:ident) => { + pub fn $name(n: $ty) -> Self { + Self { inner: n.to_string() } + } + }; +} + +impl Literal { + unsuffixed!(i64 => i64_unsuffixed); + unsuffixed!(usize => usize_unsuffixed); + unsuffixed!(u32 => u32_unsuffixed); + unsuffixed!(u16 => u16_unsuffixed); + unsuffixed!(u8 => u8_unsuffixed); + + pub fn byte_string(s: &[u8]) -> Self { + Self { inner: format!("b\"{}\"", core::str::from_utf8(s).expect("Could not turn bytes into byte literal")) } + } + + pub fn as_str(&self) -> &str { + &self.inner + } +} + +impl core::fmt::Display for TokenStream { + fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { + write!(f, "{}", self.as_str()) + } +} diff --git a/vendor/windows-bindgen/src/tree.rs b/vendor/windows-bindgen/src/tree.rs new file mode 100644 index 000000000..474d2a271 --- /dev/null +++ b/vendor/windows-bindgen/src/tree.rs @@ -0,0 +1,36 @@ +use super::*; + +#[derive(Debug)] +pub struct Tree<'a> { + pub namespace: &'a str, + pub nested: std::collections::BTreeMap<&'a str, Tree<'a>>, +} + +impl<'a> Tree<'a> { + pub fn new(reader: &'a metadata::Reader, filter: &'a metadata::Filter) -> Self { + let mut tree = Tree::from_namespace(""); + for ns in reader.namespaces() { + if filter.includes_namespace(ns) { + tree.insert_namespace(ns, 0); + } + } + tree + } + + fn from_namespace(namespace: &'a str) -> Self { + Self { namespace, nested: std::collections::BTreeMap::new() } + } + fn insert_namespace(&mut self, namespace: &'a str, pos: usize) -> &mut Self { + if let Some(next) = namespace[pos..].find('.') { + let next = pos + next; + self.nested.entry(&namespace[pos..next]).or_insert_with(|| Self::from_namespace(&namespace[..next])).insert_namespace(namespace, next + 1) + } else { + self.nested.entry(&namespace[pos..]).or_insert_with(|| Self::from_namespace(namespace)) + } + } + pub fn flatten(&self) -> Vec<&Self> { + let mut flatten = if self.namespace.is_empty() { vec![] } else { vec![self] }; + flatten.extend(self.nested.values().flat_map(|tree| tree.flatten())); + flatten + } +} diff --git a/vendor/windows-bindgen/src/try_format.rs b/vendor/windows-bindgen/src/try_format.rs deleted file mode 100644 index 493a8a842..000000000 --- a/vendor/windows-bindgen/src/try_format.rs +++ /dev/null @@ -1,31 +0,0 @@ -pub fn try_format(tokens: String) -> String { - use std::io::Write; - - let Ok(mut child) = std::process::Command::new("rustfmt").stdin(std::process::Stdio::piped()).stdout(std::process::Stdio::piped()).stderr(std::process::Stdio::null()).spawn() else { - return tokens; - }; - - let Some(mut stdin) = child.stdin.take() else { - return tokens; - }; - - if stdin.write_all(tokens.as_bytes()).is_err() { - return tokens; - } - - drop(stdin); - - let Ok(output) = child.wait_with_output() else { - return tokens; - }; - - if !output.status.success() { - return tokens; - } - - if let Ok(result) = String::from_utf8(output.stdout) { - result - } else { - tokens - } -} diff --git a/vendor/windows-bindgen/src/winmd/from_reader.rs b/vendor/windows-bindgen/src/winmd/from_reader.rs new file mode 100644 index 000000000..b535caed0 --- /dev/null +++ b/vendor/windows-bindgen/src/winmd/from_reader.rs @@ -0,0 +1,141 @@ +use super::*; +use crate::winmd::{self, writer}; +use metadata::RowReader; + +pub fn from_reader(reader: &metadata::Reader, filter: &metadata::Filter, config: std::collections::BTreeMap<&str, &str>, output: &str) -> crate::Result<()> { + let mut writer = winmd::Writer::new(output); + + // TODO: do we need any configuration values for winmd generation? + // Maybe per-namespace winmd files for namespace-splitting - be sure to use + // the same key as for winmd generation. + + if let Some((key, _)) = config.first_key_value() { + return Err(crate::Error::new(&format!("invalid configuration value `{key}`"))); + } + + // TODO: just use the reader directly since we now have everything in the reader, there's no need to abstract + // away the source format. Few reprs is always better. + + for item in reader.items(filter) { + // TODO: cover all variants + let metadata::Item::Type(def) = item else { + continue; + }; + + let generics = &metadata::type_def_generics(reader, def); + + let extends = if let Some(extends) = reader.type_def_extends(def) { writer.insert_type_ref(extends.namespace, extends.name) } else { 0 }; + + writer.tables.TypeDef.push(writer::TypeDef { + Extends: extends, + FieldList: writer.tables.Field.len() as u32, + Flags: reader.type_def_flags(def).0, + MethodList: writer.tables.MethodDef.len() as u32, + TypeName: writer.strings.insert(reader.type_def_name(def)), + TypeNamespace: writer.strings.insert(reader.type_def_namespace(def)), + }); + + for generic in reader.type_def_generics(def) { + writer.tables.GenericParam.push(writer::GenericParam { + Number: reader.generic_param_number(generic), + Flags: 0, + Owner: writer::TypeOrMethodDef::TypeDef(writer.tables.TypeDef.len() as u32 - 1).encode(), + Name: writer.strings.insert(reader.generic_param_name(generic)), + }); + } + + for imp in reader.type_def_interface_impls(def) { + let ty = reader.interface_impl_type(imp, generics); + let ty = winmd_type(reader, &ty); + + let reference = match &ty { + winmd::Type::TypeRef(type_name) if type_name.generics.is_empty() => writer.insert_type_ref(&type_name.namespace, &type_name.name), + winmd::Type::TypeRef(_) => writer.insert_type_spec(ty), + winmd::Type::IUnknown => writer.insert_type_ref("Windows.Win32.System.Com", "IUnknown"), + winmd::Type::IInspectable => writer.insert_type_ref("Windows.Win32.System.WinRT", "IInspectable"), + rest => unimplemented!("{rest:?}"), + }; + + writer.tables.InterfaceImpl.push(writer::InterfaceImpl { Class: writer.tables.TypeDef.len() as u32 - 1, Interface: reference }); + } + + // TODO: if the class is "Apis" then should we sort the fields (constants) and methods (functions) for stability + + for field in reader.type_def_fields(def) { + let ty = winmd_type(reader, &reader.field_type(field, Some(def))); + let signature = writer.insert_field_sig(&ty); + + writer.tables.Field.push(writer::Field { Flags: reader.field_flags(field).0, Name: writer.strings.insert(reader.field_name(field)), Signature: signature }); + } + + for method in reader.type_def_methods(def) { + let signature = reader.method_def_signature(method, generics); + let return_type = winmd_type(reader, &signature.return_type); + let param_types: Vec<Type> = signature.params.iter().map(|param| winmd_type(reader, param)).collect(); + + let signature = writer.insert_method_sig(signature.call_flags, &return_type, ¶m_types); + + writer.tables.MethodDef.push(winmd::MethodDef { + RVA: 0, + ImplFlags: reader.method_def_impl_flags(method).0, + Flags: reader.method_def_flags(method).0, + Name: writer.strings.insert(reader.method_def_name(method)), + Signature: signature, + ParamList: writer.tables.Param.len() as u32, + }); + + for param in reader.method_def_params(method) { + writer.tables.Param.push(writer::Param { Flags: reader.param_flags(param).0, Sequence: reader.param_sequence(param), Name: writer.strings.insert(reader.param_name(param)) }); + } + } + } + + // TODO: In theory, `config` could instruct this function to balance the types across a number of winmd files + // like mdmerge supports for namespace-splitting. + crate::write_to_file(output, writer.into_stream()).map_err(|err| err.with_path(output)) +} + +// TODO: keep the basic type conversion +fn winmd_type(reader: &metadata::Reader, ty: &metadata::Type) -> winmd::Type { + match ty { + metadata::Type::Void => winmd::Type::Void, + metadata::Type::Bool => winmd::Type::Bool, + metadata::Type::Char => winmd::Type::Char, + metadata::Type::I8 => winmd::Type::I8, + metadata::Type::U8 => winmd::Type::U8, + metadata::Type::I16 => winmd::Type::I16, + metadata::Type::U16 => winmd::Type::U16, + metadata::Type::I32 => winmd::Type::I32, + metadata::Type::U32 => winmd::Type::U32, + metadata::Type::I64 => winmd::Type::I64, + metadata::Type::U64 => winmd::Type::U64, + metadata::Type::F32 => winmd::Type::F32, + metadata::Type::F64 => winmd::Type::F64, + metadata::Type::ISize => winmd::Type::ISize, + metadata::Type::USize => winmd::Type::USize, + metadata::Type::String => winmd::Type::String, + metadata::Type::GUID => winmd::Type::GUID, + metadata::Type::IUnknown => winmd::Type::IUnknown, + metadata::Type::IInspectable => winmd::Type::IInspectable, + metadata::Type::HRESULT => winmd::Type::HRESULT, + metadata::Type::PSTR => winmd::Type::PSTR, + metadata::Type::PWSTR => winmd::Type::PWSTR, + metadata::Type::PCSTR => winmd::Type::PCSTR, + metadata::Type::PCWSTR => winmd::Type::PCWSTR, + metadata::Type::BSTR => winmd::Type::BSTR, + metadata::Type::TypeName => winmd::Type::TypeName, + metadata::Type::TypeDef(def, generics) => winmd::Type::TypeRef(winmd::TypeName { + namespace: reader.type_def_namespace(*def).to_string(), + name: reader.type_def_name(*def).to_string(), + generics: generics.iter().map(|ty| winmd_type(reader, ty)).collect(), + }), + metadata::Type::GenericParam(generic) => winmd::Type::GenericParam(reader.generic_param_number(*generic)), + metadata::Type::ConstRef(ty) => winmd::Type::ConstRef(Box::new(winmd_type(reader, ty))), + metadata::Type::WinrtArrayRef(ty) => winmd::Type::WinrtArrayRef(Box::new(winmd_type(reader, ty))), + metadata::Type::WinrtArray(ty) => winmd::Type::WinrtArray(Box::new(winmd_type(reader, ty))), + metadata::Type::MutPtr(ty, pointers) => winmd::Type::MutPtr(Box::new(winmd_type(reader, ty)), *pointers), + metadata::Type::ConstPtr(ty, pointers) => winmd::Type::ConstPtr(Box::new(winmd_type(reader, ty)), *pointers), + metadata::Type::Win32Array(ty, len) => winmd::Type::Win32Array(Box::new(winmd_type(reader, ty)), *len), + rest => unimplemented!("{rest:?}"), + } +} diff --git a/vendor/windows-bindgen/src/winmd/mod.rs b/vendor/windows-bindgen/src/winmd/mod.rs new file mode 100644 index 000000000..f01afa218 --- /dev/null +++ b/vendor/windows-bindgen/src/winmd/mod.rs @@ -0,0 +1,7 @@ +mod from_reader; +mod verify; +pub mod writer; +use super::*; +pub use from_reader::from_reader; +pub use verify::verify; +pub use writer::*; diff --git a/vendor/windows-bindgen/src/winmd/verify.rs b/vendor/windows-bindgen/src/winmd/verify.rs new file mode 100644 index 000000000..f10bd6524 --- /dev/null +++ b/vendor/windows-bindgen/src/winmd/verify.rs @@ -0,0 +1,31 @@ +use super::*; +use metadata::RowReader; + +pub fn verify(reader: &metadata::Reader, filter: &metadata::Filter) -> crate::Result<()> { + for item in reader.items(filter) { + // TODO: cover all variants + let metadata::Item::Type(def) = item else { + continue; + }; + + let generics = &metadata::type_def_generics(reader, def); + + reader.type_def_fields(def).try_for_each(|field| not_type_ref(reader, &reader.field_type(field, Some(def))))?; + + reader.type_def_methods(def).try_for_each(|method| { + let sig = reader.method_def_signature(method, generics); + not_type_ref(reader, &sig.return_type)?; + + sig.params.iter().try_for_each(|param| not_type_ref(reader, param)) + })?; + } + + Ok(()) +} + +fn not_type_ref(reader: &metadata::Reader, ty: &metadata::Type) -> crate::Result<()> { + if let metadata::Type::TypeRef(ty) = ty { + return Err(crate::Error::new(&format!("missing type definition `{}`", reader.type_def_or_ref(*ty)))); + } + Ok(()) +} diff --git a/vendor/windows-bindgen/src/winmd/writer/blobs.rs b/vendor/windows-bindgen/src/winmd/writer/blobs.rs new file mode 100644 index 000000000..5201a32d0 --- /dev/null +++ b/vendor/windows-bindgen/src/winmd/writer/blobs.rs @@ -0,0 +1,48 @@ +use super::*; +use std::collections::hash_map::*; + +pub struct Blobs { + map: HashMap<Vec<u8>, u32>, + stream: Vec<u8>, +} + +impl Default for Blobs { + fn default() -> Self { + Self { map: Default::default(), stream: vec![0] } + } +} + +impl Blobs { + pub fn insert(&mut self, value: &[u8]) -> u32 { + if value.is_empty() { + return 0; + } + + match self.map.entry(value.to_vec()) { + Entry::Vacant(entry) => { + let offset = *entry.insert(self.stream.len() as u32); + let len = value.len(); + match len { + 0..=0x7F => self.stream.push(len as u8), + 0x80..=0x3FFF => { + self.stream.push((0x80 | len >> 8) as u8); + self.stream.push((0xFF & len) as u8); + } + _ => { + self.stream.push((0xC0 | len >> 24) as u8); + self.stream.push((0xFF & len >> 16) as u8); + self.stream.push((0xFF & len >> 8) as u8); + self.stream.push((0xFF & len) as u8); + } + } + self.stream.extend_from_slice(value); + offset + } + Entry::Occupied(entry) => *entry.get(), + } + } + + pub fn into_stream(self) -> Vec<u8> { + self.stream.into_stream() + } +} diff --git a/vendor/windows-bindgen/src/winmd/writer/codes.rs b/vendor/windows-bindgen/src/winmd/writer/codes.rs new file mode 100644 index 000000000..c5aa789e0 --- /dev/null +++ b/vendor/windows-bindgen/src/winmd/writer/codes.rs @@ -0,0 +1,71 @@ +#![allow(dead_code, clippy::enum_variant_names)] + +/// A `ResolutionScope` is an index into a certain table indicating the scope in which a TypeRef can be resolved. +#[derive(Clone)] +pub enum ResolutionScope { + Module(u32), + ModuleRef(u32), + AssemblyRef(u32), + TypeRef(u32), +} + +impl ResolutionScope { + pub fn encode(&self) -> u32 { + match self { + Self::Module(row) => (row + 1) << 2, + Self::ModuleRef(row) => ((row + 1) << 2) + 1, + Self::AssemblyRef(row) => ((row + 1) << 2) + 2, + Self::TypeRef(row) => ((row + 1) << 2) + 3, + } + } +} + +/// A `TypeDefOrRef` is an index into a certain table used to locate a type definition. +#[derive(Clone)] +pub enum TypeDefOrRef { + TypeDef(u32), + TypeRef(u32), + TypeSpec(u32), +} + +impl TypeDefOrRef { + pub fn encode(&self) -> u32 { + match self { + Self::TypeDef(row) => (row + 1) << 2, + Self::TypeRef(row) => ((row + 1) << 2) + 1, + Self::TypeSpec(row) => ((row + 1) << 2) + 2, + } + } +} + +/// A `HasConstant` is an index into a certain table used to identify the parent of a row in the `Constant` table. +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)] +pub enum HasConstant { + Field(u32), + Param(u32), + Property(u32), +} + +impl HasConstant { + pub fn encode(&self) -> u32 { + match self { + Self::Field(row) => (row + 1) << 2, + Self::Param(row) => ((row + 1) << 2) + 1, + Self::Property(row) => ((row + 1) << 2) + 2, + } + } +} + +/// A `TypeOrMethodDef` is an index into a certain table used to locate the owner of a generic parameter. +#[derive(Clone)] +pub enum TypeOrMethodDef { + TypeDef(u32), +} + +impl TypeOrMethodDef { + pub fn encode(&self) -> u32 { + match self { + Self::TypeDef(row) => (row + 1) << 1, + } + } +} diff --git a/vendor/windows-bindgen/src/winmd/writer/file.rs b/vendor/windows-bindgen/src/winmd/writer/file.rs new file mode 100644 index 000000000..b452ba559 --- /dev/null +++ b/vendor/windows-bindgen/src/winmd/writer/file.rs @@ -0,0 +1,134 @@ +use super::*; +use metadata::imp::*; +use std::mem::*; + +pub fn write(mut tables: Vec<u8>, mut strings: Vec<u8>, mut blobs: Vec<u8>) -> Vec<u8> { + if [tables.len(), strings.len(), blobs.len()].iter().any(|len| *len > u32::MAX as usize) { + panic!("heap too large"); + } + + unsafe { + let mut guids = vec![0; 16]; // zero guid + let size_of_streams = tables.len() + guids.len() + strings.len() + blobs.len(); + + let mut dos: IMAGE_DOS_HEADER = zeroed(); + dos.e_magic = IMAGE_DOS_SIGNATURE; + dos.e_lfarlc = 64; + dos.e_lfanew = size_of::<IMAGE_DOS_HEADER>() as i32; + + let mut file: IMAGE_FILE_HEADER = zeroed(); + file.Machine = IMAGE_FILE_MACHINE_I386; + file.NumberOfSections = 1; + file.SizeOfOptionalHeader = size_of::<IMAGE_OPTIONAL_HEADER32>() as u16; + file.Characteristics = IMAGE_FILE_DLL | IMAGE_FILE_32BIT_MACHINE | IMAGE_FILE_EXECUTABLE_IMAGE; + + let mut optional: IMAGE_OPTIONAL_HEADER32 = zeroed(); + optional.Magic = IMAGE_NT_OPTIONAL_HDR32_MAGIC; + optional.MajorLinkerVersion = 11; + optional.SizeOfInitializedData = 1024; + optional.ImageBase = 0x400000; + optional.SectionAlignment = SECTION_ALIGNMENT; + optional.FileAlignment = 512; + optional.MajorOperatingSystemVersion = 6; + optional.MinorOperatingSystemVersion = 2; + optional.MajorSubsystemVersion = 6; + optional.MinorSubsystemVersion = 2; + optional.SizeOfHeaders = 512; + optional.Subsystem = IMAGE_SUBSYSTEM_WINDOWS_CUI; + optional.DllCharacteristics = IMAGE_DLLCHARACTERISTICS_NX_COMPAT | IMAGE_DLLCHARACTERISTICS_NO_SEH | IMAGE_DLLCHARACTERISTICS_DYNAMIC_BASE; + optional.SizeOfStackReserve = 0x100000; + optional.SizeOfHeapReserve = 4096; + optional.LoaderFlags = 0x100000; + optional.NumberOfRvaAndSizes = 16; + + let mut section: IMAGE_SECTION_HEADER = zeroed(); + section.Name = *b".text\0\0\0"; + section.Characteristics = 0x4000_0020; + section.VirtualAddress = SECTION_ALIGNMENT; + + let mut clr: IMAGE_COR20_HEADER = zeroed(); + clr.cb = size_of::<IMAGE_COR20_HEADER>() as u32; + clr.MajorRuntimeVersion = 2; + clr.MinorRuntimeVersion = 5; + clr.Flags = 1; + + let metadata = METADATA_HEADER { + signature: METADATA_SIGNATURE, + major_version: 1, + minor_version: 1, + length: 20, + version: *b"WindowsRuntime 1.4\0\0", + streams: 4, + ..Default::default() + }; + + type TablesHeader = StreamHeader<4>; + type StringsHeader = StreamHeader<12>; + type GuidsHeader = StreamHeader<8>; + type BlobsHeader = StreamHeader<8>; + + let size_of_stream_headers = size_of::<TablesHeader>() + size_of::<StringsHeader>() + size_of::<GuidsHeader>() + size_of::<BlobsHeader>(); + let size_of_image = optional.FileAlignment as usize + size_of::<IMAGE_COR20_HEADER>() + size_of::<METADATA_HEADER>() + size_of_stream_headers + size_of_streams; + + optional.SizeOfImage = round(size_of_image, optional.SectionAlignment as usize) as u32; + section.Misc.VirtualSize = size_of_image as u32 - optional.FileAlignment; + section.SizeOfRawData = round(section.Misc.VirtualSize as usize, optional.FileAlignment as usize) as u32; + + optional.DataDirectory[14] = IMAGE_DATA_DIRECTORY { VirtualAddress: SECTION_ALIGNMENT, Size: size_of::<IMAGE_COR20_HEADER>() as u32 }; + section.PointerToRawData = optional.FileAlignment; + clr.MetaData.VirtualAddress = SECTION_ALIGNMENT + size_of::<IMAGE_COR20_HEADER>() as u32; + clr.MetaData.Size = section.Misc.VirtualSize - size_of::<IMAGE_COR20_HEADER>() as u32; + + let mut buffer = Vec::<u8>::new(); + + buffer.write_header(&dos); + buffer.write_u32(IMAGE_NT_SIGNATURE); + buffer.write_header(&file); + buffer.write_header(&optional); + buffer.write_header(§ion); + debug_assert!(buffer.len() < optional.FileAlignment as usize); + buffer.resize(optional.FileAlignment as usize, 0); + buffer.write_header(&clr); + let metadata_offset = buffer.len(); + buffer.write_header(&metadata); + + let stream_offset = buffer.len() - metadata_offset + size_of_stream_headers; + let tables_header = TablesHeader::new(stream_offset as u32, tables.len() as u32, b"#~\0\0"); + let strings_header = StringsHeader::new(tables_header.next_offset(), strings.len() as u32, b"#Strings\0\0\0\0"); + let guids_header = GuidsHeader::new(strings_header.next_offset(), guids.len() as u32, b"#GUID\0\0\0"); + let blobs_header = BlobsHeader::new(guids_header.next_offset(), blobs.len() as u32, b"#Blob\0\0\0"); + + buffer.write_header(&tables_header); + buffer.write_header(&strings_header); + buffer.write_header(&guids_header); + buffer.write_header(&blobs_header); + + buffer.append(&mut tables); + buffer.append(&mut strings); + buffer.append(&mut guids); + buffer.append(&mut blobs); + + assert_eq!(clr.MetaData.Size as usize, buffer.len() - metadata_offset); + assert_eq!(size_of_image, buffer.len()); + + buffer + } +} + +const SECTION_ALIGNMENT: u32 = 4096; + +#[repr(C)] +struct StreamHeader<const LEN: usize> { + offset: u32, + size: u32, + name: [u8; LEN], +} + +impl<const LEN: usize> StreamHeader<LEN> { + fn new(offset: u32, size: u32, name: &[u8; LEN]) -> Self { + Self { offset, size, name: *name } + } + fn next_offset(&self) -> u32 { + self.offset + self.size + } +} diff --git a/vendor/windows-bindgen/src/winmd/writer/mod.rs b/vendor/windows-bindgen/src/winmd/writer/mod.rs new file mode 100644 index 000000000..af49ecfeb --- /dev/null +++ b/vendor/windows-bindgen/src/winmd/writer/mod.rs @@ -0,0 +1,329 @@ +mod blobs; +mod codes; +mod file; +mod strings; +mod tables; +mod traits; +mod r#type; + +use super::*; +use blobs::Blobs; +pub use codes::*; +use metadata::imp::*; +pub use r#type::*; +use std::collections::HashMap; +use strings::Strings; +pub use tables::*; +use traits::*; + +pub struct Writer { + pub blobs: Blobs, + pub strings: Strings, + pub tables: Tables, + pub scopes: HashMap<String, u32>, + // TODO: is this faster than jsut using a single HashMap with a (String,String) key? + pub type_refs: HashMap<String, HashMap<String, u32>>, + pub type_specs: HashMap<Type, u32>, +} + +impl Writer { + pub fn new(name: &str) -> Self { + let mut writer = Self { + blobs: Default::default(), + strings: Default::default(), + tables: Default::default(), + scopes: Default::default(), + type_refs: Default::default(), + type_specs: Default::default(), + }; + + writer.tables.TypeDef.push(TypeDef { TypeName: writer.strings.insert("<Module>"), ..Default::default() }); + + let name = name.rsplit_once(&['/', '\\']).map_or(name, |(_, name)| name); + + writer.tables.Module.push(Module { Name: writer.strings.insert(name), Mvid: 1, ..Default::default() }); + + let name = name.rsplit_once('.').map_or(name, |(_, name)| name); + + writer.tables.Assembly.push(Assembly { + Name: writer.strings.insert(name), + HashAlgId: 0x00008004, + MajorVersion: 0xFF, + MinorVersion: 0xFF, + BuildNumber: 0xFF, + RevisionNumber: 0xFF, + Flags: metadata::AssemblyFlags::WindowsRuntime.0, + ..Default::default() + }); + + // Some winmd parsers will fail to read without an `mscorlib` reference. The `insert_module_types` function will typically include it + // automatically but a minimal `Module` tree may not add this dependency. + writer.insert_scope("System"); + + writer + } + + pub fn into_stream(self) -> Vec<u8> { + file::write(self.tables.into_stream(), self.strings.into_stream(), self.blobs.into_stream()) + } + + pub fn insert_method_sig(&mut self, call_flags: metadata::MethodCallAttributes, return_type: &Type, param_types: &[Type]) -> u32 { + let mut blob = vec![call_flags.0]; + usize_blob(param_types.len(), &mut blob); + self.type_blob(return_type, &mut blob); + + for ty in param_types { + self.type_blob(ty, &mut blob); + } + + self.blobs.insert(&blob) + } + + pub fn insert_field_sig(&mut self, ty: &Type) -> u32 { + // TODO: can either cache in Writer, like we do for scopes and type_refs, or regenerate each time. + // Profile once we can stress test this with field/method signatures. + + let mut blob = vec![0x6]; // FIELD + self.type_blob(ty, &mut blob); + + self.blobs.insert(&blob) + } + + fn insert_scope(&mut self, namespace: &str) -> u32 { + if let Some(scope) = self.scopes.get(namespace) { + *scope + } else if namespace == "System" { + let scope = ResolutionScope::AssemblyRef(self.tables.AssemblyRef.push2(AssemblyRef { + Name: self.strings.insert("mscorlib"), + MajorVersion: 4, + PublicKeyOrToken: self.blobs.insert(&[0xB7, 0x7A, 0x5C, 0x56, 0x19, 0x34, 0xE0, 0x89]), // TODO: comment on this + ..Default::default() + })) + .encode(); + self.scopes.insert(namespace.to_string(), scope); + scope + } else { + // TODO: may need to capture the original assembly info for external type_refs. + let scope = ResolutionScope::AssemblyRef(self.tables.AssemblyRef.push2(AssemblyRef { + Name: self.strings.insert(namespace), + MajorVersion: 0xFF, + MinorVersion: 0xFF, + BuildNumber: 0xFF, + RevisionNumber: 0xFF, + Flags: metadata::AssemblyFlags::WindowsRuntime.0, + ..Default::default() + })) + .encode(); + self.scopes.insert(namespace.to_string(), scope); + scope + } + } + + pub fn insert_type_ref(&mut self, namespace: &str, name: &str) -> u32 { + if let Some(key) = self.type_refs.get(namespace) { + if let Some(reference) = key.get(name) { + return *reference; + } + } + + let scope = self.insert_scope(namespace); + + let reference = TypeDefOrRef::TypeRef(self.tables.TypeRef.push2(TypeRef { TypeName: self.strings.insert(name), TypeNamespace: self.strings.insert(namespace), ResolutionScope: scope })).encode(); + self.type_refs.entry(namespace.to_string()).or_default().insert(name.to_string(), reference); + reference + } + + pub fn insert_type_spec(&mut self, ty: Type) -> u32 { + if let Some(key) = self.type_specs.get(&ty) { + return *key; + } + + let mut blob = vec![]; + self.type_blob(&ty, &mut blob); + let signature = self.blobs.insert(&blob); + + let reference = TypeDefOrRef::TypeSpec(self.tables.TypeSpec.push2(TypeSpec { Signature: signature })).encode(); + + self.type_specs.insert(ty, reference); + reference + } + + fn type_blob(&mut self, ty: &Type, blob: &mut Vec<u8>) { + match ty { + Type::Void => blob.push(ELEMENT_TYPE_VOID), + Type::Bool => blob.push(ELEMENT_TYPE_BOOLEAN), + Type::Char => blob.push(ELEMENT_TYPE_CHAR), + Type::I8 => blob.push(ELEMENT_TYPE_I1), + Type::U8 => blob.push(ELEMENT_TYPE_U1), + Type::I16 => blob.push(ELEMENT_TYPE_I2), + Type::U16 => blob.push(ELEMENT_TYPE_U2), + Type::I32 => blob.push(ELEMENT_TYPE_I4), + Type::U32 => blob.push(ELEMENT_TYPE_U4), + Type::I64 => blob.push(ELEMENT_TYPE_I8), + Type::U64 => blob.push(ELEMENT_TYPE_U8), + Type::F32 => blob.push(ELEMENT_TYPE_R4), + Type::F64 => blob.push(ELEMENT_TYPE_R8), + Type::ISize => blob.push(ELEMENT_TYPE_I), + Type::USize => blob.push(ELEMENT_TYPE_U), + Type::String => blob.push(ELEMENT_TYPE_STRING), + Type::IInspectable => blob.push(ELEMENT_TYPE_OBJECT), + Type::GUID => { + let code = self.insert_type_ref("System", "Guid"); + blob.push(ELEMENT_TYPE_VALUETYPE); + usize_blob(code as usize, blob); + } + Type::HRESULT => { + let code = self.insert_type_ref("Windows.Foundation", "HResult"); + blob.push(ELEMENT_TYPE_VALUETYPE); + usize_blob(code as usize, blob); + } + Type::TypeRef(ty) => { + if !ty.generics.is_empty() { + blob.push(ELEMENT_TYPE_GENERICINST); + } + let code = self.insert_type_ref(&ty.namespace, &ty.name); + blob.push(ELEMENT_TYPE_VALUETYPE); + usize_blob(code as usize, blob); + + if !ty.generics.is_empty() { + usize_blob(ty.generics.len(), blob); + + for ty in &ty.generics { + self.type_blob(ty, blob); + } + } + } + Type::BSTR => { + let code = self.insert_type_ref("Windows.Win32.Foundation", "BSTR"); + blob.push(ELEMENT_TYPE_VALUETYPE); + usize_blob(code as usize, blob); + } + Type::IUnknown => { + let code = self.insert_type_ref("Windows.Win32.Foundation", "IUnknown"); + blob.push(ELEMENT_TYPE_VALUETYPE); + usize_blob(code as usize, blob); + } + Type::PCWSTR | Type::PWSTR => { + let code = self.insert_type_ref("Windows.Win32.Foundation", "PWSTR"); + blob.push(ELEMENT_TYPE_VALUETYPE); + usize_blob(code as usize, blob); + } + Type::PCSTR | Type::PSTR => { + let code = self.insert_type_ref("Windows.Win32.Foundation", "PSTR"); + blob.push(ELEMENT_TYPE_VALUETYPE); + usize_blob(code as usize, blob); + } + Type::ConstRef(ty) => { + usize_blob(ELEMENT_TYPE_CMOD_OPT as usize, blob); + usize_blob(self.insert_type_ref("System.Runtime.CompilerServices", "IsConst") as usize, blob); + usize_blob(ELEMENT_TYPE_BYREF as usize, blob); + self.type_blob(ty, blob); + } + Type::WinrtArrayRef(ty) => { + usize_blob(ELEMENT_TYPE_BYREF as usize, blob); + usize_blob(ELEMENT_TYPE_SZARRAY as usize, blob); + self.type_blob(ty, blob); + } + Type::WinrtArray(ty) => { + usize_blob(ELEMENT_TYPE_SZARRAY as usize, blob); + self.type_blob(ty, blob); + } + Type::Win32Array(ty, bounds) => { + usize_blob(ELEMENT_TYPE_ARRAY as usize, blob); + self.type_blob(ty, blob); + usize_blob(1, blob); // rank + usize_blob(1, blob); // count + usize_blob(*bounds, blob); + } + Type::TypeName => { + let code = self.insert_type_ref("System", "Type"); + blob.push(ELEMENT_TYPE_CLASS); + usize_blob(code as usize, blob); + } + Type::MutPtr(ty, pointers) | Type::ConstPtr(ty, pointers) => { + for _ in 0..*pointers { + usize_blob(ELEMENT_TYPE_PTR as usize, blob); + } + self.type_blob(ty, blob); + } + Type::GenericParam(index) => { + blob.push(ELEMENT_TYPE_VAR); + usize_blob(*index as usize, blob); + } + } + } +} + +fn round(size: usize, round: usize) -> usize { + let round = round - 1; + (size + round) & !round +} + +fn usize_blob(value: usize, blob: &mut Vec<u8>) { + // See II.23.2 in ECMA-335 + assert!(value < 0x20000000); + + if value < 0x80 { + blob.push(value as u8); + } else if value < 0x4000 { + blob.push((0x80 | (value & 0x3F00) >> 8) as u8); + blob.push((value & 0xFF) as u8); + } else { + blob.push((0xC0 | (value & 0x1F000000) >> 24) as u8); + blob.push(((value & 0xFF0000) >> 16) as u8); + blob.push(((value & 0xFF00) >> 8) as u8); + blob.push((value & 0xFF) as u8); + } +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_usize_blob() { + let mut blob = vec![]; + usize_blob(0, &mut blob); + usize_blob(1, &mut blob); + usize_blob(2, &mut blob); + + usize_blob(0x80 - 2, &mut blob); + usize_blob(0x80 - 1, &mut blob); + usize_blob(0x80, &mut blob); + usize_blob(0x80 + 1, &mut blob); + usize_blob(0x80 + 2, &mut blob); + + usize_blob(0x4000 - 2, &mut blob); + usize_blob(0x4000 - 1, &mut blob); + usize_blob(0x4000, &mut blob); + usize_blob(0x4000 + 1, &mut blob); + usize_blob(0x4000 + 2, &mut blob); + + usize_blob(0x20000000 - 3, &mut blob); + usize_blob(0x20000000 - 2, &mut blob); + usize_blob(0x20000000 - 1, &mut blob); + + let mut blob = metadata::Blob::new(0, &blob); + assert_eq!(blob.read_usize(), 0); + assert_eq!(blob.read_usize(), 1); + assert_eq!(blob.read_usize(), 2); + + assert_eq!(blob.read_usize(), 0x80 - 2); + assert_eq!(blob.read_usize(), 0x80 - 1); + assert_eq!(blob.read_usize(), 0x80); + assert_eq!(blob.read_usize(), 0x80 + 1); + assert_eq!(blob.read_usize(), 0x80 + 2); + + assert_eq!(blob.read_usize(), 0x4000 - 2); + assert_eq!(blob.read_usize(), 0x4000 - 1); + assert_eq!(blob.read_usize(), 0x4000); + assert_eq!(blob.read_usize(), 0x4000 + 1); + assert_eq!(blob.read_usize(), 0x4000 + 2); + + assert_eq!(blob.read_usize(), 0x20000000 - 3); + assert_eq!(blob.read_usize(), 0x20000000 - 2); + assert_eq!(blob.read_usize(), 0x20000000 - 1); + + assert_eq!(blob.slice.len(), 0); + } +} diff --git a/vendor/windows-bindgen/src/winmd/writer/strings.rs b/vendor/windows-bindgen/src/winmd/writer/strings.rs new file mode 100644 index 000000000..1eeae6d43 --- /dev/null +++ b/vendor/windows-bindgen/src/winmd/writer/strings.rs @@ -0,0 +1,35 @@ +use super::*; +use std::collections::hash_map::*; + +pub struct Strings { + map: HashMap<String, u32>, + stream: Vec<u8>, +} + +impl Default for Strings { + fn default() -> Self { + Self { map: Default::default(), stream: vec![0] } + } +} + +impl Strings { + pub fn insert(&mut self, value: &str) -> u32 { + if value.is_empty() { + return 0; + } + + match self.map.entry(value.to_string()) { + Entry::Vacant(entry) => { + let offset = *entry.insert(self.stream.len() as u32); + self.stream.extend_from_slice(value.as_bytes()); + self.stream.push(0); + offset + } + Entry::Occupied(entry) => *entry.get(), + } + } + + pub fn into_stream(self) -> Vec<u8> { + self.stream.into_stream() + } +} diff --git a/vendor/windows-bindgen/src/winmd/writer/tables.rs b/vendor/windows-bindgen/src/winmd/writer/tables.rs new file mode 100644 index 000000000..4d4b8e354 --- /dev/null +++ b/vendor/windows-bindgen/src/winmd/writer/tables.rs @@ -0,0 +1,361 @@ +#![allow(non_snake_case)] + +use super::Write; +use super::*; +use metadata::imp::coded_index_size; + +#[derive(Default)] +pub struct Tables { + // TODO: use BTreeSet for tables that have a primary key, unless they are naturally sorted. + pub Assembly: Vec<Assembly>, + pub AssemblyRef: Vec<AssemblyRef>, + pub ClassLayout: Vec<ClassLayout>, + pub Constant: Vec<Constant>, + pub CustomAttribute: Vec<CustomAttribute>, + pub Field: Vec<Field>, + pub GenericParam: Vec<GenericParam>, + pub ImplMap: Vec<ImplMap>, + pub InterfaceImpl: Vec<InterfaceImpl>, + pub MemberRef: Vec<MemberRef>, + pub MethodDef: Vec<MethodDef>, + pub Module: Vec<Module>, + pub ModuleRef: Vec<ModuleRef>, + pub NestedClass: Vec<NestedClass>, + pub Param: Vec<Param>, + pub Property: Vec<Property>, + pub TypeDef: Vec<TypeDef>, + pub TypeRef: Vec<TypeRef>, + pub TypeSpec: Vec<TypeSpec>, +} + +#[derive(Default)] +pub struct Assembly { + pub HashAlgId: u32, + pub MajorVersion: u16, + pub MinorVersion: u16, + pub BuildNumber: u16, + pub RevisionNumber: u16, + pub Flags: u32, + pub PublicKey: u32, + pub Name: u32, + pub Culture: u32, +} + +#[derive(Default)] +pub struct AssemblyRef { + pub MajorVersion: u16, + pub MinorVersion: u16, + pub BuildNumber: u16, + pub RevisionNumber: u16, + pub Flags: u32, + pub PublicKeyOrToken: u32, + pub Name: u32, + pub Culture: u32, + pub HashValue: u32, +} + +#[derive(Default)] +pub struct ClassLayout { + pub PackingSize: u16, + pub ClassSize: u32, + pub Parent: u32, +} + +#[derive(Default)] +pub struct Constant { + pub Type: u16, + pub Parent: u32, + pub Value: u32, +} + +#[derive(Default)] +pub struct CustomAttribute { + pub Parent: u32, + pub Type: u32, + pub Value: u32, +} + +#[derive(Default)] +pub struct Field { + pub Flags: u16, + pub Name: u32, + pub Signature: u32, +} + +#[derive(Default)] +pub struct GenericParam { + pub Number: u16, + pub Flags: u16, + pub Owner: u32, + pub Name: u32, +} + +#[derive(Default)] +pub struct ImplMap { + pub MappingFlags: u16, + pub MemberForwarded: u32, + pub ImportName: u32, + pub ImportScope: u32, +} + +#[derive(Default)] +pub struct InterfaceImpl { + pub Class: u32, + pub Interface: u32, +} + +#[derive(Default)] +pub struct MemberRef { + pub Class: u32, + pub Name: u32, + pub Signature: u32, +} + +#[derive(Default)] +pub struct MethodDef { + pub RVA: u32, + pub ImplFlags: u16, + pub Flags: u16, + pub Name: u32, + pub Signature: u32, + pub ParamList: u32, +} + +#[derive(Default)] +pub struct Module { + pub Generation: u16, + pub Name: u32, + pub Mvid: u32, + pub EncId: u32, + pub EncBaseId: u32, +} + +#[derive(Default)] +pub struct ModuleRef { + pub Name: u32, +} + +#[derive(Default)] +pub struct NestedClass { + pub NestedClass: u32, + pub EnclosingClass: u32, +} + +#[derive(Default)] +pub struct Param { + pub Flags: u16, + pub Sequence: u16, + pub Name: u32, +} + +#[derive(Default)] +pub struct Property { + pub Flags: u16, + pub Name: u32, + pub Type: u32, +} + +#[derive(Default)] +pub struct TypeDef { + pub Flags: u32, + pub TypeName: u32, + pub TypeNamespace: u32, + pub Extends: u32, + pub FieldList: u32, + pub MethodList: u32, +} + +#[derive(Default)] +pub struct TypeRef { + pub ResolutionScope: u32, + pub TypeName: u32, + pub TypeNamespace: u32, +} + +#[derive(Default)] +pub struct TypeSpec { + pub Signature: u32, +} + +impl Tables { + pub fn into_stream(self) -> Vec<u8> { + if [self.AssemblyRef.len(), self.ClassLayout.len(), self.Constant.len(), self.CustomAttribute.len(), self.Field.len(), self.GenericParam.len(), self.ImplMap.len(), self.InterfaceImpl.len(), self.MemberRef.len(), self.MethodDef.len(), self.Module.len(), self.ModuleRef.len(), self.NestedClass.len(), self.Param.len(), self.Property.len(), self.TypeDef.len(), self.TypeRef.len(), self.TypeSpec.len()].iter().any(|len| *len > u32::MAX as usize) { + panic!("metadata table too large"); + } + + let resolution_scope = coded_index_size(&[self.Module.len(), self.ModuleRef.len(), self.AssemblyRef.len(), self.TypeRef.len()]); + + let type_def_or_ref = coded_index_size(&[self.TypeDef.len(), self.TypeRef.len(), self.TypeSpec.len()]); + + let has_constant = coded_index_size(&[self.Field.len(), self.Param.len(), self.Property.len()]); + + let type_or_method_def = coded_index_size(&[self.TypeDef.len(), self.MethodDef.len()]); + + let valid_tables: u64 = 1 << 0 | // Module + 1 << 0x01 | // TypeRef + 1 << 0x02 | // TypeDef + 1 << 0x04 | // Field + 1 << 0x06 | // MethodDef + 1 << 0x08 | // Param + 1 << 0x09 | // InterfaceImpl + 1 << 0x0A | // MemberRef + 1 << 0x0B | // Constant + 1 << 0x0C | // CustomAttribute + 1 << 0x0F | // ClassLayout + 1 << 0x17 | // Property + 1 << 0x1A | // ModuleRef + 1 << 0x1B | // TypeSpec + 1 << 0x1C | // ImplMap + 1 << 0x20 | // Assembly + 1 << 0x23 | // AssemblyRef + 1 << 0x29 | // NestedClass + 1 << 0x2A; // GenericParam + + // The table stream header... + + let mut buffer = Vec::new(); + buffer.write_u32(0); // Reserved + buffer.write_u8(2); // MajorVersion + buffer.write_u8(0); // MinorVersion + buffer.write_u8(0b111); // HeapSizes + buffer.write_u8(0); // Reserved + buffer.write_u64(valid_tables); + buffer.write_u64(0); // Sorted + + // Followed by the length of each of the valid tables... + + buffer.write_u32(self.Module.len() as u32); + buffer.write_u32(self.TypeRef.len() as u32); + buffer.write_u32(self.TypeDef.len() as u32); + buffer.write_u32(self.Field.len() as u32); + buffer.write_u32(self.MethodDef.len() as u32); + buffer.write_u32(self.Param.len() as u32); + buffer.write_u32(self.InterfaceImpl.len() as u32); + buffer.write_u32(self.MemberRef.len() as u32); + buffer.write_u32(self.Constant.len() as u32); + buffer.write_u32(self.CustomAttribute.len() as u32); + buffer.write_u32(self.ClassLayout.len() as u32); + buffer.write_u32(self.Property.len() as u32); + buffer.write_u32(self.ModuleRef.len() as u32); + buffer.write_u32(self.TypeSpec.len() as u32); + buffer.write_u32(self.ImplMap.len() as u32); + buffer.write_u32(self.Assembly.len() as u32); + buffer.write_u32(self.AssemblyRef.len() as u32); + buffer.write_u32(self.NestedClass.len() as u32); + buffer.write_u32(self.GenericParam.len() as u32); + + // Followed by each table's rows... + + for x in self.Module { + buffer.write_u16(x.Generation); + buffer.write_u32(x.Name); + buffer.write_u32(x.Mvid); + buffer.write_u32(x.EncId); + buffer.write_u32(x.EncBaseId); + } + + for x in self.TypeRef { + buffer.write_code(x.ResolutionScope, resolution_scope); + buffer.write_u32(x.TypeName); + buffer.write_u32(x.TypeNamespace); + } + + for x in &self.TypeDef { + buffer.write_u32(x.Flags); + buffer.write_u32(x.TypeName); + buffer.write_u32(x.TypeNamespace); + buffer.write_code(x.Extends, type_def_or_ref); + buffer.write_index(x.FieldList, self.Field.len()); + buffer.write_index(x.MethodList, self.MethodDef.len()); + } + + for x in self.Field { + buffer.write_u16(x.Flags); + buffer.write_u32(x.Name); + buffer.write_u32(x.Signature); + } + + for x in self.MethodDef { + buffer.write_u32(x.RVA); + buffer.write_u16(x.ImplFlags); + buffer.write_u16(x.Flags); + buffer.write_u32(x.Name); + buffer.write_u32(x.Signature); + buffer.write_index(x.ParamList, self.Param.len()); + } + + for x in self.Param { + buffer.write_u16(x.Flags); + buffer.write_u16(x.Sequence); + buffer.write_u32(x.Name); + } + + for x in self.InterfaceImpl { + buffer.write_index(x.Class, self.TypeDef.len()); + buffer.write_code(x.Interface, type_def_or_ref); + } + + for x in self.Constant { + buffer.write_u16(x.Type); + buffer.write_code(x.Parent, has_constant); + buffer.write_u32(x.Value); + } + + for x in self.TypeSpec { + buffer.write_u32(x.Signature); + } + + for x in self.Assembly { + buffer.write_u32(x.HashAlgId); + buffer.write_u16(x.MajorVersion); + buffer.write_u16(x.MinorVersion); + buffer.write_u16(x.BuildNumber); + buffer.write_u16(x.RevisionNumber); + buffer.write_u32(x.Flags); + buffer.write_u32(x.PublicKey); + buffer.write_u32(x.Name); + buffer.write_u32(x.Culture); + } + + for x in self.AssemblyRef { + buffer.write_u16(x.MajorVersion); + buffer.write_u16(x.MinorVersion); + buffer.write_u16(x.BuildNumber); + buffer.write_u16(x.RevisionNumber); + buffer.write_u32(x.Flags); + buffer.write_u32(x.PublicKeyOrToken); + buffer.write_u32(x.Name); + buffer.write_u32(x.Culture); + buffer.write_u32(x.HashValue); + } + + for x in self.GenericParam { + buffer.write_u16(x.Number); + buffer.write_u16(x.Flags); + buffer.write_code(x.Owner, type_or_method_def); + buffer.write_u32(x.Name); + } + + // TODO: sort GenericParam table prior to writing. This needs to be done for all tables with a primary index. See II.22 + + // TODO: do these get naturally sorted by virtue of how they're pushed into "tables" in type def order? + + // Table Primary Key Column + // ClassLayout Parent + // Constant Parent + // CustomAttribute Parent + // DeclSecurity Parent + // FieldLayout Field + // FieldMarshal Parent + // FieldRVA Field + // GenericParam Owner + // GenericParamConstraint Owner + // ImplMap MemberForwarded + // InterfaceImpl Class + // MethodImpl Class + // MethodSemantics Association + // NestedClass NestedClass + + buffer.into_stream() + } +} diff --git a/vendor/windows-bindgen/src/winmd/writer/traits.rs b/vendor/windows-bindgen/src/winmd/writer/traits.rs new file mode 100644 index 000000000..45304899a --- /dev/null +++ b/vendor/windows-bindgen/src/winmd/writer/traits.rs @@ -0,0 +1,66 @@ +use super::*; + +pub trait Write { + unsafe fn write_header<T: Sized>(&mut self, value: &T); + fn write_u8(&mut self, value: u8); + fn write_u16(&mut self, value: u16); + fn write_u32(&mut self, value: u32); + fn write_u64(&mut self, value: u64); + fn write_code(&mut self, value: u32, size: usize); + fn write_index(&mut self, index: u32, len: usize); + fn into_stream(self) -> Self; +} + +impl Write for Vec<u8> { + unsafe fn write_header<T: Sized>(&mut self, value: &T) { + self.extend_from_slice(std::slice::from_raw_parts(value as *const _ as _, std::mem::size_of::<T>())); + } + + fn write_u8(&mut self, value: u8) { + self.extend_from_slice(&value.to_le_bytes()); + } + + fn write_u16(&mut self, value: u16) { + self.extend_from_slice(&value.to_le_bytes()); + } + + fn write_u32(&mut self, value: u32) { + self.extend_from_slice(&value.to_le_bytes()); + } + + fn write_u64(&mut self, value: u64) { + self.extend_from_slice(&value.to_le_bytes()); + } + + fn write_code(&mut self, value: u32, size: usize) { + if size == 2 { + self.write_u16(value as u16); + } else { + self.write_u32(value); + } + } + + fn write_index(&mut self, index: u32, len: usize) { + if len < (1 << 16) { + self.write_u16(index as u16 + 1); + } else { + self.write_u32(index + 1); + } + } + + fn into_stream(mut self) -> Self { + self.resize(round(self.len(), 4), 0); + self + } +} + +pub trait Push2<T> { + fn push2(&mut self, value: T) -> u32; +} + +impl<T> Push2<T> for Vec<T> { + fn push2(&mut self, value: T) -> u32 { + self.push(value); + (self.len() - 1) as u32 + } +} diff --git a/vendor/windows-bindgen/src/winmd/writer/type.rs b/vendor/windows-bindgen/src/winmd/writer/type.rs new file mode 100644 index 000000000..3f0178654 --- /dev/null +++ b/vendor/windows-bindgen/src/winmd/writer/type.rs @@ -0,0 +1,80 @@ +#![allow(dead_code, clippy::upper_case_acronyms)] + +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +pub struct TypeName { + pub namespace: String, + pub name: String, + pub generics: Vec<Type>, +} + +#[derive(Clone, Debug, Hash, PartialEq, Eq)] +pub enum Type { + Void, + Bool, + Char, + I8, + U8, + I16, + U16, + I32, + U32, + I64, + U64, + F32, + F64, + ISize, + USize, + String, + GUID, + IUnknown, + IInspectable, + HRESULT, + PSTR, + PWSTR, + PCSTR, + PCWSTR, + BSTR, + TypeName, + TypeRef(TypeName), + GenericParam(u16), + MutPtr(Box<Self>, usize), + ConstPtr(Box<Self>, usize), + Win32Array(Box<Self>, usize), + WinrtArray(Box<Self>), + WinrtArrayRef(Box<Self>), + ConstRef(Box<Self>), +} + +impl Type { + pub fn into_mut_ptr(self) -> Self { + match self { + Self::MutPtr(ty, count) => Self::MutPtr(ty, count + 1), + Self::ConstPtr(ty, count) => Self::MutPtr(ty, count + 1), + _ => Self::MutPtr(Box::new(self), 1), + } + } + + pub fn into_const_ptr(self) -> Self { + match self { + Self::MutPtr(ty, count) => Self::ConstPtr(ty, count + 1), + Self::ConstPtr(ty, count) => Self::ConstPtr(ty, count + 1), + _ => Self::ConstPtr(Box::new(self), 1), + } + } + + pub fn into_array(self, len: usize) -> Self { + Self::Win32Array(Box::new(self), len) + } +} + +pub struct Signature { + pub params: Vec<SignatureParam>, + pub return_type: Type, + pub call_flags: u8, +} + +// TODO: just Param? +pub struct SignatureParam { + pub name: String, + pub ty: Type, +} diff --git a/vendor/windows-bindgen/src/winrt_methods.rs b/vendor/windows-bindgen/src/winrt_methods.rs deleted file mode 100644 index 457f70c38..000000000 --- a/vendor/windows-bindgen/src/winrt_methods.rs +++ /dev/null @@ -1,258 +0,0 @@ -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) } - } -} |