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 = &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 }