Use .take instead of mem::take().

This commit is contained in:
Stephen Chung 2023-04-21 10:20:19 +08:00
parent 2034ddd830
commit f49ce33a88
14 changed files with 72 additions and 57 deletions

View File

@ -19,6 +19,7 @@ New features
* It is now possible to require a specific _type_ to the `this` pointer for a particular script-defined function so that it is called only when the `this` pointer contains the specified type. * It is now possible to require a specific _type_ to the `this` pointer for a particular script-defined function so that it is called only when the `this` pointer contains the specified type.
* `is_def_fn` is extended to support checking for typed methods, with syntax `is_def_fn(this_type, fn_name, arity)` * `is_def_fn` is extended to support checking for typed methods, with syntax `is_def_fn(this_type, fn_name, arity)`
* `Dynamic::take` is added as a short-cut for `std::mem::take(&mut value)`.
Enhancements Enhancements
------------ ------------

View File

@ -124,7 +124,7 @@ impl Engine {
/// ///
/// To access a primary argument value (i.e. cloning is cheap), use: `args[n].as_xxx().unwrap()` /// To access a primary argument value (i.e. cloning is cheap), use: `args[n].as_xxx().unwrap()`
/// ///
/// To access an argument value and avoid cloning, use `std::mem::take(args[n]).cast::<T>()`. /// To access an argument value and avoid cloning, use `args[n].take().cast::<T>()`.
/// Notice that this will _consume_ the argument, replacing it with `()`. /// Notice that this will _consume_ the argument, replacing it with `()`.
/// ///
/// To access the first mutable parameter, use `args.get_mut(0).unwrap()` /// To access the first mutable parameter, use `args.get_mut(0).unwrap()`

View File

@ -16,6 +16,7 @@ use std::{
fmt::Write, fmt::Write,
hash::Hash, hash::Hash,
iter::once, iter::once,
mem,
num::{NonZeroU8, NonZeroUsize}, num::{NonZeroU8, NonZeroUsize},
}; };
@ -833,6 +834,11 @@ impl Expr {
Self::Property(..) => matches!(token, Token::LeftParen), Self::Property(..) => matches!(token, Token::LeftParen),
} }
} }
/// Return this [`Expr`], replacing it with [`Expr::Unit`].
#[inline(always)]
pub fn take(&mut self) -> Self {
mem::take(self)
}
/// Recursively walk this expression. /// Recursively walk this expression.
/// Return `false` from the callback to terminate the walk. /// Return `false` from the callback to terminate the walk.
pub fn walk<'a>( pub fn walk<'a>(

View File

@ -1036,6 +1036,11 @@ impl Stmt {
pub const fn is_control_flow_break(&self) -> bool { pub const fn is_control_flow_break(&self) -> bool {
matches!(self, Self::Return(..) | Self::BreakLoop(..)) matches!(self, Self::Return(..) | Self::BreakLoop(..))
} }
/// Return this [`Stmt`], replacing it with [`Stmt::Noop`].
#[inline(always)]
pub fn take(&mut self) -> Self {
mem::take(self)
}
/// Recursively walk this statement. /// Recursively walk this statement.
/// Return `false` from the callback to terminate the walk. /// Return `false` from the callback to terminate the walk.
pub fn walk<'a>( pub fn walk<'a>(

View File

@ -939,7 +939,7 @@ impl Engine {
if !val.is_shared() { if !val.is_shared() {
// Replace the variable with a shared value. // Replace the variable with a shared value.
*val = std::mem::take(val).into_shared(); *val = val.take().into_shared();
} }
} }

View File

@ -748,7 +748,7 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
return match op { return match op {
PlusAssign => Some(( PlusAssign => Some((
|_ctx, args| { |_ctx, args| {
let x = std::mem::take(args[1]).into_array().unwrap(); let x = args[1].take().into_array().unwrap();
if x.is_empty() { if x.is_empty() {
return Ok(Dynamic::UNIT); return Ok(Dynamic::UNIT);
@ -783,7 +783,7 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
return match op { return match op {
PlusAssign => Some(( PlusAssign => Some((
|_ctx, args| { |_ctx, args| {
let blob2 = std::mem::take(args[1]).into_blob().unwrap(); let blob2 = args[1].take().into_blob().unwrap();
let blob1 = &mut *args[0].write_lock::<Blob>().unwrap(); let blob1 = &mut *args[0].write_lock::<Blob>().unwrap();
#[cfg(not(feature = "unchecked"))] #[cfg(not(feature = "unchecked"))]
@ -931,7 +931,7 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
PlusAssign => Some(( PlusAssign => Some((
|_ctx, args| { |_ctx, args| {
{ {
let x = std::mem::take(args[1]); let x = args[1].take();
let array = &mut *args[0].write_lock::<Array>().unwrap(); let array = &mut *args[0].write_lock::<Array>().unwrap();
push(array, x); push(array, x);
} }

View File

@ -831,7 +831,7 @@ impl Engine {
} }
// FnPtr call on object // FnPtr call on object
let fn_ptr = mem::take(&mut call_args[0]).cast::<FnPtr>(); let fn_ptr = call_args[0].take().cast::<FnPtr>();
#[cfg(not(feature = "no_function"))] #[cfg(not(feature = "no_function"))]
let (fn_name, is_anon, fn_curry, _environ, fn_def) = { let (fn_name, is_anon, fn_curry, _environ, fn_def) = {

View File

@ -57,12 +57,12 @@ pub fn by_value<T: Variant + Clone>(data: &mut Dynamic) -> T {
} }
if TypeId::of::<T>() == TypeId::of::<String>() { if TypeId::of::<T>() == TypeId::of::<String>() {
// If T is `String`, data must be `ImmutableString`, so map directly to it // If T is `String`, data must be `ImmutableString`, so map directly to it
return reify! { mem::take(data).into_string().expect("`ImmutableString`") => T }; return reify! { data.take().into_string().expect("`ImmutableString`") => T };
} }
// We consume the argument and then replace it with () - the argument is not supposed to be used again. // We consume the argument and then replace it with () - the argument is not supposed to be used again.
// This way, we avoid having to clone the argument again, because it is already a clone when passed here. // This way, we avoid having to clone the argument again, because it is already a clone when passed here.
mem::take(data).cast::<T>() data.take().cast::<T>()
} }
/// Trait to register custom Rust functions. /// Trait to register custom Rust functions.

View File

@ -67,7 +67,7 @@ impl Engine {
// Put arguments into scope as variables // Put arguments into scope as variables
scope.extend(fn_def.params.iter().cloned().zip(args.iter_mut().map(|v| { scope.extend(fn_def.params.iter().cloned().zip(args.iter_mut().map(|v| {
// Actually consume the arguments instead of cloning them // Actually consume the arguments instead of cloning them
mem::take(*v) v.take()
}))); })));
// Push a new call stack frame // Push a new call stack frame

View File

@ -1204,7 +1204,7 @@ impl Module {
/// ///
/// To access a primary argument value (i.e. cloning is cheap), use: `args[n].as_xxx().unwrap()` /// To access a primary argument value (i.e. cloning is cheap), use: `args[n].as_xxx().unwrap()`
/// ///
/// To access an argument value and avoid cloning, use `std::mem::take(args[n]).cast::<T>()`. /// To access an argument value and avoid cloning, use `args[n].take().cast::<T>()`.
/// Notice that this will _consume_ the argument, replacing it with `()`. /// Notice that this will _consume_ the argument, replacing it with `()`.
/// ///
/// To access the first mutable argument, use `args.get_mut(0).unwrap()` /// To access the first mutable argument, use `args.get_mut(0).unwrap()`
@ -1227,7 +1227,7 @@ impl Module {
/// // 'args' is guaranteed to be the right length and of the correct types /// // 'args' is guaranteed to be the right length and of the correct types
/// ///
/// // Get the second parameter by 'consuming' it /// // Get the second parameter by 'consuming' it
/// let double = std::mem::take(args[1]).cast::<bool>(); /// let double = args[1].take().cast::<bool>();
/// // Since it is a primary type, it can also be cheaply copied /// // Since it is a primary type, it can also be cheaply copied
/// let double = args[1].clone_cast::<bool>(); /// let double = args[1].clone_cast::<bool>();
/// // Get a mutable reference to the first argument. /// // Get a mutable reference to the first argument.

View File

@ -184,7 +184,7 @@ fn optimize_stmt_block(
|s| matches!(s, Stmt::Block(block, ..) if !block.iter().any(Stmt::is_block_dependent)), |s| matches!(s, Stmt::Block(block, ..) if !block.iter().any(Stmt::is_block_dependent)),
) { ) {
let (first, second) = statements.split_at_mut(n); let (first, second) = statements.split_at_mut(n);
let stmt = mem::take(&mut second[0]); let stmt = second[0].take();
let mut stmts = match stmt { let mut stmts = match stmt {
Stmt::Block(block, ..) => block, Stmt::Block(block, ..) => block,
stmt => unreachable!("Stmt::Block expected but gets {:?}", stmt), stmt => unreachable!("Stmt::Block expected but gets {:?}", stmt),
@ -406,7 +406,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
Expr::FnCall(ref mut x2, pos) => { Expr::FnCall(ref mut x2, pos) => {
state.set_dirty(); state.set_dirty();
x.0 = OpAssignment::new_op_assignment_from_base(&x2.name, pos); x.0 = OpAssignment::new_op_assignment_from_base(&x2.name, pos);
x.1.rhs = mem::take(&mut x2.args[1]); x.1.rhs = x2.args[1].take();
} }
ref expr => unreachable!("Expr::FnCall expected but gets {:?}", expr), ref expr => unreachable!("Expr::FnCall expected but gets {:?}", expr),
} }
@ -426,7 +426,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
state.set_dirty(); state.set_dirty();
let pos = condition.start_position(); let pos = condition.start_position();
let mut expr = mem::take(condition); let mut expr = condition.take();
optimize_expr(&mut expr, state, false); optimize_expr(&mut expr, state, false);
*stmt = if preserve_result { *stmt = if preserve_result {
@ -456,7 +456,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
// if false { if_block } else { else_block } -> else_block // if false { if_block } else { else_block } -> else_block
Stmt::If(x, ..) if matches!(x.expr, Expr::BoolConstant(false, ..)) => { Stmt::If(x, ..) if matches!(x.expr, Expr::BoolConstant(false, ..)) => {
state.set_dirty(); state.set_dirty();
let body = mem::take(&mut *x.branch); let body = x.branch.take_statements();
*stmt = match optimize_stmt_block(body, state, preserve_result, true, false) { *stmt = match optimize_stmt_block(body, state, preserve_result, true, false) {
statements if statements.is_empty() => Stmt::Noop(x.branch.position()), statements if statements.is_empty() => Stmt::Noop(x.branch.position()),
statements => (statements, x.branch.span()).into(), statements => (statements, x.branch.span()).into(),
@ -465,7 +465,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
// if true { if_block } else { else_block } -> if_block // if true { if_block } else { else_block } -> if_block
Stmt::If(x, ..) if matches!(x.expr, Expr::BoolConstant(true, ..)) => { Stmt::If(x, ..) if matches!(x.expr, Expr::BoolConstant(true, ..)) => {
state.set_dirty(); state.set_dirty();
let body = mem::take(&mut *x.body); let body = x.body.take_statements();
*stmt = match optimize_stmt_block(body, state, preserve_result, true, false) { *stmt = match optimize_stmt_block(body, state, preserve_result, true, false) {
statements if statements.is_empty() => Stmt::Noop(x.body.position()), statements if statements.is_empty() => Stmt::Noop(x.body.position()),
statements => (statements, x.body.span()).into(), statements => (statements, x.body.span()).into(),
@ -475,9 +475,9 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
Stmt::If(x, ..) => { Stmt::If(x, ..) => {
let FlowControl { expr, body, branch } = &mut **x; let FlowControl { expr, body, branch } = &mut **x;
optimize_expr(expr, state, false); optimize_expr(expr, state, false);
let statements = mem::take(&mut **body); let statements = body.take_statements();
**body = optimize_stmt_block(statements, state, preserve_result, true, false); **body = optimize_stmt_block(statements, state, preserve_result, true, false);
let statements = mem::take(&mut **branch); let statements = branch.take_statements();
**branch = optimize_stmt_block(statements, state, preserve_result, true, false); **branch = optimize_stmt_block(statements, state, preserve_result, true, false);
} }
@ -508,7 +508,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
if b.is_always_true() { if b.is_always_true() {
// Promote the matched case // Promote the matched case
let mut statements = Stmt::Expr(mem::take(&mut b.expr).into()); let mut statements = Stmt::Expr(b.expr.take().into());
optimize_stmt(&mut statements, state, true); optimize_stmt(&mut statements, state, true);
*stmt = statements; *stmt = statements;
} else { } else {
@ -518,14 +518,14 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
let branch = match def_case { let branch = match def_case {
Some(index) => { Some(index) => {
let mut def_stmt = let mut def_stmt =
Stmt::Expr(mem::take(&mut expressions[*index].expr).into()); Stmt::Expr(expressions[*index].expr.take().into());
optimize_stmt(&mut def_stmt, state, true); optimize_stmt(&mut def_stmt, state, true);
def_stmt.into() def_stmt.into()
} }
_ => StmtBlock::NONE, _ => StmtBlock::NONE,
}; };
let body = Stmt::Expr(mem::take(&mut b.expr).into()).into(); let body = Stmt::Expr(b.expr.take().into()).into();
let expr = mem::take(&mut b.condition); let expr = b.condition.take();
*stmt = Stmt::If( *stmt = Stmt::If(
FlowControl { expr, body, branch }.into(), FlowControl { expr, body, branch }.into(),
@ -542,7 +542,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
if b.is_always_true() { if b.is_always_true() {
// Promote the matched case // Promote the matched case
let mut statements = Stmt::Expr(mem::take(&mut b.expr).into()); let mut statements = Stmt::Expr(b.expr.take().into());
optimize_stmt(&mut statements, state, true); optimize_stmt(&mut statements, state, true);
*stmt = statements; *stmt = statements;
state.set_dirty(); state.set_dirty();
@ -567,11 +567,11 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
if range_block.is_always_true() { if range_block.is_always_true() {
// Promote the matched case // Promote the matched case
let block = &mut expressions[r.index()]; let block = &mut expressions[r.index()];
let mut statements = Stmt::Expr(mem::take(&mut block.expr).into()); let mut statements = Stmt::Expr(block.expr.take().into());
optimize_stmt(&mut statements, state, true); optimize_stmt(&mut statements, state, true);
*stmt = statements; *stmt = statements;
} else { } else {
let mut expr = mem::take(&mut range_block.condition); let mut expr = range_block.condition.take();
// switch const { range if condition => stmt, _ => def } => if condition { stmt } else { def } // switch const { range if condition => stmt, _ => def } => if condition { stmt } else { def }
optimize_expr(&mut expr, state, false); optimize_expr(&mut expr, state, false);
@ -579,16 +579,14 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
let branch = match def_case { let branch = match def_case {
Some(index) => { Some(index) => {
let mut def_stmt = let mut def_stmt =
Stmt::Expr(mem::take(&mut expressions[*index].expr).into()); Stmt::Expr(expressions[*index].expr.take().into());
optimize_stmt(&mut def_stmt, state, true); optimize_stmt(&mut def_stmt, state, true);
def_stmt.into() def_stmt.into()
} }
_ => StmtBlock::NONE, _ => StmtBlock::NONE,
}; };
let body = let body = Stmt::Expr(expressions[r.index()].expr.take().into()).into();
Stmt::Expr(mem::take(&mut expressions[r.index()].expr).into())
.into();
*stmt = Stmt::If( *stmt = Stmt::If(
FlowControl { expr, body, branch }.into(), FlowControl { expr, body, branch }.into(),
@ -628,7 +626,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
match def_case { match def_case {
Some(index) => { Some(index) => {
let mut def_stmt = Stmt::Expr(mem::take(&mut expressions[*index].expr).into()); let mut def_stmt = Stmt::Expr(expressions[*index].expr.take().into());
optimize_stmt(&mut def_stmt, state, true); optimize_stmt(&mut def_stmt, state, true);
*stmt = def_stmt; *stmt = def_stmt;
} }
@ -738,17 +736,17 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
if let Expr::BoolConstant(true, pos) = expr { if let Expr::BoolConstant(true, pos) = expr {
*expr = Expr::Unit(*pos); *expr = Expr::Unit(*pos);
} }
**body = optimize_stmt_block(mem::take(&mut **body), state, false, true, false); **body = optimize_stmt_block(body.take_statements(), state, false, true, false);
} }
// do { block } while|until expr // do { block } while|until expr
Stmt::Do(x, ..) => { Stmt::Do(x, ..) => {
optimize_expr(&mut x.expr, state, false); optimize_expr(&mut x.expr, state, false);
*x.body = optimize_stmt_block(mem::take(&mut *x.body), state, false, true, false); *x.body = optimize_stmt_block(x.body.take_statements(), state, false, true, false);
} }
// for id in expr { block } // for id in expr { block }
Stmt::For(x, ..) => { Stmt::For(x, ..) => {
optimize_expr(&mut x.2.expr, state, false); optimize_expr(&mut x.2.expr, state, false);
*x.2.body = optimize_stmt_block(mem::take(&mut *x.2.body), state, false, true, false); *x.2.body = optimize_stmt_block(x.2.body.take_statements(), state, false, true, false);
} }
// let id = expr; // let id = expr;
Stmt::Var(x, options, ..) if !options.contains(ASTFlags::CONSTANT) => { Stmt::Var(x, options, ..) if !options.contains(ASTFlags::CONSTANT) => {
@ -771,7 +769,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
// Only one statement which is not block-dependent - promote // Only one statement which is not block-dependent - promote
[s] if !s.is_block_dependent() => { [s] if !s.is_block_dependent() => {
state.set_dirty(); state.set_dirty();
*stmt = mem::take(s); *stmt = s.take();
} }
_ => *stmt = (block, span).into(), _ => *stmt = (block, span).into(),
} }
@ -781,15 +779,15 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
// If try block is pure, there will never be any exceptions // If try block is pure, there will never be any exceptions
state.set_dirty(); state.set_dirty();
*stmt = ( *stmt = (
optimize_stmt_block(mem::take(&mut *x.body), state, false, true, false), optimize_stmt_block(x.body.take_statements(), state, false, true, false),
x.body.span(), x.body.span(),
) )
.into(); .into();
} }
// try { try_block } catch ( var ) { catch_block } // try { try_block } catch ( var ) { catch_block }
Stmt::TryCatch(x, ..) => { Stmt::TryCatch(x, ..) => {
*x.body = optimize_stmt_block(mem::take(&mut *x.body), state, false, true, false); *x.body = optimize_stmt_block(x.body.take_statements(), state, false, true, false);
*x.branch = optimize_stmt_block(mem::take(&mut *x.branch), state, false, true, false); *x.branch = optimize_stmt_block(x.branch.take_statements(), state, false, true, false);
} }
// expr(stmt) // expr(stmt)
@ -799,7 +797,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
Expr::Stmt(block) if !block.is_empty() => { Expr::Stmt(block) if !block.is_empty() => {
let mut stmt_block = *mem::take(block); let mut stmt_block = *mem::take(block);
*stmt_block = *stmt_block =
optimize_stmt_block(mem::take(&mut *stmt_block), state, true, true, false); optimize_stmt_block(stmt_block.take_statements(), state, true, true, false);
*stmt = stmt_block.into(); *stmt = stmt_block.into();
} }
Expr::Stmt(..) => *stmt = Stmt::Noop(expr.position()), Expr::Stmt(..) => *stmt = Stmt::Noop(expr.position()),
@ -810,7 +808,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
// expr(func()) // expr(func())
Stmt::Expr(expr) if matches!(**expr, Expr::FnCall(..)) => { Stmt::Expr(expr) if matches!(**expr, Expr::FnCall(..)) => {
state.set_dirty(); state.set_dirty();
match mem::take(expr.as_mut()) { match expr.take() {
Expr::FnCall(x, pos) => *stmt = Stmt::FnCall(x, pos), Expr::FnCall(x, pos) => *stmt = Stmt::FnCall(x, pos),
_ => unreachable!(), _ => unreachable!(),
} }
@ -820,7 +818,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
// func(...) // func(...)
Stmt::FnCall(..) => { Stmt::FnCall(..) => {
if let Stmt::FnCall(x, pos) = mem::take(stmt) { if let Stmt::FnCall(x, pos) = stmt.take() {
let mut expr = Expr::FnCall(x, pos); let mut expr = Expr::FnCall(x, pos);
optimize_expr(&mut expr, state, false); optimize_expr(&mut expr, state, false);
*stmt = match expr { *stmt = match expr {
@ -883,16 +881,16 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
} }
// { stmt; ... } - do not count promotion as dirty because it gets turned back into an array // { stmt; ... } - do not count promotion as dirty because it gets turned back into an array
Expr::Stmt(x) => { Expr::Stmt(x) => {
***x = optimize_stmt_block(mem::take(&mut **x), state, true, true, false); ***x = optimize_stmt_block(x.take_statements(), state, true, true, false);
// { Stmt(Expr) } - promote // { Stmt(Expr) } - promote
if let [ Stmt::Expr(e) ] = &mut ****x { state.set_dirty(); *expr = mem::take(e); } if let [ Stmt::Expr(e) ] = &mut ****x { state.set_dirty(); *expr = e.take(); }
} }
// ()?.rhs // ()?.rhs
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
Expr::Dot(x, options, ..) if options.contains(ASTFlags::NEGATED) && matches!(x.lhs, Expr::Unit(..)) => { Expr::Dot(x, options, ..) if options.contains(ASTFlags::NEGATED) && matches!(x.lhs, Expr::Unit(..)) => {
state.set_dirty(); state.set_dirty();
*expr = mem::take(&mut x.lhs); *expr = x.lhs.take();
} }
// lhs.rhs // lhs.rhs
#[cfg(not(feature = "no_object"))] #[cfg(not(feature = "no_object"))]
@ -935,7 +933,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
Expr::Index(x, options, ..) if options.contains(ASTFlags::NEGATED) && matches!(x.lhs, Expr::Unit(..)) => { Expr::Index(x, options, ..) if options.contains(ASTFlags::NEGATED) && matches!(x.lhs, Expr::Unit(..)) => {
state.set_dirty(); state.set_dirty();
*expr = mem::take(&mut x.lhs); *expr = x.lhs.take();
} }
// lhs[rhs] // lhs[rhs]
#[cfg(not(feature = "no_index"))] #[cfg(not(feature = "no_index"))]
@ -946,7 +944,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
// Array literal where everything is pure - promote the indexed item. // Array literal where everything is pure - promote the indexed item.
// All other items can be thrown away. // All other items can be thrown away.
state.set_dirty(); state.set_dirty();
let mut result = mem::take(&mut a[*i as usize]); let mut result = a[*i as usize].take();
result.set_position(*pos); result.set_position(*pos);
*expr = result; *expr = result;
} }
@ -956,7 +954,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
// All other items can be thrown away. // All other items can be thrown away.
state.set_dirty(); state.set_dirty();
let index = a.len() - i.unsigned_abs() as usize; let index = a.len() - i.unsigned_abs() as usize;
let mut result = mem::take(&mut a[index]); let mut result = a[index].take();
result.set_position(*pos); result.set_position(*pos);
*expr = result; *expr = result;
} }
@ -1018,7 +1016,7 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
// Merge consecutive strings // Merge consecutive strings
while n < x.len() - 1 { while n < x.len() - 1 {
match (mem::take(&mut x[n]), mem::take(&mut x[n+1])) { match (x[n].take(),x[n+1].take()) {
(Expr::StringConstant(mut s1, pos), Expr::StringConstant(s2, ..)) => { s1 += s2; x[n] = Expr::StringConstant(s1, pos); x.remove(n+1); state.set_dirty(); } (Expr::StringConstant(mut s1, pos), Expr::StringConstant(s2, ..)) => { s1 += s2; x[n] = Expr::StringConstant(s1, pos); x.remove(n+1); state.set_dirty(); }
(expr1, Expr::Unit(..)) => { x[n] = expr1; x.remove(n+1); state.set_dirty(); } (expr1, Expr::Unit(..)) => { x[n] = expr1; x.remove(n+1); state.set_dirty(); }
(Expr::Unit(..), expr2) => { x[n+1] = expr2; x.remove(n); state.set_dirty(); } (Expr::Unit(..), expr2) => { x[n+1] = expr2; x.remove(n); state.set_dirty(); }
@ -1051,34 +1049,34 @@ fn optimize_expr(expr: &mut Expr, state: &mut OptimizerState, _chaining: bool) {
// lhs && rhs // lhs && rhs
Expr::And(x, ..) => match (&mut x.lhs, &mut x.rhs) { Expr::And(x, ..) => match (&mut x.lhs, &mut x.rhs) {
// true && rhs -> rhs // true && rhs -> rhs
(Expr::BoolConstant(true, ..), rhs) => { state.set_dirty(); optimize_expr(rhs, state, false); *expr = mem::take(rhs); } (Expr::BoolConstant(true, ..), rhs) => { state.set_dirty(); optimize_expr(rhs, state, false); *expr = rhs.take(); }
// false && rhs -> false // false && rhs -> false
(Expr::BoolConstant(false, pos), ..) => { state.set_dirty(); *expr = Expr::BoolConstant(false, *pos); } (Expr::BoolConstant(false, pos), ..) => { state.set_dirty(); *expr = Expr::BoolConstant(false, *pos); }
// lhs && true -> lhs // lhs && true -> lhs
(lhs, Expr::BoolConstant(true, ..)) => { state.set_dirty(); optimize_expr(lhs, state, false); *expr = mem::take(lhs); } (lhs, Expr::BoolConstant(true, ..)) => { state.set_dirty(); optimize_expr(lhs, state, false); *expr = lhs.take(); }
// lhs && rhs // lhs && rhs
(lhs, rhs) => { optimize_expr(lhs, state, false); optimize_expr(rhs, state, false); } (lhs, rhs) => { optimize_expr(lhs, state, false); optimize_expr(rhs, state, false); }
}, },
// lhs || rhs // lhs || rhs
Expr::Or(ref mut x, ..) => match (&mut x.lhs, &mut x.rhs) { Expr::Or(ref mut x, ..) => match (&mut x.lhs, &mut x.rhs) {
// false || rhs -> rhs // false || rhs -> rhs
(Expr::BoolConstant(false, ..), rhs) => { state.set_dirty(); optimize_expr(rhs, state, false); *expr = mem::take(rhs); } (Expr::BoolConstant(false, ..), rhs) => { state.set_dirty(); optimize_expr(rhs, state, false); *expr = rhs.take(); }
// true || rhs -> true // true || rhs -> true
(Expr::BoolConstant(true, pos), ..) => { state.set_dirty(); *expr = Expr::BoolConstant(true, *pos); } (Expr::BoolConstant(true, pos), ..) => { state.set_dirty(); *expr = Expr::BoolConstant(true, *pos); }
// lhs || false // lhs || false
(lhs, Expr::BoolConstant(false, ..)) => { state.set_dirty(); optimize_expr(lhs, state, false); *expr = mem::take(lhs); } (lhs, Expr::BoolConstant(false, ..)) => { state.set_dirty(); optimize_expr(lhs, state, false); *expr = lhs.take(); }
// lhs || rhs // lhs || rhs
(lhs, rhs) => { optimize_expr(lhs, state, false); optimize_expr(rhs, state, false); } (lhs, rhs) => { optimize_expr(lhs, state, false); optimize_expr(rhs, state, false); }
}, },
// () ?? rhs -> rhs // () ?? rhs -> rhs
Expr::Coalesce(x, ..) if matches!(x.lhs, Expr::Unit(..)) => { Expr::Coalesce(x, ..) if matches!(x.lhs, Expr::Unit(..)) => {
state.set_dirty(); state.set_dirty();
*expr = mem::take(&mut x.rhs); *expr = x.rhs.take();
}, },
// lhs:constant ?? rhs -> lhs // lhs:constant ?? rhs -> lhs
Expr::Coalesce(x, ..) if x.lhs.is_constant() => { Expr::Coalesce(x, ..) if x.lhs.is_constant() => {
state.set_dirty(); state.set_dirty();
*expr = mem::take(&mut x.lhs); *expr = x.lhs.take();
}, },
// !true or !false // !true or !false
@ -1383,7 +1381,7 @@ impl Engine {
functions.into_iter().for_each(|fn_def| { functions.into_iter().for_each(|fn_def| {
let mut fn_def = crate::func::shared_take_or_clone(fn_def); let mut fn_def = crate::func::shared_take_or_clone(fn_def);
// Optimize the function body // Optimize the function body
let body = mem::take(&mut *fn_def.body); let body = fn_def.body.take_statements();
*fn_def.body = self.optimize_top_level(body, scope, lib2, optimization_level); *fn_def.body = self.optimize_top_level(body, scope, lib2, optimization_level);

View File

@ -1146,6 +1146,11 @@ impl Dynamic {
)), )),
} }
} }
/// Return this [`Dynamic`], replacing it with [`Dynamic::UNIT`].
#[inline(always)]
pub fn take(&mut self) -> Self {
mem::take(self)
}
/// Convert the [`Dynamic`] value into specific type. /// Convert the [`Dynamic`] value into specific type.
/// ///
/// Casting to a [`Dynamic`] just returns as is, but if it contains a shared value, /// Casting to a [`Dynamic`] just returns as is, but if it contains a shared value,

View File

@ -175,7 +175,7 @@ fn test_fn_ptr_raw() -> Result<(), Box<EvalAltResult>> {
TypeId::of::<INT>(), TypeId::of::<INT>(),
], ],
move |context, args| { move |context, args| {
let fp = std::mem::take(args[1]).cast::<FnPtr>(); let fp = args[1].take().cast::<FnPtr>();
let value = args[2].clone(); let value = args[2].clone();
let this_ptr = args.get_mut(0).unwrap(); let this_ptr = args.get_mut(0).unwrap();

View File

@ -16,8 +16,8 @@ fn test_fn_ptr_curry_call() -> Result<(), Box<EvalAltResult>> {
"call_with_arg", "call_with_arg",
[TypeId::of::<FnPtr>(), TypeId::of::<INT>()], [TypeId::of::<FnPtr>(), TypeId::of::<INT>()],
|context, args| { |context, args| {
let fn_ptr = std::mem::take(args[0]).cast::<FnPtr>(); let fn_ptr = args[0].take().cast::<FnPtr>();
fn_ptr.call_raw(&context, None, [std::mem::take(args[1])]) fn_ptr.call_raw(&context, None, [args[1].take()])
}, },
); );