Copy values differently.
This commit is contained in:
parent
800a7bf283
commit
3408086240
@ -8,7 +8,7 @@ use crate::module::Module;
|
|||||||
use crate::optimize::OptimizationLevel;
|
use crate::optimize::OptimizationLevel;
|
||||||
use crate::packages::{CorePackage, Package, PackageLibrary, PackagesCollection, StandardPackage};
|
use crate::packages::{CorePackage, Package, PackageLibrary, PackagesCollection, StandardPackage};
|
||||||
use crate::parser::{Expr, FnAccess, FnDef, ReturnType, Stmt, AST};
|
use crate::parser::{Expr, FnAccess, FnDef, ReturnType, Stmt, AST};
|
||||||
use crate::r#unsafe::unsafe_cast_var_name_to_lifetime;
|
use crate::r#unsafe::{unsafe_cast_var_name_to_lifetime, unsafe_mut_cast_to_lifetime};
|
||||||
use crate::result::EvalAltResult;
|
use crate::result::EvalAltResult;
|
||||||
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
use crate::scope::{EntryType as ScopeEntryType, Scope};
|
||||||
use crate::token::Position;
|
use crate::token::Position;
|
||||||
@ -655,27 +655,31 @@ impl Engine {
|
|||||||
.or_else(|| self.packages.get_fn(hashes.0))
|
.or_else(|| self.packages.get_fn(hashes.0))
|
||||||
{
|
{
|
||||||
// Calling pure function in method-call?
|
// Calling pure function in method-call?
|
||||||
let backup: Option<Dynamic> = if func.is_pure() && is_ref && args.len() > 0 {
|
let mut this_copy: Option<Dynamic>;
|
||||||
// Backup the original value. It'll be consumed because the function
|
let mut this_pointer: Option<&mut Dynamic> = None;
|
||||||
|
|
||||||
|
if func.is_pure() && is_ref && args.len() > 0 {
|
||||||
|
// Clone the original value. It'll be consumed because the function
|
||||||
// is pure and doesn't know that the first value is a reference (i.e. `is_ref`)
|
// is pure and doesn't know that the first value is a reference (i.e. `is_ref`)
|
||||||
Some(args[0].clone())
|
this_copy = Some(args[0].clone());
|
||||||
} else {
|
|
||||||
None
|
// Replace the first reference with a reference to the clone, force-casting the lifetime.
|
||||||
};
|
// Keep the original reference. Must remember to restore it before existing this function.
|
||||||
|
this_pointer = Some(mem::replace(
|
||||||
|
args.get_mut(0).unwrap(),
|
||||||
|
unsafe_mut_cast_to_lifetime(this_copy.as_mut().unwrap()),
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
// Run external function
|
// Run external function
|
||||||
let result = match func.get_native_fn()(args) {
|
let result = func.get_native_fn()(args);
|
||||||
Ok(r) => {
|
|
||||||
// Restore the backup value for the first argument since it has been consumed!
|
// Restore the original reference
|
||||||
if let Some(backup) = backup {
|
if let Some(this_pointer) = this_pointer {
|
||||||
*args[0] = backup;
|
mem::replace(args.get_mut(0).unwrap(), this_pointer);
|
||||||
}
|
}
|
||||||
r
|
|
||||||
}
|
let result = result.map_err(|err| err.new_position(pos))?;
|
||||||
Err(err) => {
|
|
||||||
return Err(err.new_position(pos));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// See if the function match print/debug (which requires special processing)
|
// See if the function match print/debug (which requires special processing)
|
||||||
return Ok(match fn_name {
|
return Ok(match fn_name {
|
||||||
|
@ -42,6 +42,18 @@ pub fn unsafe_cast_box<X: Variant, T: Variant>(item: Box<X>) -> Result<Box<T>, B
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// # DANGEROUS!!!
|
||||||
|
///
|
||||||
|
/// A dangerous function that blindly casts a reference from one lifetime to another lifetime.
|
||||||
|
///
|
||||||
|
/// Force-casting a a reference to another lifetime saves on allocations and string cloning,
|
||||||
|
/// but must be used with the utmost care.
|
||||||
|
pub fn unsafe_mut_cast_to_lifetime<'a, T>(value: &mut T) -> &'a mut T {
|
||||||
|
unsafe { mem::transmute::<_, &'a mut T>(value) }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// # DANGEROUS!!!
|
||||||
|
///
|
||||||
/// A dangerous function that blindly casts a `&str` from one lifetime to a `Cow<str>` of
|
/// A dangerous function that blindly casts a `&str` from one lifetime to a `Cow<str>` of
|
||||||
/// another lifetime. This is mainly used to let us push a block-local variable into the
|
/// another lifetime. This is mainly used to let us push a block-local variable into the
|
||||||
/// current `Scope` without cloning the variable name. Doing this is safe because all local
|
/// current `Scope` without cloning the variable name. Doing this is safe because all local
|
||||||
|
Loading…
x
Reference in New Issue
Block a user