From 44efb05edfcba3baf7a3abcf10085c7647a909ad Mon Sep 17 00:00:00 2001 From: varkor Date: Wed, 11 Apr 2018 15:16:54 +0100 Subject: [PATCH] Add cs_fold1 for better derives --- src/libsyntax_ext/deriving/generic/mod.rs | 109 ++++++++++++++++++---- 1 file changed, 92 insertions(+), 17 deletions(-) diff --git a/src/libsyntax_ext/deriving/generic/mod.rs b/src/libsyntax_ext/deriving/generic/mod.rs index 4126ce79f3555..11bd72691c568 100644 --- a/src/libsyntax_ext/deriving/generic/mod.rs +++ b/src/libsyntax_ext/deriving/generic/mod.rs @@ -1676,12 +1676,55 @@ impl<'a> TraitDef<'a> { // helpful premade recipes +pub fn cs_fold_fields<'a, F>(use_foldl: bool, + mut f: F, + base: P, + cx: &mut ExtCtxt, + all_fields: &[FieldInfo<'a>]) + -> P + where F: FnMut(&mut ExtCtxt, Span, P, P, &[P]) -> P +{ + if use_foldl { + all_fields.iter().fold(base, |old, field| { + f(cx, field.span, old, field.self_.clone(), &field.other) + }) + } else { + all_fields.iter().rev().fold(base, |old, field| { + f(cx, field.span, old, field.self_.clone(), &field.other) + }) + } +} + +pub fn cs_fold_enumnonmatch(mut enum_nonmatch_f: EnumNonMatchCollapsedFunc, + cx: &mut ExtCtxt, + trait_span: Span, + substructure: &Substructure) + -> P +{ + match *substructure.fields { + EnumNonMatchingCollapsed(ref all_args, _, tuple) => { + enum_nonmatch_f(cx, + trait_span, + (&all_args[..], tuple), + substructure.nonself_args) + } + _ => cx.span_bug(trait_span, "cs_fold_enumnonmatch expected an EnumNonMatchingCollapsed") + } +} + +pub fn cs_fold_static(cx: &mut ExtCtxt, + trait_span: Span) + -> P +{ + cx.span_bug(trait_span, "static function in `derive`") +} + /// Fold the fields. `use_foldl` controls whether this is done /// left-to-right (`true`) or right-to-left (`false`). pub fn cs_fold(use_foldl: bool, - mut f: F, + f: F, base: P, - mut enum_nonmatch_f: EnumNonMatchCollapsedFunc, + enum_nonmatch_f: EnumNonMatchCollapsedFunc, cx: &mut ExtCtxt, trait_span: Span, substructure: &Substructure) @@ -1691,26 +1734,58 @@ pub fn cs_fold(use_foldl: bool, match *substructure.fields { EnumMatching(.., ref all_fields) | Struct(_, ref all_fields) => { - if use_foldl { - all_fields.iter().fold(base, |old, field| { - f(cx, field.span, old, field.self_.clone(), &field.other) - }) - } else { - all_fields.iter().rev().fold(base, |old, field| { - f(cx, field.span, old, field.self_.clone(), &field.other) - }) - } + cs_fold_fields(use_foldl, f, base, cx, all_fields) } - EnumNonMatchingCollapsed(ref all_args, _, tuple) => { - enum_nonmatch_f(cx, - trait_span, - (&all_args[..], tuple), - substructure.nonself_args) + EnumNonMatchingCollapsed(..) => { + cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure) + } + StaticEnum(..) | StaticStruct(..) => { + cs_fold_static(cx, trait_span) } - StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"), } } +/// Special version of `cs_fold` that uses the result of a function call on the first field +/// as the base case when is at least 1 field, and the usual base case when there are zero fields. +pub fn cs_fold1(use_foldl: bool, + f: F, + mut b: B, + enum_nonmatch_f: EnumNonMatchCollapsedFunc, + cx: &mut ExtCtxt, + trait_span: Span, + substructure: &Substructure) + -> P + where F: FnMut(&mut ExtCtxt, Span, P, P, &[P]) -> P, + B: FnMut(&mut ExtCtxt, Option<(Span, P, &[P])>) -> P +{ + match *substructure.fields { + EnumMatching(.., ref all_fields) | + Struct(_, ref all_fields) => { + let (base, all_fields) = match (all_fields.is_empty(), use_foldl) { + (false, true) => { + let field = &all_fields[0]; + let args = (field.span, field.self_.clone(), &field.other[..]); + (b(cx, Some(args)), &all_fields[1..]) + } + (false, false) => { + let idx = all_fields.len() - 1; + let field = &all_fields[idx]; + let args = (field.span, field.self_.clone(), &field.other[..]); + (b(cx, Some(args)), &all_fields[..idx]) + } + (true, _) => (b(cx, None), &all_fields[..]) + }; + + cs_fold_fields(use_foldl, f, base, cx, all_fields) + } + EnumNonMatchingCollapsed(..) => { + cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure) + } + StaticEnum(..) | StaticStruct(..) => { + cs_fold_static(cx, trait_span) + } + } +} /// Call the method that is being derived on all the fields, and then /// process the collected results. i.e.