in amzn-smt-ir-derive/src/lib.rs [203:270]
fn derive_iterate(s: &synstructure::Structure) -> TokenStream {
let smt_ir = smt_ir_crate_path();
#[allow(non_snake_case)]
let (Term, Logic, Iterate, Args) = (
quote!(#smt_ir::Term),
quote!(#smt_ir::Logic),
quote!(#smt_ir::term::args::Iterate),
quote!(#smt_ir::term::args::Arguments),
);
fn argument_iter_branches(
s: &synstructure::Structure,
mut iterate: impl FnMut(&synstructure::BindingInfo) -> TokenStream,
) -> TokenStream {
s.each_variant(|v| {
let mut bindings = (v.bindings().iter())
.skip_while(|field| index_array(&field.ast().ty).is_some())
.map(&mut iterate);
let mut iter = bindings
.next()
.unwrap_or_else(|| quote!(std::iter::empty()));
for new in bindings {
iter = quote!(#iter.chain(#new))
}
// TODO: instead of boxing, could also make an enum -- might be worth it
quote!(std::boxed::Box::new(#iter))
})
}
let mut where_clause = syn::WhereClause {
where_token: Default::default(),
predicates: Default::default(),
};
bound_argument_fields(
s,
&mut where_clause,
|ty| parse_quote!(#ty: #Iterate<'a, L>),
);
let args_branches = argument_iter_branches(s, |field| quote!(#Iterate::<L>::terms(#field)));
let into_args_branches =
argument_iter_branches(s, |field| quote!(#Iterate::<L>::into_terms(#field)));
s.gen_impl(quote! {
gen impl<'a, L: #Logic> #Iterate<'a, L> for @Self
#where_clause
{
type Terms = std::boxed::Box<dyn std::iter::Iterator<Item = &'a #Term<L>> + 'a>;
type IntoTerms = std::boxed::Box<dyn std::iter::Iterator<Item = #Term<L>> + 'a>;
fn terms(&'a self) -> Self::Terms {
match self {
#args_branches
}
}
fn into_terms(self) -> Self::IntoTerms {
match self {
#into_args_branches
}
}
}
gen impl<'a, L: #Logic> #Args<'a, L> for @Self #where_clause {}
})
}