// If there are any closures in the argument list, turn them into boxed
// functions
If there are any closures in the argument list, turn them into boxed
functions
If there are any closures in the argument list turn them into boxed functions
fn declosurefy(gen: &Generics, args: &Punctuated<FnArg, Token![,]>) -> 
    (Generics, Punctuated<FnArg, Token![,]>, Punctuated<TokenStream, Token![,]>)
{
    let mut hm = HashMap::new();
    let mut save_fn_types = |ident: &Ident, tpb: &TypeParamBound| {
        if let TypeParamBound::Trait(tb) = tpb {
            let fident = &tb.path.segments.last().unwrap().ident;
            if ["Fn", "FnMut", "FnOnce"].iter().any(|s| fident == *s) {
                let newty: Type = parse2(quote!(Box<dyn #tb>)).unwrap();
                let subst_ty: Type = parse2(quote!(#ident)).unwrap();
                assert!(hm.insert(subst_ty, newty).is_none(),
                    "A generic parameter had two Fn bounds?");
            }
        }
    };
    // First, build a HashMap of all Fn generic types
    for g in gen.params.iter() {
        if let GenericParam::Type(tp) = g {
            for tpb in tp.bounds.iter() {
                save_fn_types(&tp.ident, tpb);
            }
        }
    }
    if let Some(wc) = &gen.where_clause {
        for pred in wc.predicates.iter() {
            if let WherePredicate::Type(pt) = pred {
                let bounded_ty = &pt.bounded_ty;
                if let Ok(ident) = parse2::<Ident>(quote!(#bounded_ty)) {
                    for tpb in pt.bounds.iter() {
                        save_fn_types(&ident, tpb);
                    }
                } else {
                    // We can't yet handle where clauses this complicated
                }
            }
        }
    }
    // Then remove those types from both the Generics' params and where clause
    let should_remove = |ident: &Ident| {
            let ty: Type = parse2(quote!(#ident)).unwrap();
            if hm.contains_key(&ty) {
                true
            } else {
                false
            }
    };
    let params = Punctuated::from_iter(gen.params.iter().filter(|g| {
        if let GenericParam::Type(tp) = g {
            !should_remove(&tp.ident)
        } else {
            true
        }
    }).cloned());
    let mut wc2 = gen.where_clause.clone();
    if let Some(wc) = &mut wc2 {
        wc.predicates = Punctuated::from_iter(wc.predicates.iter().filter(|wp| {
            if let WherePredicate::Type(pt) = wp {
                let bounded_ty = &pt.bounded_ty;
                if let Ok(ident) = parse2::<Ident>(quote!(#bounded_ty)) {
                    !should_remove(&ident)
                } else {
                    // We can't yet handle where clauses this complicated
                    true
                }
            } else {
                true
            }
        }).cloned());
    }
    let outg = Generics {
        lt_token: if params.is_empty() { None } else { gen.lt_token.clone() },
        gt_token: if params.is_empty() { None } else { gen.gt_token.clone() },
        params,
        where_clause: wc2
    };
    // Next substitute Box<Fn> into the arguments
    let outargs = Punctuated::from_iter(args.iter().map(|arg| {
        if let FnArg::Typed(pt) = arg {
            let mut immutable_pt = pt.clone();
            demutify_arg(&mut immutable_pt);
            if let Some(newty) = hm.get(&pt.ty) {
                FnArg::Typed(PatType {
                    attrs: Vec::default(),
                    pat: immutable_pt.pat,
                    colon_token: pt.colon_token.clone(),
                    ty: Box::new(newty.clone())
                })
            } else {
                FnArg::Typed(PatType {
                    attrs: Vec::default(),
                    pat: immutable_pt.pat,
                    colon_token: pt.colon_token.clone(),
                    ty: pt.ty.clone()
                })
            }
        } else {
            arg.clone()
        }
    }));
    // Finally, Box any closure arguments
    // use filter_map to remove the &self argument
    let callargs = Punctuated::from_iter(args.iter().filter_map(|arg| {
        match arg {
            FnArg::Typed(pt) => {
                let mut pt2 = pt.clone();
                demutify_arg(&mut pt2);
                let pat = &pt2.pat;
                if hm.contains_key(&pt.ty) {
                    Some(quote!(Box::new(#pat)))
                } else {
                    Some(quote!(#pat))
                }
            },
            FnArg::Receiver(_) => None,
        }
    }));
    (outg, outargs, callargs)
}
fn declosurefy ( gen : & Generics , args : & Punctuated < FnArg , Token ! [ ] > ) -> ( Generics , Punctuated < FnArg , Token ! [ ] > , Punctuated < TokenStream , Token ! [ ] > ) { let mut hm = HashMap :: new ( ) ; let mut save_fn_types = | ident : & Ident , tpb : & TypeParamBound | { if let TypeParamBound :: Trait ( tb ) = tpb { let fident = & tb . path . segments . last ( ) . unwrap ( ) . ident ; if [ " " , " " , " " ] . iter ( ) . any ( | s | fident == * s ) { let newty : Type = parse2 ( quote ! ( Box dyn tb ) ) . unwrap ( ) ; let subst_ty : Type = parse2 ( quote ! ( ident ) ) . unwrap ( ) ; assert ! ( hm insert ( subst_ty newty ) is_none ( ) " " ) ; } } } ; // First, build a HashMap of all Fn generic types for g in gen . params . iter ( ) { if let GenericParam :: Type ( tp ) = g { for tpb in tp . bounds . iter ( ) { save_fn_types ( & tp . ident , tpb ) ; } } } if let Some ( wc ) = & gen . where_clause { for pred in wc . predicates . iter ( ) { if let WherePredicate :: Type ( pt ) = pred { let bounded_ty = & pt . bounded_ty ; if let Ok ( ident ) = parse2 :: < Ident > ( quote ! ( bounded_ty ) ) { for tpb in pt . bounds . iter ( ) { save_fn_types ( & ident , tpb ) ; } } else { // We can't yet handle where clauses this complicated } } } } // Then remove those types from both the Generics' params and where clause let should_remove = | ident : & Ident | { let ty : Type = parse2 ( quote ! ( ident ) ) . unwrap ( ) ; if hm . contains_key ( & ty ) { true } else { false } } ; let params = Punctuated :: from_iter ( gen . params . iter ( ) . filter ( | g | { if let GenericParam :: Type ( tp ) = g { ! should_remove ( & tp . ident ) } else { true } } ) . cloned ( ) ) ; let mut wc2 = gen . where_clause . clone ( ) ; if let Some ( wc ) = & mut wc2 { wc . predicates = Punctuated :: from_iter ( wc . predicates . iter ( ) . filter ( | wp | { if let WherePredicate :: Type ( pt ) = wp { let bounded_ty = & pt . bounded_ty ; if let Ok ( ident ) = parse2 :: < Ident > ( quote ! ( bounded_ty ) ) { ! should_remove ( & ident ) } else { // We can't yet handle where clauses this complicated true } } else { true } } ) . cloned ( ) ) ; } let outg = Generics { lt_token : if params . is_empty ( ) { None } else { gen . lt_token . clone ( ) } , gt_token : if params . is_empty ( ) { None } else { gen . gt_token . clone ( ) } , params , where_clause : wc2 } ; // Next substitute Box<Fn> into the arguments let outargs = Punctuated :: from_iter ( args . iter ( ) . map ( | arg | { if let FnArg :: Typed ( pt ) = arg { let mut immutable_pt = pt . clone ( ) ; demutify_arg ( & mut immutable_pt ) ; if let Some ( newty ) = hm . get ( & pt . ty ) { FnArg :: Typed ( PatType { attrs : Vec :: default ( ) , pat : immutable_pt . pat , colon_token : pt . colon_token . clone ( ) , ty : Box :: new ( newty . clone ( ) ) } ) } else { FnArg :: Typed ( PatType { attrs : Vec :: default ( ) , pat : immutable_pt . pat , colon_token : pt . colon_token . clone ( ) , ty : pt . ty . clone ( ) } ) } } else { arg . clone ( ) } } ) ) ; // Finally, Box any closure arguments // use filter_map to remove the &self argument let callargs = Punctuated :: from_iter ( args . iter ( ) . filter_map ( | arg | { match arg { FnArg :: Typed ( pt ) => { let mut pt2 = pt . clone ( ) ; demutify_arg ( & mut pt2 ) ; let pat = & pt2 . pat ; if hm . contains_key ( & pt . ty ) { Some ( quote ! ( Box new ( pat ) ) ) } else { Some ( quote ! ( pat ) ) } } , FnArg :: Receiver ( _ ) => None , } } ) ) ; ( outg , outargs , callargs ) }
If there are any closures in the argument list, turn them into boxed
functions
If there are any closures in the argument list turn them into boxed functions
gen
&Generics
args
&Punctuated<FnArg, Token![,]>