Fixup ArgBackup.

This commit is contained in:
Stephen Chung 2022-03-14 08:26:27 +08:00
parent 963af0653e
commit a704d26986

View File

@ -37,6 +37,7 @@ struct ArgBackup<'a> {
impl<'a> ArgBackup<'a> { impl<'a> ArgBackup<'a> {
/// Create a new `ArgBackup`. /// Create a new `ArgBackup`.
#[inline(always)]
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
orig_mut: None, orig_mut: None,
@ -60,8 +61,8 @@ impl<'a> ArgBackup<'a> {
/// # Panics /// # Panics
/// ///
/// Panics when `args` is empty. /// Panics when `args` is empty.
#[inline] #[inline(always)]
fn change_first_arg_to_copy(&mut self, args: &mut FnCallArgs<'a>) { pub fn change_first_arg_to_copy(&mut self, args: &mut FnCallArgs<'a>) {
// Clone the original value. // Clone the original value.
self.value_copy = args[0].clone(); self.value_copy = args[0].clone();
@ -86,7 +87,7 @@ impl<'a> ArgBackup<'a> {
/// If `change_first_arg_to_copy` has been called, this function **MUST** be called _BEFORE_ /// If `change_first_arg_to_copy` has been called, this function **MUST** be called _BEFORE_
/// exiting the current scope. Otherwise it is undefined behavior as the shorter lifetime will leak. /// exiting the current scope. Otherwise it is undefined behavior as the shorter lifetime will leak.
#[inline(always)] #[inline(always)]
fn restore_first_arg(mut self, args: &mut FnCallArgs<'a>) { pub fn restore_first_arg(mut self, args: &mut FnCallArgs<'a>) {
if let Some(p) = self.orig_mut.take() { if let Some(p) = self.orig_mut.take() {
args[0] = p; args[0] = p;
} }
@ -94,7 +95,7 @@ impl<'a> ArgBackup<'a> {
} }
impl Drop for ArgBackup<'_> { impl Drop for ArgBackup<'_> {
#[inline] #[inline(always)]
fn drop(&mut self) { fn drop(&mut self) {
// Panic if the shorter lifetime leaks. // Panic if the shorter lifetime leaks.
assert!( assert!(
@ -382,15 +383,12 @@ impl Engine {
let mut _result = if let Some(FnResolutionCacheEntry { func, source }) = func { let mut _result = if let Some(FnResolutionCacheEntry { func, source }) = func {
assert!(func.is_native()); assert!(func.is_native());
let mut backup = ArgBackup::new();
// Calling pure function but the first argument is a reference? // Calling pure function but the first argument is a reference?
let mut backup: Option<ArgBackup> = None;
if is_ref_mut && func.is_pure() && !args.is_empty() { if is_ref_mut && func.is_pure() && !args.is_empty() {
// Clone the first argument // Clone the first argument
backup = Some(ArgBackup::new()); backup.change_first_arg_to_copy(args);
backup
.as_mut()
.expect("`Some`")
.change_first_arg_to_copy(args);
} }
let source = match (source.as_str(), parent_source.as_str()) { let source = match (source.as_str(), parent_source.as_str()) {
@ -420,9 +418,7 @@ impl Engine {
}; };
// Restore the original reference // Restore the original reference
if let Some(bk) = backup { backup.restore_first_arg(args);
bk.restore_first_arg(args)
}
result result
} else { } else {
@ -711,7 +707,7 @@ impl Engine {
// Method call of script function - map first argument to `this` // Method call of script function - map first argument to `this`
let (first_arg, rest_args) = args.split_first_mut().unwrap(); let (first_arg, rest_args) = args.split_first_mut().unwrap();
let result = self.call_script_fn( self.call_script_fn(
scope, scope,
global, global,
state, state,
@ -722,19 +718,14 @@ impl Engine {
true, true,
pos, pos,
level, level,
); )
result?
} else { } else {
// Normal call of script function // Normal call of script function
let mut backup = ArgBackup::new();
// The first argument is a reference? // The first argument is a reference?
let mut backup: Option<ArgBackup> = None;
if is_ref_mut && !args.is_empty() { if is_ref_mut && !args.is_empty() {
backup = Some(ArgBackup::new()); backup.change_first_arg_to_copy(args);
backup
.as_mut()
.expect("`Some`")
.change_first_arg_to_copy(args);
} }
let result = self.call_script_fn( let result = self.call_script_fn(
@ -742,17 +733,15 @@ impl Engine {
); );
// Restore the original reference // Restore the original reference
if let Some(bk) = backup { backup.restore_first_arg(args);
bk.restore_first_arg(args)
}
result? result
}; };
// Restore the original source // Restore the original source
mem::swap(&mut global.source, &mut source); mem::swap(&mut global.source, &mut source);
return Ok((result, false)); return Ok((result?, false));
} }
// Native function call // Native function call