use nom::branch::alt; use nom::bytes::complete::{tag, take_till}; use nom::character::complete::char; use nom::combinator::{cut, map, not, opt, peek, recognize}; use nom::multi::{fold_many0, many0, separated_list0, separated_list1}; use nom::sequence::{delimited, pair, preceded, terminated, tuple}; use nom::IResult;
/// Returns `true` if enough assumptions can be made, /// to determine that `self` is copyable. pub(crate) fn is_copyable(&self) -> bool { self.is_copyable_within_op(false)
}
fn is_copyable_within_op(&self, within_op: bool) -> bool { use Expr::*; matchself {
BoolLit(_) | NumLit(_) | StrLit(_) | CharLit(_) => true,
Unary(.., expr) => expr.is_copyable_within_op(true),
BinOp(_, lhs, rhs) => {
lhs.is_copyable_within_op(true) && rhs.is_copyable_within_op(true)
}
Range(..) => true, // The result of a call likely doesn't need to be borrowed, // as in that case the call is more likely to return a // reference in the first place then.
Call(..) | Path(..) => true, // If the `expr` is within a `Unary` or `BinOp` then // an assumption can be made that the operand is copy. // If not, then the value is moved and adding `.clone()` // will solve that issue. However, if the operand is // implicitly borrowed, then it's likely not even possible // to get the template to compile.
_ => within_op && self.is_attr_self(),
}
}
/// Returns `true` if this is an `Attr` where the `obj` is `"self"`. pub(crate) fn is_attr_self(&self) -> bool { matchself {
Expr::Attr(obj, _) if matches!(obj.as_ref(), Expr::Var("self")) => true,
Expr::Attr(obj, _) if matches!(obj.as_ref(), Expr::Attr(..)) => obj.is_attr_self(),
_ => false,
}
}
/// Returns `true` if the outcome of this expression may be used multiple times in the same /// `write!()` call, without evaluating the expression again, i.e. the expression should be /// side-effect free. pub(crate) fn is_cacheable(&self) -> bool { matchself { // Literals are the definition of pure:
Expr::BoolLit(_) => true,
Expr::NumLit(_) => true,
Expr::StrLit(_) => true,
Expr::CharLit(_) => true, // fmt::Display should have no effects:
Expr::Var(_) => true,
Expr::Path(_) => true, // Check recursively:
Expr::Array(args) => args.iter().all(|arg| arg.is_cacheable()),
Expr::Attr(lhs, _) => lhs.is_cacheable(),
Expr::Index(lhs, rhs) => lhs.is_cacheable() && rhs.is_cacheable(),
Expr::Filter(_, args) => args.iter().all(|arg| arg.is_cacheable()),
Expr::Unary(_, arg) => arg.is_cacheable(),
Expr::BinOp(_, lhs, rhs) => lhs.is_cacheable() && rhs.is_cacheable(),
Expr::Range(_, lhs, rhs) => {
lhs.as_ref().map_or(true, |v| v.is_cacheable())
&& rhs.as_ref().map_or(true, |v| v.is_cacheable())
}
Expr::Group(arg) => arg.is_cacheable(),
Expr::Tuple(args) => args.iter().all(|arg| arg.is_cacheable()), // We have too little information to tell if the expression is pure:
Expr::Call(_, _) => false,
Expr::RustMacro(_, _) => false,
Expr::Try(_) => false,
}
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.