@@ -1680,12 +1680,55 @@ impl<'a> TraitDef<'a> {
16801680
16811681// helpful premade recipes
16821682
1683+ pub fn cs_fold_fields < ' a , F > ( use_foldl : bool ,
1684+ mut f : F ,
1685+ base : P < Expr > ,
1686+ cx : & mut ExtCtxt ,
1687+ all_fields : & [ FieldInfo < ' a > ] )
1688+ -> P < Expr >
1689+ where F : FnMut ( & mut ExtCtxt , Span , P < Expr > , P < Expr > , & [ P < Expr > ] ) -> P < Expr >
1690+ {
1691+ if use_foldl {
1692+ all_fields. iter ( ) . fold ( base, |old, field| {
1693+ f ( cx, field. span , old, field. self_ . clone ( ) , & field. other )
1694+ } )
1695+ } else {
1696+ all_fields. iter ( ) . rev ( ) . fold ( base, |old, field| {
1697+ f ( cx, field. span , old, field. self_ . clone ( ) , & field. other )
1698+ } )
1699+ }
1700+ }
1701+
1702+ pub fn cs_fold_enumnonmatch ( mut enum_nonmatch_f : EnumNonMatchCollapsedFunc ,
1703+ cx : & mut ExtCtxt ,
1704+ trait_span : Span ,
1705+ substructure : & Substructure )
1706+ -> P < Expr >
1707+ {
1708+ match * substructure. fields {
1709+ EnumNonMatchingCollapsed ( ref all_args, _, tuple) => {
1710+ enum_nonmatch_f ( cx,
1711+ trait_span,
1712+ ( & all_args[ ..] , tuple) ,
1713+ substructure. nonself_args )
1714+ }
1715+ _ => cx. span_bug ( trait_span, "cs_fold_enumnonmatch expected an EnumNonMatchingCollapsed" )
1716+ }
1717+ }
1718+
1719+ pub fn cs_fold_static ( cx : & mut ExtCtxt ,
1720+ trait_span : Span )
1721+ -> P < Expr >
1722+ {
1723+ cx. span_bug ( trait_span, "static function in `derive`" )
1724+ }
1725+
16831726/// Fold the fields. `use_foldl` controls whether this is done
16841727/// left-to-right (`true`) or right-to-left (`false`).
16851728pub fn cs_fold < F > ( use_foldl : bool ,
1686- mut f : F ,
1729+ f : F ,
16871730 base : P < Expr > ,
1688- mut enum_nonmatch_f : EnumNonMatchCollapsedFunc ,
1731+ enum_nonmatch_f : EnumNonMatchCollapsedFunc ,
16891732 cx : & mut ExtCtxt ,
16901733 trait_span : Span ,
16911734 substructure : & Substructure )
@@ -1695,26 +1738,65 @@ pub fn cs_fold<F>(use_foldl: bool,
16951738 match * substructure. fields {
16961739 EnumMatching ( .., ref all_fields) |
16971740 Struct ( _, ref all_fields) => {
1698- if use_foldl {
1699- all_fields. iter ( ) . fold ( base, |old, field| {
1700- f ( cx, field. span , old, field. self_ . clone ( ) , & field. other )
1701- } )
1702- } else {
1703- all_fields. iter ( ) . rev ( ) . fold ( base, |old, field| {
1704- f ( cx, field. span , old, field. self_ . clone ( ) , & field. other )
1705- } )
1706- }
1741+ cs_fold_fields ( use_foldl, f, base, cx, all_fields)
17071742 }
1708- EnumNonMatchingCollapsed ( ref all_args , _ , tuple ) => {
1709- enum_nonmatch_f ( cx,
1710- trait_span ,
1711- ( & all_args [ .. ] , tuple ) ,
1712- substructure . nonself_args )
1743+ EnumNonMatchingCollapsed ( .. ) => {
1744+ cs_fold_enumnonmatch ( enum_nonmatch_f , cx, trait_span , substructure )
1745+ }
1746+ StaticEnum ( .. ) | StaticStruct ( .. ) => {
1747+ cs_fold_static ( cx , trait_span )
17131748 }
1714- StaticEnum ( ..) | StaticStruct ( ..) => cx. span_bug ( trait_span, "static function in `derive`" ) ,
17151749 }
17161750}
17171751
1752+ /// Function to fold over fields, with three cases, to generate more efficient and concise code.
1753+ /// When the `substructure` has grouped fields, there are two cases:
1754+ /// Zero fields: call the base case function with None (like the usual base case of `cs_fold`).
1755+ /// One or more fields: call the base case function on the first value (which depends on
1756+ /// `use_fold`), and use that as the base case. Then perform `cs_fold` on the remainder of the
1757+ /// fields.
1758+ /// When the `substructure` is a `EnumNonMatchingCollapsed`, the result of `enum_nonmatch_f`
1759+ /// is returned. Statics may not be folded over.
1760+ /// See `cs_op` in `partial_ord.rs` for a model example.
1761+ pub fn cs_fold1 < F , B > ( use_foldl : bool ,
1762+ f : F ,
1763+ mut b : B ,
1764+ enum_nonmatch_f : EnumNonMatchCollapsedFunc ,
1765+ cx : & mut ExtCtxt ,
1766+ trait_span : Span ,
1767+ substructure : & Substructure )
1768+ -> P < Expr >
1769+ where F : FnMut ( & mut ExtCtxt , Span , P < Expr > , P < Expr > , & [ P < Expr > ] ) -> P < Expr > ,
1770+ B : FnMut ( & mut ExtCtxt , Option < ( Span , P < Expr > , & [ P < Expr > ] ) > ) -> P < Expr >
1771+ {
1772+ match * substructure. fields {
1773+ EnumMatching ( .., ref all_fields) |
1774+ Struct ( _, ref all_fields) => {
1775+ let ( base, all_fields) = match ( all_fields. is_empty ( ) , use_foldl) {
1776+ ( false , true ) => {
1777+ let field = & all_fields[ 0 ] ;
1778+ let args = ( field. span , field. self_ . clone ( ) , & field. other [ ..] ) ;
1779+ ( b ( cx, Some ( args) ) , & all_fields[ 1 ..] )
1780+ }
1781+ ( false , false ) => {
1782+ let idx = all_fields. len ( ) - 1 ;
1783+ let field = & all_fields[ idx] ;
1784+ let args = ( field. span , field. self_ . clone ( ) , & field. other [ ..] ) ;
1785+ ( b ( cx, Some ( args) ) , & all_fields[ ..idx] )
1786+ }
1787+ ( true , _) => ( b ( cx, None ) , & all_fields[ ..] )
1788+ } ;
1789+
1790+ cs_fold_fields ( use_foldl, f, base, cx, all_fields)
1791+ }
1792+ EnumNonMatchingCollapsed ( ..) => {
1793+ cs_fold_enumnonmatch ( enum_nonmatch_f, cx, trait_span, substructure)
1794+ }
1795+ StaticEnum ( ..) | StaticStruct ( ..) => {
1796+ cs_fold_static ( cx, trait_span)
1797+ }
1798+ }
1799+ }
17181800
17191801/// Call the method that is being derived on all the fields, and then
17201802/// process the collected results. i.e.
0 commit comments