Skip to content

Commit

Permalink
Add cs_fold1 for better derives
Browse files Browse the repository at this point in the history
  • Loading branch information
varkor committed Apr 11, 2018
1 parent 59ee333 commit 44efb05
Showing 1 changed file with 92 additions and 17 deletions.
109 changes: 92 additions & 17 deletions src/libsyntax_ext/deriving/generic/mod.rs
Expand Up @@ -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<Expr>,
cx: &mut ExtCtxt,
all_fields: &[FieldInfo<'a>])
-> P<Expr>
where F: FnMut(&mut ExtCtxt, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>
{
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<Expr>
{
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<Expr>
{
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<F>(use_foldl: bool,
mut f: F,
f: F,
base: P<Expr>,
mut enum_nonmatch_f: EnumNonMatchCollapsedFunc,
enum_nonmatch_f: EnumNonMatchCollapsedFunc,
cx: &mut ExtCtxt,
trait_span: Span,
substructure: &Substructure)
Expand All @@ -1691,26 +1734,58 @@ pub fn cs_fold<F>(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<F, B>(use_foldl: bool,
f: F,
mut b: B,
enum_nonmatch_f: EnumNonMatchCollapsedFunc,
cx: &mut ExtCtxt,
trait_span: Span,
substructure: &Substructure)
-> P<Expr>
where F: FnMut(&mut ExtCtxt, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>,
B: FnMut(&mut ExtCtxt, Option<(Span, P<Expr>, &[P<Expr>])>) -> P<Expr>
{
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.
Expand Down

0 comments on commit 44efb05

Please sign in to comment.