impl<'a, 'b> Folder for InvocationCollector<'a, 'b> {
fn fold_expr(&mut self, expr: P<ast::Expr>) -> P<ast::Expr> {
- let mut expr = self.cfg.configure_expr(expr).into_inner();
- expr.node = self.cfg.configure_expr_kind(expr.node);
-
- // ignore derives so they remain unused
- let (attr, expr, after_derive) = self.classify_nonitem(expr);
-
- if attr.is_some() {
- // collect the invoc regardless of whether or not attributes are permitted here
- // expansion will eat the attribute so it won't error later
- attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));
-
- // AstFragmentKind::Expr requires the macro to emit an expression
- return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
- AstFragmentKind::Expr, after_derive).make_expr();
- }
+ let expr = self.cfg.configure_expr(expr);
+ expr.map(|mut expr| {
+ expr.node = self.cfg.configure_expr_kind(expr.node);
+
+ // ignore derives so they remain unused
+ let (attr, expr, after_derive) = self.classify_nonitem(expr);
+
+ if attr.is_some() {
+ // Collect the invoc regardless of whether or not attributes are permitted here
+ // expansion will eat the attribute so it won't error later.
+ attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));
+
+ // AstFragmentKind::Expr requires the macro to emit an expression.
+ return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
+ AstFragmentKind::Expr, after_derive)
+ .make_expr()
+ .into_inner()
+ }
- if let ast::ExprKind::Mac(mac) = expr.node {
- self.check_attributes(&expr.attrs);
- self.collect_bang(mac, expr.span, AstFragmentKind::Expr).make_expr()
- } else {
- P(noop_fold_expr(expr, self))
- }
+ if let ast::ExprKind::Mac(mac) = expr.node {
+ self.check_attributes(&expr.attrs);
+ self.collect_bang(mac, expr.span, AstFragmentKind::Expr)
+ .make_expr()
+ .into_inner()
+ } else {
+ noop_fold_expr(expr, self)
+ }
+ })
}
fn fold_opt_expr(&mut self, expr: P<ast::Expr>) -> Option<P<ast::Expr>> {
- let mut expr = configure!(self, expr).into_inner();
- expr.node = self.cfg.configure_expr_kind(expr.node);
+ let expr = configure!(self, expr);
+ expr.filter_map(|mut expr| {
+ expr.node = self.cfg.configure_expr_kind(expr.node);
- // ignore derives so they remain unused
- let (attr, expr, after_derive) = self.classify_nonitem(expr);
+ // Ignore derives so they remain unused.
+ let (attr, expr, after_derive) = self.classify_nonitem(expr);
- if attr.is_some() {
- attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));
+ if attr.is_some() {
+ attr.as_ref().map(|a| self.cfg.maybe_emit_expr_attr_err(a));
- return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
- AstFragmentKind::OptExpr, after_derive).make_opt_expr();
- }
+ return self.collect_attr(attr, vec![], Annotatable::Expr(P(expr)),
+ AstFragmentKind::OptExpr, after_derive)
+ .make_opt_expr()
+ .map(|expr| expr.into_inner())
+ }
- if let ast::ExprKind::Mac(mac) = expr.node {
- self.check_attributes(&expr.attrs);
- self.collect_bang(mac, expr.span, AstFragmentKind::OptExpr).make_opt_expr()
- } else {
- Some(P(noop_fold_expr(expr, self)))
- }
+ if let ast::ExprKind::Mac(mac) = expr.node {
+ self.check_attributes(&expr.attrs);
+ self.collect_bang(mac, expr.span, AstFragmentKind::OptExpr)
+ .make_opt_expr()
+ .map(|expr| expr.into_inner())
+ } else {
+ Some(noop_fold_expr(expr, self))
+ }
+ })
}
fn fold_pat(&mut self, pat: P<ast::Pat>) -> P<ast::Pat> {
*self.ptr
}
- /// Transform the inner value, consuming `self` and producing a new `P<T>`.
+ /// Produce a new `P<T>` from `self` without reallocating.
pub fn map<F>(mut self, f: F) -> P<T> where
F: FnOnce(T) -> T,
{
ptr::write(p, f(ptr::read(p)));
// Recreate self from the raw pointer.
- P {
- ptr: Box::from_raw(p)
+ P { ptr: Box::from_raw(p) }
+ }
+ }
+
+ /// Optionally produce a new `P<T>` from `self` without reallocating.
+ pub fn filter_map<F>(mut self, f: F) -> Option<P<T>> where
+ F: FnOnce(T) -> Option<T>,
+ {
+ let p: *mut T = &mut *self.ptr;
+
+ // Leak self in case of panic.
+ // FIXME(eddyb) Use some sort of "free guard" that
+ // only deallocates, without dropping the pointee,
+ // in case the call the `f` below ends in a panic.
+ mem::forget(self);
+
+ unsafe {
+ if let Some(v) = f(ptr::read(p)) {
+ ptr::write(p, v);
+
+ // Recreate self from the raw pointer.
+ Some(P { ptr: Box::from_raw(p) })
+ } else {
+ None
}
}
}