use crate::core_ext::*;
use proc_macro2::{Ident, TokenStream};
use quote::{ToTokens, TokenStreamExt};
use syn::{Generics, ImplGenerics, TypeGenerics, WhereClause};
use unspecified::Unspecified;
#[cfg(feature = "generic-impl")]
pub struct GenericImpl<G, Tgt = Unspecified, Tr = Unspecified> {
generics: G,
implemented_for: Tgt,
implemented_trait: Tr,
}
impl<G> GenericImpl<G> {
#[inline]
pub fn new(generics: G) -> Self
where
G: GenericsLike,
{
Self {
generics,
implemented_trait: Unspecified,
implemented_for: Unspecified,
}
}
}
impl<G, Tgt, Tr> GenericImpl<G, Tgt, Tr> {
#[inline]
pub fn with_trait<Tr2>(self, trait_name: Tr2) -> GenericImpl<G, Tgt, Tr2> {
GenericImpl {
generics: self.generics,
implemented_trait: trait_name,
implemented_for: self.implemented_for,
}
}
pub fn with_target<Tgt2>(self, target: Tgt2) -> GenericImpl<G, Tgt2, Tr> {
GenericImpl {
generics: self.generics,
implemented_trait: self.implemented_trait,
implemented_for: target,
}
}
}
impl<G, Tgt> ToTokens for GenericImpl<G, Tgt>
where
G: GenericsLike,
Tgt: ToTokens,
{
fn to_tokens(&self, tokens: &mut TokenStream) {
let Self {
generics,
implemented_for,
implemented_trait: _,
} = self;
let (g1, g2, g3) = generics.split_for_impl();
tokens.append(Ident::create("impl"));
g1.to_tokens(tokens);
implemented_for.to_tokens(tokens);
g2.to_tokens(tokens);
g3.to_tokens(tokens);
}
}
impl<G, Tgt, Tr> ToTokens for GenericImpl<G, Tgt, Tr>
where
G: GenericsLike,
Tgt: ToTokens,
Tr: ToTokens,
{
fn to_tokens(&self, tokens: &mut TokenStream) {
let Self {
generics,
implemented_for,
implemented_trait,
} = self;
let (g1, g2, g3) = generics.split_for_impl();
tokens.append(Ident::create("impl"));
g1.to_tokens(tokens);
implemented_trait.to_tokens(tokens);
tokens.append(Ident::create("for"));
implemented_for.to_tokens(tokens);
g2.to_tokens(tokens);
g3.to_tokens(tokens);
}
}
pub trait GenericsLike {
fn split_for_impl(&self) -> (ImplGenerics<'_>, TypeGenerics<'_>, Option<&WhereClause>);
}
impl<T: GenericsLike> GenericsLike for &T {
#[inline]
fn split_for_impl(&self) -> (ImplGenerics<'_>, TypeGenerics<'_>, Option<&WhereClause>) {
T::split_for_impl(*self)
}
}
impl GenericsLike for Generics {
fn split_for_impl(&self) -> (ImplGenerics<'_>, TypeGenerics<'_>, Option<&WhereClause>) {
Generics::split_for_impl(self)
}
}
mod unspecified {
pub struct Unspecified;
}