use crate::{extract_fields_with_types, extract_variants_with_types};
use proc_macro2::TokenStream;
use quote::quote;
use syn::{Data, DataEnum, DataStruct, DeriveInput, Ident};
pub fn dispatch_struct_enum(input: DeriveInput) -> TokenStream {
let ident = input.ident;
match input.data {
Data::Struct(ds) => substitute_modes_struct(ds, ident),
Data::Enum(de) => substitute_modes_enum(de, ident),
_ => panic!("SubstituteModes can only be derived on structs and enums"),
}
}
fn substitute_modes_enum(de: DataEnum, ident: Ident) -> TokenStream {
let variants_with_type = extract_variants_with_types(de).into_iter();
let remap_quotes = variants_with_type.map(|(vident, _ ,_)| {
quote! {
&#ident::#vident(ref inner) => {Ok(#ident::#vident(SubstituteModes::remap_modes(&(*inner), mapping)?))},
}
});
let bremap = quote! {
fn remap_modes(&self, mapping: &std::collections::HashMap<usize, usize>) -> Result<Self, RoqoqoError> {
match self{
#(#remap_quotes)*
_ => panic!("Unexpectedly cannot match variant")
}
}
};
quote! {
#[automatically_derived]
impl SubstituteModes for #ident{
#bremap
}
}
}
fn substitute_modes_struct(ds: DataStruct, ident: Ident) -> TokenStream {
let fields_with_type = extract_fields_with_types(ds).into_iter();
let remap_quote = fields_with_type.map(|(fid, _, _)| match fid.to_string().as_str() {
"mode" => quote! {*mapping.get(&self.mode).unwrap_or(&self.mode)},
"mode_0" => quote! {*mapping.get(&self.mode_0).unwrap_or(&self.mode_0)},
"mode_1" => quote! {*mapping.get(&self.mode_1).unwrap_or(&self.mode_1)},
_ => quote! {(self).#fid.clone()},
});
quote! {
#[automatically_derived]
impl SubstituteModes for #ident{
fn remap_modes(&self, mapping: &std::collections::HashMap<usize, usize>) -> Result<Self, RoqoqoError>{
crate::operations::check_valid_mapping(mapping)?;
Ok(Self::new(#(#remap_quote),*))
}
}
}
}