pub fn derive_coerce(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    if let Err(err) = check_repr(&input) {
        return err.into_compile_error().into();
    }

    let lifetimes = input.generics.lifetimes().collect::<Vec<_>>();

    if input.generics.type_params().count() == 0 {
        let field = match &input.data {
            Data::Struct(x) if x.fields.len() == 1 => x.fields.iter().next().unwrap(),
            _ => {
                return syn::Error::new_spanned(
                    input,
                    "Type-parameter free types must be a single field struct",
                )
                .into_compile_error()
                .into();
            }
        };

        let type1 = input.ident;
        let type2 = &field.ty;
        let gen = quote! {
            unsafe impl < #(#lifetimes),* > gazebo::coerce::Coerce<#type1< #(#lifetimes),* >> for #type2 {}
            unsafe impl < #(#lifetimes),* > gazebo::coerce::Coerce<#type2> for #type1< #(#lifetimes),* > {}
        };
        gen.into()
    } else {
        // unsafe impl <To__T, From__T> Coerce<X<To__T>> X<From__T> where ...
        let name = &input.ident;
        let mut ty_args = HashSet::new();
        let mut ty_args_to = Vec::new();
        let mut ty_args_from = Vec::new();
        let mut ty_args_to1 = Vec::new();
        let mut ty_args_from1 = Vec::new();
        for t in input.generics.type_params() {
            ty_args.insert(t.ident.clone());
            let to_ident = format_ident!("To{}", t.ident);
            let from_ident = format_ident!("From{}", t.ident);
            ty_args_to.push(to_ident.clone());
            ty_args_from.push(from_ident.clone());
            if t.bounds.is_empty() {
                ty_args_to1.push(quote! { #to_ident });
                ty_args_from1.push(quote! { #from_ident });
            } else {
                let bounds = &t.bounds;
                ty_args_to1.push(quote! { #to_ident: #bounds });
                ty_args_from1.push(quote! { #from_ident: #bounds });
            }
        }

        let mut constraints = Vec::new();
        let fields: Vec<_> = match &input.data {
            Data::Struct(x) => x.fields.iter().collect(),
            Data::Enum(x) => x.variants.iter().flat_map(|x| &x.fields).collect(),
            _ => {
                return syn::Error::new_spanned(input, "Type-parameter cannot be a union")
                    .into_compile_error()
                    .into();
            }
        };
        for x in fields {
            let mut to_ty = x.ty.clone();
            let mut from_ty = x.ty.clone();
            let to = replace_type(&mut to_ty, &ty_args, "To");
            let from = replace_type(&mut from_ty, &ty_args, "From");
            if to.is_none() || from.is_none() {
                return syn::Error::new_spanned(
                    &input,
                    "Don't know how to deal with some of the fields",
                )
                .into_compile_error()
                .into();
            }
            if to_ty != from_ty {
                constraints.push(quote! { #from_ty : gazebo::coerce::Coerce< #to_ty >});
            }
        }

        let gen = quote! {
            unsafe impl < #(#lifetimes,)* #(#ty_args_from1,)* #(#ty_args_to1,)* >
                gazebo::coerce::Coerce<#name < #(#lifetimes,)* #(#ty_args_to,)* >>
                for #name < #(#lifetimes,)* #(#ty_args_from,)* >
                where #(#constraints,)* {}
        };
        gen.into()
    }
}
// This macro does two related derivations depending on whether there are any generic parameters.
//
// struct A(B) ==> coerce both ways between A and B
// struct A<T>(...) => coerce A<T1> to A<T2> if coerce T1 to T2 and all the fields support it
This macro does two related derivations depending on whether there are any generic parameters.
struct A(B) ==> coerce both ways between A and B
struct A(...) => coerce A to A if coerce T1 to T2 and all the fields support it
This macro does two related derivations depending on whether there are any generic parameters . struct A ( B ) == > coerce both ways between A and B struct A ( ... ) = > coerce A to A if coerce T1 to T2 and all the fields support it
pub fn derive_coerce(input: proc_macro::TokenStream) -> proc_macro::TokenStream {
    let input = parse_macro_input!(input as DeriveInput);
    if let Err(err) = check_repr(&input) {
        return err.into_compile_error().into();
    }
    let lifetimes = input.generics.lifetimes().collect::<Vec<_>>();
    if input.generics.type_params().count() == 0 {
        let field = match &input.data {
            Data::Struct(x) if x.fields.len() == 1 => x.fields.iter().next().unwrap(),
            _ => {
                return syn::Error::new_spanned(
                    input,
                    "Type-parameter free types must be a single field struct",
                )
                .into_compile_error()
                .into();
            }
        };
        let type1 = input.ident;
        let type2 = &field.ty;
        let gen = quote! {
            unsafe impl < #(#lifetimes),* > gazebo::coerce::Coerce<#type1< #(#lifetimes),* >> for #type2 {}
            unsafe impl < #(#lifetimes),* > gazebo::coerce::Coerce<#type2> for #type1< #(#lifetimes),* > {}
        };
        gen.into()
    } else {
        // unsafe impl <To__T, From__T> Coerce<X<To__T>> X<From__T> where ...
        let name = &input.ident;
        let mut ty_args = HashSet::new();
        let mut ty_args_to = Vec::new();
        let mut ty_args_from = Vec::new();
        let mut ty_args_to1 = Vec::new();
        let mut ty_args_from1 = Vec::new();
        for t in input.generics.type_params() {
            ty_args.insert(t.ident.clone());
            let to_ident = format_ident!("To{}", t.ident);
            let from_ident = format_ident!("From{}", t.ident);
            ty_args_to.push(to_ident.clone());
            ty_args_from.push(from_ident.clone());
            if t.bounds.is_empty() {
                ty_args_to1.push(quote! { #to_ident });
                ty_args_from1.push(quote! { #from_ident });
            } else {
                let bounds = &t.bounds;
                ty_args_to1.push(quote! { #to_ident: #bounds });
                ty_args_from1.push(quote! { #from_ident: #bounds });
            }
        }
        let mut constraints = Vec::new();
        let fields: Vec<_> = match &input.data {
            Data::Struct(x) => x.fields.iter().collect(),
            Data::Enum(x) => x.variants.iter().flat_map(|x| &x.fields).collect(),
            _ => {
                return syn::Error::new_spanned(input, "Type-parameter cannot be a union")
                    .into_compile_error()
                    .into();
            }
        };
        for x in fields {
            let mut to_ty = x.ty.clone();
            let mut from_ty = x.ty.clone();
            let to = replace_type(&mut to_ty, &ty_args, "To");
            let from = replace_type(&mut from_ty, &ty_args, "From");
            if to.is_none() || from.is_none() {
                return syn::Error::new_spanned(
                    &input,
                    "Don't know how to deal with some of the fields",
                )
                .into_compile_error()
                .into();
            }
            if to_ty != from_ty {
                constraints.push(quote! { #from_ty : gazebo::coerce::Coerce< #to_ty >});
            }
        }
        let gen = quote! {
            unsafe impl < #(#lifetimes,)* #(#ty_args_from1,)* #(#ty_args_to1,)* >
                gazebo::coerce::Coerce<#name < #(#lifetimes,)* #(#ty_args_to,)* >>
                for #name < #(#lifetimes,)* #(#ty_args_from,)* >
                where #(#constraints,)* {}
        };
        gen.into()
    }
}
pub fn derive_coerce ( input : proc_macro :: TokenStream ) -> proc_macro :: TokenStream { let input = parse_macro_input ! ( input as DeriveInput ) ; if let Err ( err ) = check_repr ( & input ) { return err . into_compile_error ( ) . into ( ) ; } let lifetimes = input . generics . lifetimes ( ) . collect :: < Vec < _ > > ( ) ; if input . generics . type_params ( ) . count ( ) == 0 { let field = match & input . data { Data :: Struct ( x ) if x . fields . len ( ) == 1 => x . fields . iter ( ) . next ( ) . unwrap ( ) , _ => { return syn :: Error :: new_spanned ( input , " " , ) . into_compile_error ( ) . into ( ) ; } } ; let type1 = input . ident ; let type2 = & field . ty ; let gen = quote ! { unsafe impl ( lifetimes ) gazebo coerce Coerce type1 ( lifetimes ) for type2 { } unsafe impl ( lifetimes ) gazebo coerce Coerce type2 for type1 ( lifetimes ) { } } ; gen . into ( ) } else { // unsafe impl <To__T, From__T> Coerce<X<To__T>> X<From__T> where ... let name = & input . ident ; let mut ty_args = HashSet :: new ( ) ; let mut ty_args_to = Vec :: new ( ) ; let mut ty_args_from = Vec :: new ( ) ; let mut ty_args_to1 = Vec :: new ( ) ; let mut ty_args_from1 = Vec :: new ( ) ; for t in input . generics . type_params ( ) { ty_args . insert ( t . ident . clone ( ) ) ; let to_ident = format_ident ! ( " " t ident ) ; let from_ident = format_ident ! ( " " t ident ) ; ty_args_to . push ( to_ident . clone ( ) ) ; ty_args_from . push ( from_ident . clone ( ) ) ; if t . bounds . is_empty ( ) { ty_args_to1 . push ( quote ! { to_ident } ) ; ty_args_from1 . push ( quote ! { from_ident } ) ; } else { let bounds = & t . bounds ; ty_args_to1 . push ( quote ! { to_ident bounds } ) ; ty_args_from1 . push ( quote ! { from_ident bounds } ) ; } } let mut constraints = Vec :: new ( ) ; let fields : Vec < _ > = match & input . data { Data :: Struct ( x ) => x . fields . iter ( ) . collect ( ) , Data :: Enum ( x ) => x . variants . iter ( ) . flat_map ( | x | & x . fields ) . collect ( ) , _ => { return syn :: Error :: new_spanned ( input , " " ) . into_compile_error ( ) . into ( ) ; } } ; for x in fields { let mut to_ty = x . ty . clone ( ) ; let mut from_ty = x . ty . clone ( ) ; let to = replace_type ( & mut to_ty , & ty_args , " " ) ; let from = replace_type ( & mut from_ty , & ty_args , " " ) ; if to . is_none ( ) || from . is_none ( ) { return syn :: Error :: new_spanned ( & input , " " , ) . into_compile_error ( ) . into ( ) ; } if to_ty != from_ty { constraints . push ( quote ! { from_ty gazebo coerce Coerce to_ty } ) ; } } let gen = quote ! { unsafe impl ( lifetimes ) ( ty_args_from1 ) ( ty_args_to1 ) gazebo coerce Coerce name ( lifetimes ) ( ty_args_to ) for name ( lifetimes ) ( ty_args_from ) where ( constraints ) { } } ; gen . into ( ) } }
This macro does two related derivations depending on whether there are any generic parameters.
This macro does two related derivations depending on whether there are any generic parameters .
input
proc_macro::TokenStream
input
proc_macro::TokenStream