use proc_macro2::TokenStream as TokenStream2;
use crate::derive::config::EnumBitsetConfig;
impl EnumBitsetConfig {
pub fn impl_iter(&self) -> TokenStream2 {
let name = &self.set_type;
let iter = &self.iter_type;
let base_ty = &self.base_type;
let inner_ty = &self.inner_type;
let inner_vis = &self.inner_vis;
let doc1 = format!("Iterator returned by the [`iter`]({name}::iter) method.");
let doc2 = format!(
"[`{iter}`] iterates over the variants of [`{base_ty}`] contained in a [`{name}`] instance."
);
quote::quote! {
#[doc = #doc1]
#[doc = #doc2]
#[derive(Clone)]
#inner_vis struct #iter {
items: #inner_ty,
}
impl Iterator for #iter {
type Item = #base_ty;
fn next(&mut self) -> Option<#base_ty> {
if self.items == 0 {
return Option::None;
}
let index = self.items.trailing_zeros();
self.items &= !(1 << index);
Option::Some(#name::VARIANTS[index as usize].clone())
}
fn size_hint(&self) -> (usize, Option<usize>) {
let n = self.items.count_ones() as usize;
(n, Option::Some(n))
}
fn count(self) -> usize {
self.items.count_ones() as usize
}
}
impl FromIterator<#base_ty> for #name {
fn from_iter<T: IntoIterator<Item = #base_ty>>(iter: T) -> Self {
Self::from(iter)
}
}
impl<'a> FromIterator<&'a #base_ty> for #name {
fn from_iter<T: IntoIterator<Item = &'a #base_ty>>(iter: T) -> Self {
let items = iter.into_iter().fold(0, |acc, item| acc | base_to_value(item));
Self { items }
}
}
impl Extend<#base_ty> for #name {
fn extend<T: IntoIterator<Item = #base_ty>>(&mut self, iter: T) {
self.items |= iter.into_iter().fold(0, |acc, item| acc | base_to_value(&item));
}
}
impl<'a> Extend<&'a #base_ty> for #name {
fn extend<T: IntoIterator<Item = &'a #base_ty>>(&mut self, iter: T) {
self.items |= iter.into_iter().fold(0, |acc, item| acc | base_to_value(item));
}
}
impl FromIterator<#name> for #name {
fn from_iter<T: IntoIterator<Item = #name>>(iter: T) -> Self {
iter.into_iter().flat_map(|item| item.into_iter()).collect()
}
}
impl<'a> FromIterator<&'a #name> for #name {
fn from_iter<T: IntoIterator<Item = &'a #name>>(iter: T) -> Self {
iter.into_iter().flat_map(|item| item.iter()).collect()
}
}
impl IntoIterator for #name {
type Item = #base_ty;
type IntoIter = #iter;
fn into_iter(self) -> Self::IntoIter {
#iter { items: self.items }
}
}
}
}
}