use crate::ParseResult;
pub(crate) fn expand_derive(res: &ParseResult) -> syn::Result<proc_macro::TokenStream> {
let mut tokens = proc_macro2::TokenStream::new();
tokens.extend(expand_newtype_trait(res));
tokens.extend(expand_from(res));
tokens.extend(expand_try_from(res));
tokens.extend(expand_into(res));
tokens.extend(expand_try_into(res));
tokens.extend(expand_add(res));
tokens.extend(expand_add_assign(res));
tokens.extend(expand_partial_eq(res));
tokens.extend(expand_sub(res));
tokens.extend(expand_sub_assign(res));
Ok(tokens.into())
}
fn expand_newtype_trait(res: &ParseResult) -> proc_macro2::TokenStream {
let newtype = &res.newtype;
let inner_ty = &res.inner_ty;
let (impl_generics, newtype_generics, where_clause) = &res.generics.split_for_impl();
quote::quote! {
#[automatically_derived]
impl #impl_generics newtype_tools::Newtype for #newtype #newtype_generics #where_clause {
type Inner = #inner_ty;
}
#[automatically_derived]
impl #impl_generics From<#inner_ty> for #newtype #newtype_generics #where_clause {
fn from(inner: #inner_ty) -> Self {
#newtype(inner)
}
}
#[automatically_derived]
impl #impl_generics AsRef<#inner_ty> for #newtype #newtype_generics #where_clause {
fn as_ref(&self) -> &#inner_ty {
&self.0
}
}
}
}
fn expand_from(res: &ParseResult) -> proc_macro2::TokenStream {
let newtype = &res.newtype;
let (impl_generics, newtype_generics, where_clause) = &res.generics.split_for_impl();
res.from
.iter()
.map(|(from_ty, expr)| {
quote::quote! {
#[automatically_derived]
impl #impl_generics From<#from_ty> for #newtype #newtype_generics #where_clause {
fn from(value: #from_ty) -> Self {
fn call_inner<I, O, F: FnOnce(I) -> O>(f: F, i: I) -> O {
f(i)
}
call_inner(#expr, value)
}
}
}
})
.collect()
}
fn expand_try_from(res: &ParseResult) -> proc_macro2::TokenStream {
let newtype = &res.newtype;
let (impl_generics, newtype_generics, where_clause) = &res.generics.split_for_impl();
res.try_from
.iter()
.map(|(try_from_ty, error_ty, expr)| {
quote::quote! {
#[automatically_derived]
impl #impl_generics TryFrom<#try_from_ty> for #newtype #newtype_generics #where_clause {
type Error = #error_ty;
fn try_from(value: #try_from_ty) -> Result<Self, Self::Error> {
fn call_inner<I, O, F: FnOnce(I) -> O>(f: F, i: I) -> O {
f(i)
}
call_inner(#expr, value)
}
}
}
})
.collect()
}
fn expand_into(res: &ParseResult) -> proc_macro2::TokenStream {
let newtype = &res.newtype;
let (impl_generics, newtype_generics, where_clause) = &res.generics.split_for_impl();
res.into
.iter()
.map(|(output_ty, expr)| {
quote::quote! {
#[automatically_derived]
impl #impl_generics From<#newtype #newtype_generics> for #output_ty #where_clause {
fn from(newtype: #newtype #newtype_generics) -> Self {
fn call_inner<I, O, F: FnOnce(I) -> O>(f: F, i: I) -> O {
f(i)
}
call_inner(#expr, newtype)
}
}
}
})
.collect()
}
fn expand_try_into(res: &ParseResult) -> proc_macro2::TokenStream {
let newtype = &res.newtype;
let (impl_generics, newtype_generics, where_clause) = &res.generics.split_for_impl();
res.try_into
.iter()
.map(|(output_ty, error_ty, expr)| {
quote::quote! {
#[automatically_derived]
impl #impl_generics TryFrom<#newtype #newtype_generics> for #output_ty #where_clause {
type Error = #error_ty;
fn try_from(newtype: #newtype #newtype_generics) -> Result<Self, Self::Error> {
fn call_inner<I, O, F: FnOnce(I) -> O>(f: F, i: I) -> O {
f(i)
}
call_inner(#expr, newtype)
}
}
}
})
.collect()
}
fn expand_add(res: &ParseResult) -> proc_macro2::TokenStream {
expand_bin_op(
syn::parse_quote!(std::ops::Add),
syn::parse_quote!(add),
res,
&res.add,
)
}
fn expand_add_assign(res: &ParseResult) -> proc_macro2::TokenStream {
expand_assign_op(
syn::parse_quote!(std::ops::AddAssign),
syn::parse_quote!(add_assign),
res,
&res.add_assign,
)
}
fn expand_partial_eq(res: &ParseResult) -> proc_macro2::TokenStream {
let newtype = &res.newtype;
let (impl_generics, newtype_generics, where_clause) = &res.generics.split_for_impl();
res.partial_eq
.iter()
.map(|(other_ty, expr)| {
quote::quote! {
#[automatically_derived]
impl #impl_generics PartialEq<#other_ty> for #newtype #newtype_generics #where_clause {
fn eq(&self, other: &#other_ty) -> bool {
fn call_inner<S, I, O, F: FnOnce(S, I) -> O>(f: F, s: S, i: I) -> O {
f(s, i)
}
call_inner(#expr, self, other)
}
}
}
})
.collect()
}
fn expand_sub(res: &ParseResult) -> proc_macro2::TokenStream {
expand_bin_op(
syn::parse_quote!(std::ops::Sub),
syn::parse_quote!(sub),
res,
&res.sub,
)
}
fn expand_sub_assign(res: &ParseResult) -> proc_macro2::TokenStream {
expand_assign_op(
syn::parse_quote!(std::ops::SubAssign),
syn::parse_quote!(sub_assign),
res,
&res.sub_assign,
)
}
fn expand_bin_op(
trait_path: syn::Path,
method_ident: syn::Ident,
res: &ParseResult,
ops: &[(syn::Type, syn::Type, syn::Expr)],
) -> proc_macro2::TokenStream {
if ops.is_empty() {
return proc_macro2::TokenStream::new();
}
let newtype = &res.newtype;
let (impl_generics, newtype_generics, where_clause) = &res.generics.split_for_impl();
ops
.iter()
.map(|(rhs_ty, output_ty, expr)| {
quote::quote! {
#[automatically_derived]
impl #impl_generics #trait_path<&#rhs_ty> for &#newtype #newtype_generics #where_clause {
type Output = #output_ty;
fn #method_ident(self, rhs: &#rhs_ty) -> Self::Output {
fn call_inner<S, I, O, F: FnOnce(S, I) -> O>(f: F, s: S, i: I) -> O {
f(s, i)
}
call_inner(#expr, self, rhs)
}
}
#[automatically_derived]
impl #impl_generics #trait_path<&#rhs_ty> for #newtype #newtype_generics #where_clause {
type Output = #output_ty;
fn #method_ident(self, rhs: &#rhs_ty) -> Self::Output { #trait_path::#method_ident(&self, rhs) }
}
#[automatically_derived]
impl #impl_generics #trait_path<#rhs_ty> for &#newtype #newtype_generics #where_clause {
type Output = #output_ty;
fn #method_ident(self, rhs: #rhs_ty) -> Self::Output { #trait_path::#method_ident(self, &rhs) }
}
#[automatically_derived]
impl #impl_generics #trait_path<#rhs_ty> for #newtype #newtype_generics #where_clause {
type Output = #output_ty;
fn #method_ident(self, rhs: #rhs_ty) -> Self::Output { #trait_path::#method_ident(&self, &rhs) }
}
}
})
.collect()
}
fn expand_assign_op(
trait_path: syn::Path,
method_ident: syn::Ident,
res: &ParseResult,
ops: &[(syn::Type, syn::Expr)],
) -> proc_macro2::TokenStream {
if ops.is_empty() {
return proc_macro2::TokenStream::new();
}
let newtype = &res.newtype;
let (impl_generics, newtype_generics, where_clause) = &res.generics.split_for_impl();
ops
.iter()
.map(|(rhs_ty, expr)| {
quote::quote! {
#[automatically_derived]
impl #impl_generics #trait_path<&#rhs_ty> for #newtype #newtype_generics #where_clause {
fn #method_ident(&mut self, rhs: &#rhs_ty) {
fn call_inner<S, I, F: FnOnce(S, I)>(f: F, s: S, i: I) {
f(s, i)
}
call_inner(#expr, self, rhs)
}
}
#[automatically_derived]
impl #impl_generics #trait_path<#rhs_ty> for #newtype #newtype_generics #where_clause {
fn #method_ident(&mut self, rhs: #rhs_ty) { #trait_path::#method_ident(self, &rhs) }
}
}
})
.collect()
}