use crate::fields::field_types;
use deluxe::ExtractAttributes;
use proc_macro2::{Delimiter, Group, Ident, Punct, Spacing, TokenStream};
use quote::TokenStreamExt;
use std::collections::HashSet;
use syn::punctuated::Punctuated;
use syn::parse_quote;
use syn::{Data, DeriveInput, Error, Expr, Result, Token};
use syn::{TypeParamBound, WhereClause, WherePredicate};
#[derive(Clone, Default, Debug, ExtractAttributes)]
#[deluxe(attributes(polyquine))]
pub struct Attrs {
#[deluxe(default = false)]
pub recursive: bool,
#[deluxe(default = None)]
pub custom_with: Option<Expr>,
}
pub fn add_bounds(
input: DeriveInput,
where_clause: Option<&WhereClause>,
bounds: Punctuated<TypeParamBound, Token![+]>,
) -> Result<WhereClause> {
let unique_types: HashSet<_> = match input.data {
Data::Union(_) => return Err(Error::new_spanned(input, "unions are not supported")),
Data::Struct(data) => HashSet::from_iter(field_types(data.fields)),
Data::Enum(data) => data
.variants
.into_iter()
.flat_map(|v| field_types(v.fields))
.collect::<HashSet<_>>(),
};
let mut where_clause = where_clause.cloned().unwrap_or_else(|| WhereClause {
where_token: Default::default(),
predicates: Default::default(),
});
where_clause
.predicates
.extend(unique_types.iter().map(|ty| -> WherePredicate {
parse_quote! {
#ty: #bounds
}
}));
Ok(where_clause)
}
pub fn expand_sequence(seq: &Ident) -> TokenStream {
let mut inner = TokenStream::new();
inner.append(Punct::new('#', Spacing::Alone));
let mut paren_content = TokenStream::new();
paren_content.append(Punct::new('#', Spacing::Alone));
paren_content.append(seq.clone());
let paren_group = Group::new(Delimiter::Parenthesis, paren_content);
inner.append(paren_group);
inner.append(Punct::new(',', Spacing::Alone));
inner.append(Punct::new('*', Spacing::Alone));
inner
}