use super::*; pub fn writer(writer: &Writer, def: TypeDef, generics: &[Type], ident: &TokenStream, constraints: &TokenStream, _phantoms: &TokenStream, cfg: &Cfg) -> TokenStream { match def.type_name() { // If the type is IIterator then simply implement the Iterator trait over top. TypeName::IIterator => { return quote! { impl ::core::iter::Iterator for IIterator { type Item = T; fn next(&mut self) -> ::core::option::Option { let result = self.Current().ok(); if result.is_some() { self.MoveNext().ok()?; } result } } }; } // If the type is IIterable then implement the IntoIterator trait and rely on the resulting // IIterator returned by first() to implement the Iterator trait. TypeName::IIterable => { return quote! { impl ::core::iter::IntoIterator for IIterable { type Item = T; type IntoIter = IIterator; fn into_iter(self) -> Self::IntoIter { ::core::iter::IntoIterator::into_iter(&self) } } impl ::core::iter::IntoIterator for &IIterable { type Item = T; type IntoIter = IIterator; fn into_iter(self) -> Self::IntoIter { // TODO: not sure how to avoid this unwrap, although it should always succeed in practice. self.First().unwrap() } } }; } // If the type is IVectorView then provide the VectorViewIterator fast iterator. TypeName::IVectorView => { return quote! { pub struct VectorViewIterator { vector: ::core::option::Option>, current: u32, } impl VectorViewIterator { pub fn new(vector: ::core::option::Option>) -> Self { Self { vector, current: 0 } } } impl ::core::iter::Iterator for VectorViewIterator { type Item = T; fn next(&mut self) -> ::core::option::Option { self.vector.as_ref() .and_then(|vector| { vector.GetAt(self.current).ok() }) .and_then(|result| { self.current += 1; Some(result) }) } } impl ::core::iter::IntoIterator for IVectorView { type Item = T; type IntoIter = VectorViewIterator; fn into_iter(self) -> Self::IntoIter { ::core::iter::IntoIterator::into_iter(&self) } } impl ::core::iter::IntoIterator for &IVectorView { type Item = T; type IntoIter = VectorViewIterator; fn into_iter(self) -> Self::IntoIter { // TODO: shouldn't need to clone - VectorViewIterator should hold a reference VectorViewIterator::new(::core::option::Option::Some(::core::clone::Clone::clone(self))) } } }; } TypeName::IVector => { return quote! { pub struct VectorIterator { vector: ::core::option::Option>, current: u32, } impl VectorIterator { pub fn new(vector: ::core::option::Option>) -> Self { Self { vector, current: 0 } } } impl ::core::iter::Iterator for VectorIterator { type Item = T; fn next(&mut self) -> ::core::option::Option { self.vector.as_ref() .and_then(|vector| { vector.GetAt(self.current).ok() }) .and_then(|result| { self.current += 1; Some(result) }) } } impl ::core::iter::IntoIterator for IVector { type Item = T; type IntoIter = VectorIterator; fn into_iter(self) -> Self::IntoIter { ::core::iter::IntoIterator::into_iter(&self) } } impl ::core::iter::IntoIterator for &IVector { type Item = T; type IntoIter = VectorIterator; fn into_iter(self) -> Self::IntoIter { // TODO: shouldn't need to clone - VectorIterator should hold a reference VectorIterator::new(::core::option::Option::Some(::core::clone::Clone::clone(self))) } } }; } _ => {} } let wfc = writer.namespace("Windows.Foundation.Collections"); let mut iterable = None; let interfaces = type_interfaces(&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 interface.type_name() { TypeName::IVectorView => { let item = writer.type_name(&interface_generics[0]); let mut cfg = cfg.clone(); type_def_cfg_combine(*interface, interface_generics, &mut cfg); let features = writer.cfg_features(&cfg); return quote! { #features impl<#constraints> ::core::iter::IntoIterator for #ident { type Item = #item; type IntoIter = #wfc VectorViewIterator; fn into_iter(self) -> Self::IntoIter { ::core::iter::IntoIterator::into_iter(&self) } } #features impl<#constraints> ::core::iter::IntoIterator for &#ident { type Item = #item; type IntoIter = #wfc VectorViewIterator; fn into_iter(self) -> Self::IntoIter { #wfc VectorViewIterator::new(::windows_core::ComInterface::cast(self).ok()) } } }; } TypeName::IVector => { let item = writer.type_name(&interface_generics[0]); let mut cfg = cfg.clone(); type_def_cfg_combine(*interface, interface_generics, &mut cfg); let features = writer.cfg_features(&cfg); return quote! { #features impl<#constraints> ::core::iter::IntoIterator for #ident { type Item = #item; type IntoIter = #wfc VectorIterator; fn into_iter(self) -> Self::IntoIter { ::core::iter::IntoIterator::into_iter(&self) } } #features impl<#constraints> ::core::iter::IntoIterator for &#ident { type Item = #item; type IntoIter = #wfc VectorIterator; fn into_iter(self) -> Self::IntoIter { #wfc VectorIterator::new(::windows_core::ComInterface::cast(self).ok()) } } }; } TypeName::IIterable => { iterable = Some((*interface, interface_generics.to_vec())); } _ => {} } } } match iterable { None => TokenStream::new(), Some((interface, interface_generics)) => { let item = writer.type_name(&interface_generics[0]); let mut cfg = cfg.clone(); type_def_cfg_combine(interface, &interface_generics, &mut cfg); let features = writer.cfg_features(&cfg); quote! { #features impl<#constraints> ::core::iter::IntoIterator for #ident { type Item = #item; type IntoIter = #wfc IIterator; fn into_iter(self) -> Self::IntoIter { ::core::iter::IntoIterator::into_iter(&self) } } #features impl<#constraints> ::core::iter::IntoIterator for &#ident { type Item = #item; type IntoIter = #wfc IIterator; fn into_iter(self) -> Self::IntoIter { // TODO: not sure how to avoid this unwrap, although it should always succeed in practice. self.First().unwrap() } } } } } }