4 pub reader
: &'a Reader
<'a
>,
5 pub namespace
: &'a
str,
15 pub fn new(reader
: &'a Reader
) -> Self {
32 pub fn type_def_name(&self, def
: TypeDef
, generics
: &[Type
]) -> TokenStream
{
33 self.type_def_name_imp(def
, generics
, "")
35 pub fn type_def_vtbl_name(&self, def
: TypeDef
, generics
: &[Type
]) -> TokenStream
{
36 self.type_def_name_imp(def
, generics
, "_Vtbl")
38 pub fn type_def_name_imp(&self, def
: TypeDef
, generics
: &[Type
], suffix
: &str) -> TokenStream
{
39 let type_name
= self.reader
.type_def_type_name(def
);
41 if type_name
.namespace
.is_empty() {
42 to_ident(&self.scoped_name(def
))
44 let mut namespace
= self.namespace(type_name
.namespace
);
45 let mut name
= to_ident(type_name
.name
);
46 name
.push_str(suffix
);
48 if generics
.is_empty() || self.sys
{
49 namespace
.combine(&name
);
52 let colon_separated
= if !namespace
.as_str().is_empty() {
58 let generics
= generics
.iter().map(|ty
| self.type_name(ty
));
59 quote
! { #namespace #name #colon_separated<#(#generics),*> }
68 pub fn type_default_name(&self, ty
: &Type
) -> TokenStream
{
69 if let Type
::WinrtArray(ty
) = ty
{
70 self.type_default_name(ty
)
72 let kind
= self.type_name(ty
);
75 quote
! { <#kind as ::windows::core::Type<#kind>>::Default }
76 } else if self.reader
.type_is_nullable(ty
) && !self.sys
{
77 quote
! { ::core::option::Option<#kind> }
84 pub(crate) fn type_name(&self, ty
: &Type
) -> TokenStream
{
86 Type
::Void
=> quote
! { ::core::ffi::c_void }
,
87 Type
::Bool
=> quote
! { bool }
,
88 Type
::Char
=> quote
! { u16 }
,
89 Type
::I8
=> quote
! { i8 }
,
90 Type
::U8
=> quote
! { u8 }
,
91 Type
::I16
=> quote
! { i16 }
,
92 Type
::U16
=> quote
! { u16 }
,
93 Type
::I32
=> quote
! { i32 }
,
94 Type
::U32
=> quote
! { u32 }
,
95 Type
::I64
=> quote
! { i64 }
,
96 Type
::U64
=> quote
! { u64 }
,
97 Type
::F32
=> quote
! { f32 }
,
98 Type
::F64
=> quote
! { f64 }
,
99 Type
::ISize
=> quote
! { isize }
,
100 Type
::USize
=> quote
! { usize }
,
102 let crate_name
= self.crate_name();
103 quote
! { #crate_name HSTRING }
106 let crate_name
= self.crate_name();
107 quote
! { #crate_name BSTR }
109 Type
::IInspectable
=> {
110 let crate_name
= self.crate_name();
111 quote
! { #crate_name IInspectable }
114 let crate_name
= self.crate_name();
115 quote
! { #crate_name GUID }
118 let crate_name
= self.crate_name();
119 quote
! { #crate_name IUnknown }
122 let crate_name
= self.crate_name();
123 quote
! { #crate_name HRESULT }
126 let crate_name
= self.crate_name();
127 quote
! { #crate_name PSTR }
130 let crate_name
= self.crate_name();
131 quote
! { #crate_name PWSTR }
134 let crate_name
= self.crate_name();
135 quote
! { #crate_name PCSTR }
138 let crate_name
= self.crate_name();
139 quote
! { #crate_name PCWSTR }
141 Type
::Win32Array((ty
, len
)) => {
142 let name
= self.type_default_name(ty
);
143 let len
= Literal
::usize_unsuffixed(*len
);
144 quote
! { [#name; #len] }
146 Type
::GenericParam(generic
) => self.reader
.generic_param_name(*generic
).into(),
147 Type
::TypeDef((def
, generics
)) => self.type_def_name(*def
, generics
),
148 Type
::MutPtr((ty
, pointers
)) => {
149 let pointers
= mut_ptrs(*pointers
);
150 let ty
= self.type_default_name(ty
);
151 quote
! { #pointers #ty }
153 Type
::ConstPtr((ty
, pointers
)) => {
154 let pointers
= const_ptrs(*pointers
);
155 let ty
= self.type_default_name(ty
);
156 quote
! { #pointers #ty }
158 Type
::WinrtArray(ty
) => self.type_name(ty
),
159 Type
::WinrtArrayRef(ty
) => self.type_name(ty
),
160 Type
::WinrtConstRef(ty
) => self.type_name(ty
),
161 _
=> unimplemented
!(),
164 pub fn type_vtbl_name(&self, ty
: &Type
) -> TokenStream
{
166 Type
::TypeDef((def
, generics
)) => self.type_def_vtbl_name(*def
, generics
),
167 _
=> unimplemented
!(),
170 pub fn type_abi_name(&self, ty
: &Type
) -> TokenStream
{
172 return self.type_default_name(ty
);
176 Type
::IUnknown
| Type
::IInspectable
=> {
177 quote
! { *mut ::core::ffi::c_void }
180 quote
! { ::std::mem::MaybeUninit<::windows::core::HSTRING> }
183 quote
! { ::std::mem::MaybeUninit<::windows::core::BSTR> }
185 Type
::Win32Array((kind
, len
)) => {
186 let name
= self.type_abi_name(kind
);
187 let len
= Literal
::usize_unsuffixed(*len
);
188 quote
! { [#name; #len] }
190 Type
::GenericParam(generic
) => {
191 let name
= to_ident(self.reader
.generic_param_name(*generic
));
192 quote
! { ::windows::core::AbiType<#name> }
194 Type
::TypeDef((def
, _
)) => match self.reader
.type_def_kind(*def
) {
195 TypeKind
::Enum
=> self.type_def_name(*def
, &[]),
196 TypeKind
::Struct
=> {
197 let tokens
= self.type_def_name(*def
, &[]);
198 if self.reader
.type_def_is_blittable(*def
) {
201 quote
! { ::std::mem::MaybeUninit<#tokens> }
204 TypeKind
::Delegate
=> {
207 .type_def_flags(*def
)
208 .contains(TypeAttributes
::WINRT
)
210 quote
! { *mut ::core::ffi::c_void }
212 self.type_def_name(*def
, &[])
215 _
=> quote
! { *mut ::core::ffi::c_void }
,
217 Type
::MutPtr((kind
, pointers
)) => {
218 let pointers_tokens
= gen_mut_ptrs(*pointers
);
219 let kind
= if *pointers
> 1 {
222 self.type_abi_name(kind
)
224 quote
! { #pointers_tokens #kind }
226 Type
::ConstPtr((kind
, pointers
)) => {
227 let pointers_tokens
= gen_const_ptrs(*pointers
);
228 let kind
= if *pointers
> 1 {
231 self.type_abi_name(kind
)
233 quote
! { #pointers_tokens #kind }
235 Type
::WinrtArray(kind
) => self.type_abi_name(kind
),
236 Type
::WinrtArrayRef(kind
) => self.type_abi_name(kind
),
237 _
=> self.type_name(ty
),
245 pub fn generic_phantoms(&self, generics
: &[Type
]) -> TokenStream
{
246 let mut tokens
= TokenStream
::new();
247 for generic
in generics
{
248 let generic
= self.type_name(generic
);
249 tokens
.combine("e
! { ::core::marker::PhantomData::<#generic>, }
);
253 pub fn generic_named_phantoms(&self, generics
: &[Type
]) -> Vec
<TokenStream
> {
257 let generic
= self.type_name(generic
);
258 quote
! { #generic: ::core::marker::PhantomData::<#generic>, }
262 pub fn generic_constraints(&self, generics
: &[Type
]) -> TokenStream
{
263 let mut tokens
= TokenStream
::new();
264 for generic
in generics
{
265 let generic
= self.type_name(generic
);
266 tokens
.combine("e
! { #generic: ::windows::core::RuntimeType + 'static, }
);
270 pub fn generic_names(&self, generics
: &[Type
]) -> TokenStream
{
271 let mut tokens
= TokenStream
::new();
272 for generic
in generics
{
273 let generic
= self.type_name(generic
);
274 tokens
.combine("e
! { #generic, }
);
278 /// The signature params which are generic (along with their relative index)
279 pub fn generic_params
<'b
>(
281 params
: &'b
[SignatureParam
],
282 ) -> impl Iterator
<Item
= (usize, &SignatureParam
)> + 'b
{
285 .filter(move |param
| self.reader
.signature_param_is_convertible(param
))
288 /// The generic param names (i.e., `T` in `fn foo<T>()`)
289 pub fn constraint_generics(&self, params
: &[SignatureParam
]) -> TokenStream
{
290 let mut generics
= self
291 .generic_params(params
)
292 .map(|(position
, _
)| -> TokenStream { format!("P{position}
").into() })
295 if generics.peek().is_some() {
296 quote!(#(#generics),*)
301 /// A `where` clause for some constrained generic params
302 pub fn where_clause(&self, params: &[SignatureParam]) -> TokenStream {
303 let constraints = self.param_constraints(params);
305 if !constraints.is_empty() {
306 quote!(where #constraints)
311 fn param_constraints(&self, params: &[SignatureParam]) -> TokenStream {
312 let mut tokens = TokenStream::new();
313 let gen_name = |position| {
314 let name: TokenStream = format!("P{position}
").into();
317 for (position, param) in self.generic_params(params) {
319 SignatureParamKind::TryInto => {
320 let name: TokenStream = gen_name(position);
321 let into = self.type_name(¶m.ty);
322 tokens.combine("e! { #name: ::windows::core::TryIntoParam<#into>, });
324 SignatureParamKind::IntoParam => {
325 let name: TokenStream = gen_name(position);
326 let into = self.type_name(¶m.ty);
327 tokens.combine("e! { #name: ::windows::core::IntoParam<#into>, });
339 /// Generates doc comments for types, free functions, and constants.
340 pub(crate) fn cfg_doc(&self, cfg: &Cfg) -> TokenStream {
344 let mut tokens = format!(r#"`
\"{}
\"`
"#, to_feature(self.namespace));
345 let features = self.cfg_features_imp(cfg, self.namespace);
347 for features in features {
348 write!(tokens, r#", `
\"{}
\"`
"#, to_feature(features)).unwrap();
352 tokens.push_str(r#", `
\"implement
\"`
"#)
355 format!(r#" #[doc = "*Required features: {tokens}*"]"#).into()
359 /// Generates doc comments for member functions (methods) and avoids redundantly declaring the
360 /// enclosing module feature required by the method's type.
361 pub(crate) fn cfg_method_doc(&self, cfg: &Cfg) -> TokenStream {
365 let features = self.cfg_features_imp(cfg, self.namespace);
366 if features.is_empty() {
369 let mut tokens = String::new();
370 for features in features {
371 write!(tokens, r#"`\"{}\"`, "#, to_feature(features)).unwrap();
373 tokens.truncate(tokens.len() - 2);
374 format!(r#"#[doc = "*Required features: {tokens}*"]"#).into()
379 pub(crate) fn cfg_features(&self, cfg: &Cfg) -> TokenStream {
380 let arches = &cfg.arches;
381 let arch = match arches.len() {
384 quote! { #[cfg(#(target_arch = #arches),*)] }
387 quote! { #[cfg(any(#(target_arch = #arches),*))] }
391 let features = self.cfg_features_imp(cfg, self.namespace);
393 let features = match features.len() {
396 let features = features.iter().cloned().map(to_feature);
397 quote! { #[cfg(#(feature = #features)*)] }
400 let features = features.iter().cloned().map(to_feature);
401 quote! { #[cfg(all( #(feature = #features),* ))] }
405 quote! { #arch #features }
408 fn cfg_features_imp(&self, cfg: &'a Cfg, namespace: &'a str) -> Vec<&'a str> {
409 let mut compact = Vec::<&'static str>::new();
410 if !self.standalone && !self.component {
411 for feature in cfg.types.keys() {
412 if !feature.is_empty() && !starts_with(namespace, feature) {
413 for pos in 0..compact.len() {
414 if starts_with(feature, unsafe { compact.get_unchecked(pos) }) {
419 compact.push(feature);
426 fn cfg_not_features(&self, cfg: &Cfg) -> TokenStream {
427 let features = self.cfg_features_imp(cfg, self.namespace);
428 if features.is_empty() {
431 match features.len() {
434 let features = features.iter().cloned().map(to_feature);
435 quote! { #[cfg(not(#(feature = #features)*))] }
438 let features = features.iter().cloned().map(to_feature);
439 quote! { #[cfg(not(all( #(feature = #features),* )))] }
449 pub(crate) fn namespace(&self, namespace: &str) -> TokenStream {
450 if self.standalone || namespace == self.namespace {
454 namespace.starts_with("Windows.") && !self.namespace.starts_with("Windows");
455 let mut relative = self.namespace.split('.').peekable();
456 let mut namespace = namespace.split('.').peekable();
458 while relative.peek() == namespace.peek() {
459 if relative.next().is_none() {
466 let mut tokens = TokenStream::new();
469 tokens.push_str("::windows::");
472 for _ in 0..relative.count() {
473 tokens.push_str("super::");
477 for namespace in namespace {
478 tokens.push_str(namespace);
479 tokens.push_str("::");
485 pub fn crate_name(&self) -> TokenStream {
489 "::windows_sys::core::".into()
491 "::windows::core::".into()
494 fn scoped_name(&self, def: TypeDef) -> String {
495 if let Some(enclosing_type) = self.reader.type_def_enclosing_type(def) {
496 for (index, nested_type) in self.reader.nested_types(enclosing_type).enumerate() {
497 if self.reader.type_def_name(nested_type) == self.reader.type_def_name(def) {
498 return format!("{}_{index}", &self.scoped_name(enclosing_type));
502 self.reader.type_def_name(def).to_string()
504 pub fn value(&self, value: &Value) -> TokenStream {
506 Value::Bool(value) => quote! { #value },
507 Value::U8(value) => quote! { #value },
508 Value::I8(value) => quote! { #value },
509 Value::U16(value) => quote! { #value },
510 Value::I16(value) => quote! { #value },
511 Value::U32(value) => quote! { #value },
512 Value::I32(value) => quote! { #value },
513 Value::U64(value) => quote! { #value },
514 Value::I64(value) => quote! { #value },
515 Value::F32(value) => quote! { #value },
516 Value::F64(value) => quote! { #value },
517 Value::String(value) => {
518 let mut tokens = "\"".to_string();
520 for u in value.chars() {
521 write!(tokens, "{}", u.escape_default()).unwrap();
527 _ => unimplemented!(),
530 pub fn typed_value(&self, value: &Value) -> TokenStream {
531 let literal = self.value(value);
533 Value::Bool(_) => quote! { bool = #literal },
534 Value::U8(_) => quote! { u8 = #literal },
535 Value::I8(_) => quote! { i8 = #literal },
536 Value::U16(_) => quote! { u16 = #literal },
537 Value::I16(_) => quote! { i16 = #literal },
538 Value::U32(_) => quote! { u32 = #literal },
539 Value::I32(_) => quote! { i32 = #literal },
540 Value::U64(_) => quote! { u64 = #literal },
541 Value::I64(_) => quote! { i64 = #literal },
542 Value::F32(_) => quote! { f32 = #literal },
543 Value::F64(_) => quote! { f64 = #literal },
544 Value::String(_) => {
545 quote! { &str = #literal }
547 _ => unimplemented!(),
551 pub fn guid(&self, value: &GUID) -> TokenStream {
552 let guid = self.type_name(&Type::GUID);
553 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()
555 pub fn interface_core_traits(
560 constraints: &TokenStream,
561 _phantoms: &TokenStream,
562 features: &TokenStream,
564 let name = trim_tick(self.reader.type_def_name(def));
567 impl<#constraints> ::core::cmp::PartialEq for #ident {
568 fn eq(&self, other: &Self) -> bool {
573 impl<#constraints> ::core::cmp::Eq for #ident {}
575 impl<#constraints> ::core::fmt::Debug for #ident {
576 fn fmt(&self, f: &mut ::core::fmt::Formatter<'_>) -> ::core::fmt::Result {
577 f.debug_tuple(#name).field(&self.0).finish()
586 constraints: &TokenStream,
587 features: &TokenStream,
589 if self.reader.type_def_is_agile(def) {
592 unsafe impl<#constraints> ::core::marker::Send for #ident {}
594 unsafe impl<#constraints> ::core::marker::Sync for #ident {}
605 constraints: &TokenStream,
606 _phantoms: &TokenStream,
607 features: &TokenStream,
609 let mut kind = self.reader.type_def_async_kind(def);
610 let mut async_generics = generics.to_vec();
612 if kind == AsyncKind::None {
613 for interface in self.reader.type_def_interfaces(def, generics) {
614 if let Type::TypeDef((interface_def, interface_generics)) = &interface.ty {
615 kind = self.reader.type_def_async_kind(*interface_def);
616 if kind != AsyncKind::None {
617 async_generics = interface_generics.to_vec();
624 if kind == AsyncKind::None {
627 let return_type = match kind {
628 AsyncKind::Operation | AsyncKind::OperationWithProgress => {
629 self.type_name(&async_generics[0])
634 let handler = match kind {
635 AsyncKind::Action => quote! { AsyncActionCompletedHandler },
636 AsyncKind::ActionWithProgress => quote! { AsyncActionWithProgressCompletedHandler },
637 AsyncKind::Operation => quote! { AsyncOperationCompletedHandler },
638 AsyncKind::OperationWithProgress => {
639 quote! { AsyncOperationWithProgressCompletedHandler }
641 _ => unimplemented!(),
644 let namespace = self.namespace("Windows.Foundation");
648 impl<#constraints> #ident {
649 pub fn get(&self) -> ::windows::core::Result<#return_type> {
650 if self.Status()? == #namespace AsyncStatus::Started {
651 let (_waiter, signaler) = ::windows::imp::Waiter::new()?;
652 self.SetCompleted(&#namespace #handler::new(move |_sender, _args| {
653 // Safe because the waiter will only be dropped after being signaled.
654 unsafe { signaler.signal(); }
662 impl<#constraints> ::std::future::Future for #ident {
663 type Output = ::windows::core::Result<#return_type>;
665 fn poll(self: ::std::pin::Pin<&mut Self>, context: &mut ::std::task::Context) -> ::std::task::Poll<Self::Output> {
666 if self.Status()? == #namespace AsyncStatus::Started {
667 let waker = context.waker().clone();
669 let _ = self.SetCompleted(&#namespace #handler::new(move |_sender, _args| {
674 ::std::task::Poll::Pending
676 ::std::task::Poll::Ready(self.GetResults())
683 pub fn interface_winrt_trait(
688 constraints: &TokenStream,
689 _phantoms: &TokenStream,
690 features: &TokenStream,
695 .contains(TypeAttributes::WINRT)
697 let type_signature = if self.reader.type_def_kind(def) == TypeKind::Class {
699 Literal::byte_string(self.reader.type_def_signature(def, generics).as_bytes());
700 quote! { ::windows::imp::ConstBuffer::from_slice(#type_signature) }
702 let signature = Literal::byte_string(
703 format!("{{{:#?}}}", self.reader.type_def_guid(def).unwrap()).as_bytes(),
706 if generics.is_empty() {
707 quote! { ::windows::imp::ConstBuffer::from_slice(#signature) }
709 let generics = generics.iter().enumerate().map(|(index, g)| {
710 let g = self.type_name(g);
711 let semi = if index != generics.len() - 1 {
720 .push_other(<#g as ::windows::core::RuntimeType>::SIGNATURE)
727 ::windows::imp::ConstBuffer::new()
728 .push_slice(b"pinterface(")
729 .push_slice(#signature)
740 impl<#constraints> ::windows::core::RuntimeType for #ident {
741 const SIGNATURE: ::windows::imp::ConstBuffer = #type_signature;
748 pub fn runtime_name_trait(
753 constraints: &TokenStream,
754 features: &TokenStream,
759 .contains(TypeAttributes::WINRT)
761 // TODO: this needs to use a ConstBuffer-like facility to accomodate generics
762 let runtime_name = format!("{}", self.reader.type_def_type_name(def));
766 impl<#constraints> ::windows::core::RuntimeName for #name {
767 const NAME: &'static str = #runtime_name;
773 impl ::windows::core::RuntimeName for #name {}
778 pub fn interface_trait(
783 constraints: &TokenStream,
784 features: &TokenStream,
785 has_unknown_base: bool,
787 if let Some(default) = self.reader.type_def_default_interface(def) {
788 let default_name = self.type_name(&default);
789 let vtbl = self.type_vtbl_name(&default);
792 impl<#constraints> ::core::clone::Clone for #ident {
793 fn clone(&self) -> Self {
798 unsafe impl ::windows::core::Interface for #ident {
802 unsafe impl ::windows::core::ComInterface for #ident {
803 const IID: ::windows::core::GUID = <#default_name as ::windows::core::ComInterface>::IID;
807 let vtbl = self.type_def_vtbl_name(def, generics);
808 let guid = if generics.is_empty() {
809 match self.reader.type_def_guid(def) {
810 Some(guid) => self.guid(&guid),
813 ::windows::core::GUID::zeroed()
819 ::windows::core::GUID::from_signature(<Self as ::windows::core::RuntimeType>::SIGNATURE)
823 let phantoms = self.generic_phantoms(generics);
825 let mut tokens = quote! {
827 unsafe impl<#constraints> ::windows::core::Interface for #ident {
831 impl<#constraints> ::core::clone::Clone for #ident {
832 fn clone(&self) -> Self {
833 Self(self.0.clone(), #phantoms)
838 if has_unknown_base {
839 tokens.combine("e! {
841 unsafe impl<#constraints> ::windows::core::ComInterface for #ident {
842 const IID: ::windows::core::GUID = #guid;
850 pub fn interface_vtbl(
854 _ident: &TokenStream,
855 constraints: &TokenStream,
856 features: &TokenStream,
858 let vtbl = self.type_def_vtbl_name(def, generics);
859 let mut methods = quote! {};
860 let mut method_names = MethodNames::new();
861 method_names.add_vtable_types(self, def);
862 let phantoms = self.generic_named_phantoms(generics);
864 match self.reader.type_def_vtables(def).last() {
865 Some(Type::IUnknown) => {
866 methods.combine("e! { pub base__: ::windows::core::IUnknown_Vtbl, })
868 Some(Type::IInspectable) => {
869 methods.combine("e! { pub base__: ::windows::core::IInspectable_Vtbl, })
871 Some(Type::TypeDef((def, _))) => {
872 let vtbl = self.type_def_vtbl_name(*def, &[]);
873 methods.combine("e! { pub base__: #vtbl, });
878 for method in self.reader.type_def_methods(def) {
879 if self.reader.method_def_name(method) == ".ctor" {
882 let name = method_names.add(self, method);
883 let signature = self.reader.method_def_signature(method, generics);
884 let mut cfg = self.reader.signature_cfg(&signature);
885 let signature = self.vtbl_signature(def, generics, &signature);
886 cfg.add_feature(self.reader.type_def_namespace(def));
887 let cfg_all = self.cfg_features(&cfg);
888 let cfg_not = self.cfg_not_features(&cfg);
890 let signature = quote! { pub #name: unsafe extern "system" fn #signature, };
892 if cfg_all.is_empty() {
893 methods.combine(&signature);
895 methods.combine("e! {
906 #[repr(C)] #[doc(hidden)] pub struct #vtbl where #constraints {
912 pub fn vtbl_signature(
916 signature: &Signature,
921 .contains(TypeAttributes::WINRT);
922 let hresult = self.type_name(&Type::HRESULT);
924 let (trailing_return_type, return_type, udt_return_type) = if is_winrt {
925 if let Some(return_type) = &signature.return_type {
926 if let Type::WinrtArray(kind) = return_type {
927 let tokens = self.type_abi_name(kind);
929 quote! { result_size__: *mut u32, result__: *mut *mut #tokens },
930 quote! { -> #hresult },
934 let tokens = self.type_abi_name(return_type);
936 quote! { result__: *mut #tokens },
937 quote! { -> #hresult },
942 (quote! {}, quote! { -> #hresult }, quote! {})
944 } else if let Some(return_type) = &signature.return_type {
945 if self.reader.type_is_struct(return_type) {
946 let tokens = self.type_abi_name(return_type);
947 (quote! {}, quote! {}, quote! { result__: *mut #tokens, })
949 let tokens = self.type_default_name(return_type);
950 (quote! {}, quote! { -> #tokens }, quote! {})
953 (quote! {}, quote! {}, quote! {})
956 let params = signature.params.iter().map(|p| {
957 let name = self.param_name(p.def);
959 let abi = self.type_abi_name(&p.ty);
960 let abi_size_name: TokenStream =
961 format!("{}_array_size", self.reader.param_name(p.def)).into();
966 .contains(ParamAttributes::INPUT)
968 if p.ty.is_winrt_array() {
969 quote! { #abi_size_name: u32, #name: *const #abi, }
970 } else if p.ty.is_winrt_const_ref() {
971 quote! { #name: &#abi, }
973 quote! { #name: #abi, }
975 } else if p.ty.is_winrt_array() {
976 quote! { #abi_size_name: u32, #name: *mut #abi, }
977 } else if p.ty.is_winrt_array_ref() {
978 quote! { #abi_size_name: *mut u32, #name: *mut *mut #abi, }
980 quote! { #name: *mut #abi, }
984 SignatureParamKind::ValueType => {
985 let abi = self.type_default_name(&p.ty);
986 quote! { #name: #abi, }
989 let abi = self.type_abi_name(&p.ty);
990 quote! { #name: #abi, }
996 quote! { (this: *mut ::core::ffi::c_void, #udt_return_type #(#params)* #trailing_return_type) #return_type }
998 pub fn param_name(&self, param: Param) -> TokenStream {
999 // In Rust, function parameters cannot be named the same as structs. This avoids some collisions that occur in the win32 metadata.
1000 // See Icmp6SendEcho2 for an example.
1001 to_ident(&self.reader.param_name(param).to_lowercase())
1003 pub fn return_sig(&self, signature: &Signature) -> TokenStream {
1004 if let Some(return_type) = &signature.return_type {
1005 let tokens = self.type_default_name(return_type);
1006 format!(" -> {}", tokens.as_str()).into()
1007 } else if self.reader.method_def_does_not_return(signature.def) {
1013 pub fn win32_args(&self, params: &[SignatureParam], kind: SignatureKind) -> TokenStream {
1014 let mut tokens = quote! {};
1016 for (position, param) in params.iter().enumerate() {
1017 let new = match kind {
1018 SignatureKind::Query(query) if query.object == position => {
1019 quote! { &mut result__, }
1021 SignatureKind::ReturnValue | SignatureKind::ResultValue
1022 if params.len() - 1 == position =>
1024 quote! { &mut result__, }
1026 SignatureKind::QueryOptional(query) if query.object == position => {
1027 quote! { result__ as *mut _ as *mut _, }
1029 SignatureKind::Query(query) | SignatureKind::QueryOptional(query)
1030 if query.guid == position =>
1032 quote! { &<T as ::windows::core::ComInterface>::IID, }
1035 let name = self.param_name(param.def);
1036 let flags = self.reader.param_flags(param.def);
1038 SignatureParamKind::ArrayFixed(_)
1039 | SignatureParamKind::ArrayRelativeLen(_)
1040 | SignatureParamKind::ArrayRelativeByteLen(_) => {
1041 let map = if flags.contains(ParamAttributes::OPTIONAL) {
1042 quote! { #name.as_deref().map_or(::core::ptr::null(), |slice|slice.as_ptr()) }
1044 quote! { #name.as_ptr() }
1046 quote! { ::core::mem::transmute(#map), }
1048 SignatureParamKind::ArrayRelativePtr(relative) => {
1049 let name = self.param_name(params[relative].def);
1050 let flags = self.reader.param_flags(params[relative].def);
1051 if flags.contains(ParamAttributes::OPTIONAL) {
1052 quote! { #name.as_deref().map_or(0, |slice|slice.len() as _), }
1054 quote! { #name.len() as _, }
1057 SignatureParamKind::TryInto => {
1058 quote! { #name.try_into_param()?.abi(), }
1060 SignatureParamKind::IntoParam => {
1061 quote! { #name.into_param().abi(), }
1063 SignatureParamKind::OptionalPointer => {
1064 if flags.contains(ParamAttributes::OUTPUT) {
1065 quote! { ::core::mem::transmute(#name.unwrap_or(::std::ptr::null_mut())), }
1067 quote! { ::core::mem::transmute(#name.unwrap_or(::std::ptr::null())), }
1070 SignatureParamKind::ValueType => {
1073 SignatureParamKind::Blittable => {
1074 quote! { ::core::mem::transmute(#name), }
1076 SignatureParamKind::Other => {
1077 quote! { ::core::mem::transmute_copy(#name), }
1082 tokens.combine(&new)
1087 pub fn win32_params(&self, params: &[SignatureParam], kind: SignatureKind) -> TokenStream {
1088 let mut tokens = quote! {};
1090 let mut generic_params = self.generic_params(params);
1091 for (position, param) in params.iter().enumerate() {
1093 SignatureKind::Query(query) | SignatureKind::QueryOptional(query) => {
1094 if query.object == position || query.guid == position {
1098 SignatureKind::ReturnValue | SignatureKind::ResultValue
1099 if params.len() - 1 == position =>
1106 let name = self.param_name(param.def);
1109 SignatureParamKind::ArrayFixed(fixed) => {
1110 let ty = param.ty.deref();
1111 let ty = self.type_default_name(&ty);
1112 let len = Literal::u32_unsuffixed(fixed as _);
1115 .param_flags(param.def)
1116 .contains(ParamAttributes::OUTPUT)
1118 quote! { &mut [#ty; #len] }
1120 quote! { &[#ty; #len] }
1124 .param_flags(param.def)
1125 .contains(ParamAttributes::OPTIONAL)
1127 tokens.combine("e! { #name: ::core::option::Option<#ty>, });
1129 tokens.combine("e! { #name: #ty, });
1132 SignatureParamKind::ArrayRelativeLen(_) => {
1133 let ty = param.ty.deref();
1134 let ty = self.type_default_name(&ty);
1137 .param_flags(param.def)
1138 .contains(ParamAttributes::OUTPUT)
1140 quote! { &mut [#ty] }
1146 .param_flags(param.def)
1147 .contains(ParamAttributes::OPTIONAL)
1149 tokens.combine("e! { #name: ::core::option::Option<#ty>, });
1151 tokens.combine("e! { #name: #ty, });
1154 SignatureParamKind::ArrayRelativeByteLen(_) => {
1157 .param_flags(param.def)
1158 .contains(ParamAttributes::OUTPUT)
1160 quote! { &mut [u8] }
1166 .param_flags(param.def)
1167 .contains(ParamAttributes::OPTIONAL)
1169 tokens.combine("e! { #name: ::core::option::Option<#ty>, });
1171 tokens.combine("e! { #name: #ty, });
1174 SignatureParamKind::ArrayRelativePtr(_) => {}
1175 SignatureParamKind::TryInto | SignatureParamKind::IntoParam => {
1176 let (position, _) = generic_params.next().unwrap();
1177 let kind: TokenStream = format!("P{position}").into();
1178 tokens.combine("e! { #name: #kind, });
1180 SignatureParamKind::OptionalPointer => {
1181 let kind = self.type_default_name(¶m.ty);
1182 tokens.combine("e! { #name: ::core::option::Option<#kind>, });
1184 SignatureParamKind::ValueType | SignatureParamKind::Blittable => {
1185 let kind = self.type_default_name(¶m.ty);
1186 tokens.combine("e! { #name: #kind, });
1188 SignatureParamKind::Other => {
1189 let kind = self.type_default_name(¶m.ty);
1190 tokens.combine("e! { #name: &#kind, });
1198 pub fn impl_signature(&self, def: TypeDef, signature: &Signature) -> TokenStream {
1201 .type_def_flags(def)
1202 .contains(TypeAttributes::WINRT)
1204 let is_delegate = self.reader.type_def_kind(def) == TypeKind::Delegate;
1205 let params = signature
1208 .map(|p| self.winrt_produce_type(p, !is_delegate));
1210 let return_type = if let Some(return_type) = &signature.return_type {
1211 let tokens = self.type_name(return_type);
1213 if return_type.is_winrt_array() {
1214 quote! { ::windows::core::Array<#tokens> }
1222 let this = if is_delegate {
1228 quote! { (#this #(#params),*) -> ::windows::core::Result<#return_type> }
1230 let signature_kind = self.reader.signature_kind(signature);
1231 let mut params = quote! {};
1233 if signature_kind == SignatureKind::ResultValue {
1234 for param in &signature.params[..signature.params.len() - 1] {
1235 params.combine(&self.win32_produce_type(param));
1238 for param in &signature.params {
1239 params.combine(&self.win32_produce_type(param));
1243 let return_type = match signature_kind {
1244 SignatureKind::ReturnVoid => quote! {},
1245 SignatureKind::Query(_)
1246 | SignatureKind::QueryOptional(_)
1247 | SignatureKind::ResultVoid => quote! { -> ::windows::core::Result<()> },
1248 SignatureKind::ResultValue => {
1249 let return_type = signature.params[signature.params.len() - 1].ty.deref();
1250 let return_type = self.type_name(&return_type);
1252 quote! { -> ::windows::core::Result<#return_type> }
1254 _ => self.return_sig(signature),
1257 quote! { (&self, #params) #return_type }
1260 fn winrt_produce_type(&self, param: &SignatureParam, include_param_names: bool) -> TokenStream {
1261 let default_type = self.type_default_name(¶m.ty);
1265 .param_flags(param.def)
1266 .contains(ParamAttributes::INPUT)
1268 if param.ty.is_winrt_array() {
1269 quote! { &[#default_type] }
1270 } else if self.reader.type_is_primitive(¶m.ty) {
1271 quote! { #default_type }
1272 } else if self.reader.type_is_nullable(¶m.ty) {
1273 let type_name = self.type_name(¶m.ty);
1274 quote! { ::core::option::Option<&#type_name> }
1276 quote! { &#default_type }
1278 } else if param.ty.is_winrt_array() {
1279 quote! { &mut [#default_type] }
1280 } else if param.ty.is_winrt_array_ref() {
1281 let kind = self.type_name(¶m.ty);
1282 quote! { &mut ::windows::core::Array<#kind> }
1284 quote! { &mut #default_type }
1287 if include_param_names {
1288 let name = self.param_name(param.def);
1289 quote! { #name: #sig }
1294 fn win32_produce_type(&self, param: &SignatureParam) -> TokenStream {
1295 let name = self.param_name(param.def);
1296 let kind = self.type_default_name(¶m.ty);
1300 .param_flags(param.def)
1301 .contains(ParamAttributes::INPUT)
1303 if self.reader.type_is_primitive(¶m.ty) {
1304 quote! { #name: #kind, }
1305 } else if self.reader.type_is_nullable(¶m.ty) {
1306 let kind = self.type_name(¶m.ty);
1307 quote! { #name: ::core::option::Option<&#kind>, }
1309 quote! { #name: &#kind, }
1312 quote! { #name: #kind, }
1317 pub fn to_ident(name: &str) -> TokenStream {
1318 // keywords list based on https://doc.rust-lang.org/reference/keywords.html
1320 "abstract" | "as" | "become" | "box" | "break" | "const" | "continue" | "crate" | "do"
1321 | "else" | "enum" | "extern" | "false" | "final" | "fn" | "for" | "if" | "impl" | "in"
1322 | "let" | "loop" | "macro" | "match" | "mod" | "move" | "mut" | "override" | "priv"
1323 | "pub" | "ref" | "return" | "static" | "struct" | "super" | "trait" | "true" | "type"
1324 | "typeof" | "unsafe" | "unsized" | "use" | "virtual" | "where" | "while" | "yield"
1325 | "try" | "async" | "await" | "dyn" => format!("r#{name}").into(),
1326 "Self" | "self" => format!("{name}_").into(),
1327 "_" => "unused".into(),
1328 _ => trim_tick(name).into(),
1332 fn mut_ptrs(pointers: usize) -> TokenStream {
1333 "*mut ".repeat(pointers).into()
1336 fn const_ptrs(pointers: usize) -> TokenStream {
1337 "*const ".repeat(pointers).into()
1340 fn to_feature(name: &str) -> String {
1341 let mut feature = String::new();
1343 for name in name.split('.').skip(1) {
1344 feature.push_str(name);
1348 if feature.is_empty() {
1349 feature = name.to_string();
1351 feature.truncate(feature.len() - 1);
1357 fn starts_with(namespace: &str, feature: &str) -> bool {
1358 if namespace == feature {
1362 if namespace.len() > feature.len() && namespace.as_bytes().get(feature.len()) == Some(&b'.') {
1363 return namespace.starts_with(feature);
1369 fn gen_mut_ptrs(pointers: usize) -> TokenStream {
1370 "*mut ".repeat(pointers).into()
1373 fn gen_const_ptrs(pointers: usize) -> TokenStream {
1374 "*const ".repeat(pointers).into()
1382 fn test_starts_with() {
1383 assert!(starts_with(
1384 "Windows.Win32.Graphics.Direct3D11on12",
1385 "Windows.Win32.Graphics.Direct3D11on12"
1387 assert!(starts_with(
1388 "Windows.Win32.Graphics.Direct3D11on12",
1389 "Windows.Win32.Graphics"
1391 assert!(!starts_with(
1392 "Windows.Win32.Graphics.Direct3D11on12",
1393 "Windows.Win32.Graphics.Direct3D11"
1395 assert!(!starts_with(
1396 "Windows.Win32.Graphics.Direct3D",
1397 "Windows.Win32.Graphics.Direct3D11"