use proc_macro2::{Delimiter, Group, TokenStream, TokenTree};
use quote::quote;
use syn::{FnArg, ImplItem, parse::Parse, parse2};
use crate::NodynEnum;
#[allow(dead_code)]
#[derive(Debug, Clone)]
pub(crate) struct MethodImpl {
pub(crate) items: Vec<syn::ImplItem>,
pub(crate) functions: Vec<syn::ImplItemFn>,
}
impl Parse for MethodImpl {
fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
let mut items = Vec::new();
let mut functions = Vec::new();
let content;
let _brace_token = syn::braced!(content in input);
while !content.is_empty() {
let item = content.parse::<syn::ImplItem>()?;
if let ImplItem::Verbatim(ts) = item {
let ts: TokenStream = ts
.into_iter()
.map(|tt| {
if &tt.to_string() == ";" {
TokenTree::Group(Group::new(Delimiter::Brace, TokenStream::new()))
} else {
tt
}
})
.collect();
functions.push(parse2::<syn::ImplItemFn>(ts)?);
} else {
items.push(item);
}
}
Ok(Self { items, functions })
}
}
impl MethodImpl {
pub(crate) fn expand_methods_tokens(&self, wrapper: &NodynEnum) -> Vec<TokenStream> {
self.functions
.iter()
.map(|f| {
if let Some(FnArg::Receiver(_)) = f.sig.inputs.first() {
let arms = wrapper
.variants
.iter()
.map(|v| v.fn_call_arm_tokens(&wrapper.ident, &f.sig.ident, &f.sig.inputs));
let attrs = &f.attrs;
let vis = &f.vis;
let signature = &f.sig;
quote! {
#(#attrs)*
#vis #signature {
match self {
#(#arms)*
}
}
}
} else {
quote! {}
}
})
.collect::<Vec<_>>()
}
}