Skip to content

Commit 44efb05

Browse files
committed
Add cs_fold1 for better derives
1 parent 59ee333 commit 44efb05

File tree

1 file changed

+92
-17
lines changed
  • src/libsyntax_ext/deriving/generic

1 file changed

+92
-17
lines changed

src/libsyntax_ext/deriving/generic/mod.rs

Lines changed: 92 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -1676,12 +1676,55 @@ impl<'a> TraitDef<'a> {
16761676

16771677
// helpful premade recipes
16781678

1679+
pub fn cs_fold_fields<'a, F>(use_foldl: bool,
1680+
mut f: F,
1681+
base: P<Expr>,
1682+
cx: &mut ExtCtxt,
1683+
all_fields: &[FieldInfo<'a>])
1684+
-> P<Expr>
1685+
where F: FnMut(&mut ExtCtxt, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>
1686+
{
1687+
if use_foldl {
1688+
all_fields.iter().fold(base, |old, field| {
1689+
f(cx, field.span, old, field.self_.clone(), &field.other)
1690+
})
1691+
} else {
1692+
all_fields.iter().rev().fold(base, |old, field| {
1693+
f(cx, field.span, old, field.self_.clone(), &field.other)
1694+
})
1695+
}
1696+
}
1697+
1698+
pub fn cs_fold_enumnonmatch(mut enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1699+
cx: &mut ExtCtxt,
1700+
trait_span: Span,
1701+
substructure: &Substructure)
1702+
-> P<Expr>
1703+
{
1704+
match *substructure.fields {
1705+
EnumNonMatchingCollapsed(ref all_args, _, tuple) => {
1706+
enum_nonmatch_f(cx,
1707+
trait_span,
1708+
(&all_args[..], tuple),
1709+
substructure.nonself_args)
1710+
}
1711+
_ => cx.span_bug(trait_span, "cs_fold_enumnonmatch expected an EnumNonMatchingCollapsed")
1712+
}
1713+
}
1714+
1715+
pub fn cs_fold_static(cx: &mut ExtCtxt,
1716+
trait_span: Span)
1717+
-> P<Expr>
1718+
{
1719+
cx.span_bug(trait_span, "static function in `derive`")
1720+
}
1721+
16791722
/// Fold the fields. `use_foldl` controls whether this is done
16801723
/// left-to-right (`true`) or right-to-left (`false`).
16811724
pub fn cs_fold<F>(use_foldl: bool,
1682-
mut f: F,
1725+
f: F,
16831726
base: P<Expr>,
1684-
mut enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1727+
enum_nonmatch_f: EnumNonMatchCollapsedFunc,
16851728
cx: &mut ExtCtxt,
16861729
trait_span: Span,
16871730
substructure: &Substructure)
@@ -1691,26 +1734,58 @@ pub fn cs_fold<F>(use_foldl: bool,
16911734
match *substructure.fields {
16921735
EnumMatching(.., ref all_fields) |
16931736
Struct(_, ref all_fields) => {
1694-
if use_foldl {
1695-
all_fields.iter().fold(base, |old, field| {
1696-
f(cx, field.span, old, field.self_.clone(), &field.other)
1697-
})
1698-
} else {
1699-
all_fields.iter().rev().fold(base, |old, field| {
1700-
f(cx, field.span, old, field.self_.clone(), &field.other)
1701-
})
1702-
}
1737+
cs_fold_fields(use_foldl, f, base, cx, all_fields)
17031738
}
1704-
EnumNonMatchingCollapsed(ref all_args, _, tuple) => {
1705-
enum_nonmatch_f(cx,
1706-
trait_span,
1707-
(&all_args[..], tuple),
1708-
substructure.nonself_args)
1739+
EnumNonMatchingCollapsed(..) => {
1740+
cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure)
1741+
}
1742+
StaticEnum(..) | StaticStruct(..) => {
1743+
cs_fold_static(cx, trait_span)
17091744
}
1710-
StaticEnum(..) | StaticStruct(..) => cx.span_bug(trait_span, "static function in `derive`"),
17111745
}
17121746
}
17131747

1748+
/// Special version of `cs_fold` that uses the result of a function call on the first field
1749+
/// as the base case when is at least 1 field, and the usual base case when there are zero fields.
1750+
pub fn cs_fold1<F, B>(use_foldl: bool,
1751+
f: F,
1752+
mut b: B,
1753+
enum_nonmatch_f: EnumNonMatchCollapsedFunc,
1754+
cx: &mut ExtCtxt,
1755+
trait_span: Span,
1756+
substructure: &Substructure)
1757+
-> P<Expr>
1758+
where F: FnMut(&mut ExtCtxt, Span, P<Expr>, P<Expr>, &[P<Expr>]) -> P<Expr>,
1759+
B: FnMut(&mut ExtCtxt, Option<(Span, P<Expr>, &[P<Expr>])>) -> P<Expr>
1760+
{
1761+
match *substructure.fields {
1762+
EnumMatching(.., ref all_fields) |
1763+
Struct(_, ref all_fields) => {
1764+
let (base, all_fields) = match (all_fields.is_empty(), use_foldl) {
1765+
(false, true) => {
1766+
let field = &all_fields[0];
1767+
let args = (field.span, field.self_.clone(), &field.other[..]);
1768+
(b(cx, Some(args)), &all_fields[1..])
1769+
}
1770+
(false, false) => {
1771+
let idx = all_fields.len() - 1;
1772+
let field = &all_fields[idx];
1773+
let args = (field.span, field.self_.clone(), &field.other[..]);
1774+
(b(cx, Some(args)), &all_fields[..idx])
1775+
}
1776+
(true, _) => (b(cx, None), &all_fields[..])
1777+
};
1778+
1779+
cs_fold_fields(use_foldl, f, base, cx, all_fields)
1780+
}
1781+
EnumNonMatchingCollapsed(..) => {
1782+
cs_fold_enumnonmatch(enum_nonmatch_f, cx, trait_span, substructure)
1783+
}
1784+
StaticEnum(..) | StaticStruct(..) => {
1785+
cs_fold_static(cx, trait_span)
1786+
}
1787+
}
1788+
}
17141789

17151790
/// Call the method that is being derived on all the fields, and then
17161791
/// process the collected results. i.e.

0 commit comments

Comments
 (0)