diff --git a/Cargo.toml b/Cargo.toml index d43de4210..99249f402 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -130,6 +130,8 @@ unstable = [] ## Running under a testing environment. testing-environ = [] +dangerous = [] + [[bin]] name = "rhai-repl" required-features = ["rustyline"] diff --git a/benches/eval_type.rs b/benches/eval_type.rs index 7cee4394e..d943071f5 100644 --- a/benches/eval_type.rs +++ b/benches/eval_type.rs @@ -12,7 +12,7 @@ struct Test { } impl Test { - pub fn get_x(&mut self) -> INT { + pub fn get_x(&self) -> INT { self.x } pub fn action(&mut self) { @@ -21,7 +21,7 @@ impl Test { pub fn update(&mut self, val: INT) { self.x = val; } - pub fn get_nest(&mut self) -> Test { + pub fn get_nest(&self) -> Test { Test { x: 9 } } } diff --git a/examples/simple_fn.rs b/examples/simple_fn.rs index 887cad30b..9bcbce69f 100644 --- a/examples/simple_fn.rs +++ b/examples/simple_fn.rs @@ -1,18 +1,63 @@ //! An example showing how to register a simple Rust function. -use rhai::{Engine, EvalAltResult}; +use rhai::{dynamic_scope, Dynamic, Engine, EvalAltResult}; +use rhai::{Scope, INT}; fn add(x: i64, y: i64) -> i64 { x + y } +struct TestStruct { + x: INT, + y: INT, + array: Vec, +} + +impl TestStruct { + fn new() -> Self { + Self { + x: 1, + y: 833, + array: vec![1, 2, 3, 4, 5], + } + } + + fn get_y(&self) -> INT { + self.y + } +} + +impl Clone for TestStruct { + fn clone(&self) -> Self { + unimplemented!() + } +} fn main() -> Result<(), Box> { let mut engine = Engine::new(); + let mut scope = Scope::new(); + let target = TestStruct::new(); + + let result = dynamic_scope(|| { + scope.set_value("ts", unsafe { Dynamic::from_ref(&target) }); + engine.register_get("y", TestStruct::get_y); + + engine.register_fn("xx1", |_: TestStruct| {}); + engine.register_fn("xx2", |_: &'static TestStruct| {}); - engine.register_fn("add", add); + // THIS CAUSE ERROR + // engine.register_get("xx2", |x: &TestStruct| -> &'static INT { &x.y }); - let result = engine.eval::("add(40, 2)")?; + engine.eval_with_scope::( + &mut scope, + r#" + ts.y + // xx1(ts) // <- this is impossible + // xx2(ts) // <- this is also impossible + "#, + ) + })?; + drop(target); println!("Answer: {result}"); // prints 42 Ok(()) diff --git a/src/api/deprecated.rs b/src/api/deprecated.rs index 755560312..e838d06a5 100644 --- a/src/api/deprecated.rs +++ b/src/api/deprecated.rs @@ -12,7 +12,7 @@ use std::any::TypeId; use std::prelude::v1::*; #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] -use crate::func::register::Mut; +use crate::func::register::{Mut, Ref}; #[cfg(not(feature = "no_std"))] #[cfg(any(not(target_family = "wasm"), not(target_os = "unknown")))] @@ -221,7 +221,7 @@ impl Engine { pub fn register_get_result( &mut self, name: impl AsRef, - get_fn: impl RhaiNativeFunc<(Mut,), 1, X, R, true> + SendSync + 'static, + get_fn: impl RhaiNativeFunc<(Ref,), 1, X, R, true> + SendSync + 'static, ) -> &mut Self { self.register_get(name, get_fn) } diff --git a/src/api/register.rs b/src/api/register.rs index 245b2eec2..bbfa12af6 100644 --- a/src/api/register.rs +++ b/src/api/register.rs @@ -11,7 +11,7 @@ use std::any::{type_name, TypeId}; use std::prelude::v1::*; #[cfg(any(not(feature = "no_index"), not(feature = "no_object")))] -use crate::func::register::Mut; +use crate::func::register::{Mut, Ref}; impl Engine { /// Get a mutable reference to the global namespace module @@ -74,7 +74,6 @@ impl Engine { func: impl RhaiNativeFunc + SendSync + 'static, ) -> &mut Self { FuncRegistration::new(name.into()).register_into_engine(self, func); - self } /// Register a function of the [`Engine`]. @@ -279,7 +278,7 @@ impl Engine { /// Self { field: 1 } /// } /// // Even a getter must start with `&mut self` and not `&self`. - /// fn get_field(&mut self) -> i64 { + /// fn get_field(&self) -> i64 { /// self.field /// } /// } @@ -305,7 +304,7 @@ impl Engine { pub fn register_get( &mut self, name: impl AsRef, - get_fn: impl RhaiNativeFunc<(Mut,), 1, X, R, F> + SendSync + 'static, + get_fn: impl RhaiNativeFunc<(Ref,), 1, X, R, F> + SendSync + 'static, ) -> &mut Self { self.register_fn(crate::engine::make_getter(name.as_ref()), get_fn) } @@ -380,7 +379,7 @@ impl Engine { /// Self { field: 1 } /// } /// // Even a getter must start with `&mut self` and not `&self`. - /// fn get_field(&mut self) -> i64 { + /// fn get_field(&self) -> i64 { /// self.field /// } /// fn set_field(&mut self, new_val: i64) { @@ -417,7 +416,7 @@ impl Engine { >( &mut self, name: impl AsRef, - get_fn: impl RhaiNativeFunc<(Mut,), 1, X1, R, F1> + SendSync + 'static, + get_fn: impl RhaiNativeFunc<(Ref,), 1, X1, R, F1> + SendSync + 'static, set_fn: impl RhaiNativeFunc<(Mut, R), 2, X2, (), F2> + SendSync + 'static, ) -> &mut Self { self.register_get(&name, get_fn).register_set(&name, set_fn) diff --git a/src/func/call.rs b/src/func/call.rs index 3c002b89e..98abc65bd 100644 --- a/src/func/call.rs +++ b/src/func/call.rs @@ -174,6 +174,9 @@ impl Engine { allow_dynamic: bool, ) -> Option<&'s FnResolutionCacheEntry> { let mut hash = args.as_deref().map_or(hash_base, |args| { + args.iter() + .map(|a| a.type_name()) + .for_each(|x| println!("{x}")); calc_fn_hash_full(hash_base, args.iter().map(|a| a.type_id())) }); @@ -353,6 +356,9 @@ impl Engine { ) -> RhaiResultOf<(Dynamic, bool)> { self.track_operation(global, pos)?; + println!("---------------"); + println!("{}", name); + // Check if function access already in the cache let local_entry = &mut None; let a = Some(&mut *args); @@ -1866,6 +1872,7 @@ impl Engine { } _ => (), }, + (Union::SharedVariant(..), _) | (_, Union::SharedVariant(..)) => (), (Union::Variant(..), _) | (_, Union::Variant(..)) => (), _ => { if let Some((func, need_context)) = diff --git a/src/func/register.rs b/src/func/register.rs index f67452461..c44439d15 100644 --- a/src/func/register.rs +++ b/src/func/register.rs @@ -8,7 +8,7 @@ use super::call::FnCallArgs; use super::function::RhaiFunc; use super::native::{SendSync, Shared}; -use crate::types::dynamic::{DynamicWriteLock, Union, Variant}; +use crate::types::dynamic::{DynamicReadLock, DynamicWriteLock, Union, Variant}; use crate::{Dynamic, Identifier, NativeCallContext, RhaiResultOf}; #[cfg(feature = "no_std")] use std::prelude::v1::*; @@ -35,7 +35,7 @@ use std::{ /// /// These types are not actually used anywhere. pub struct Mut(T); -//pub struct Ref(T); +pub struct Ref(T); /// Dereference into [`DynamicWriteLock`] #[inline(always)] @@ -44,6 +44,12 @@ pub fn by_ref(data: &mut Dynamic) -> DynamicWriteLock { data.write_lock::().unwrap() } +#[inline(always)] +pub fn by_ref_read(data: &mut Dynamic) -> DynamicReadLock { + // Directly cast the &mut Dynamic into DynamicWriteLock to access the underlying data. + data.read_lock::().unwrap() +} + /// Dereference into value. #[inline(always)] #[must_use] @@ -145,7 +151,7 @@ macro_rules! def_register { #[inline(always)] fn param_types() -> [TypeId;$n] { [$(TypeId::of::<$par>()),*] } #[cfg(feature = "metadata")] #[inline(always)] fn param_names() -> [&'static str;$n] { [$(type_name::<$param>()),*] } #[inline(always)] fn into_rhai_function(self, is_pure: bool, is_volatile: bool) -> RhaiFunc { - RhaiFunc::$abi { func: Shared::new(move |_, args: &mut FnCallArgs| { + RhaiFunc::$abi { func: Shared::new(move |ctx: _, args: &mut FnCallArgs| { // The arguments are assumed to be of the correct number and types! let mut drain = args.iter_mut(); $(let mut $par = $clone(drain.next().unwrap()); )* @@ -174,6 +180,7 @@ macro_rules! def_register { let mut drain = args.iter_mut(); $(let mut $par = $clone(drain.next().unwrap()); )* + // Call the function with each argument value let r = self(ctx, $($arg),*); @@ -230,6 +237,7 @@ macro_rules! def_register { ($p0:ident:$n0:expr $(, $p:ident: $n:expr)*) => { def_register!(imp Pure : $n0 ; $p0 => $p0 => $p0 => $p0 => by_value $(, $p => $p => $p => $p => by_value)*); def_register!(imp Method : $n0 ; $p0 => &mut $p0 => Mut<$p0> => &mut $p0 => by_ref $(, $p => $p => $p => $p => by_value)*); + def_register!(imp Method : $n0 ; $p0 => & $p0 => Ref<$p0> => & $p0 => by_ref_read $(, $p => $p => $p => $p => by_value)*); // ^ RhaiFunc constructor // ^ number of arguments ^ first parameter passed through // ^ others passed by value (by_value) diff --git a/src/lib.rs b/src/lib.rs index 525df595c..2dade0c9a 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -92,6 +92,7 @@ #![allow(clippy::enum_glob_use)] // Sometimes useful to import all `Tokens` etc. #![allow(clippy::no_effect_underscore_binding)] // Underscored variables may be used by code within feature guards #![allow(clippy::semicolon_if_nothing_returned)] // One-liner `match` cases are sometimes formatted as multi-line blocks +#![feature(thread_local)] #[cfg(feature = "no_std")] extern crate alloc; @@ -323,7 +324,7 @@ pub use module::resolvers as module_resolvers; #[cfg(not(feature = "no_optimize"))] pub use optimizer::OptimizationLevel; -// Expose internal data structures. +pub use types::dynamic::dynamic_scope; #[cfg(feature = "internals")] pub use types::dynamic::{AccessMode, DynamicReadLock, DynamicWriteLock, Variant}; diff --git a/src/module/mod.rs b/src/module/mod.rs index 4c8ba66ce..e1a77c67c 100644 --- a/src/module/mod.rs +++ b/src/module/mod.rs @@ -407,6 +407,7 @@ impl FuncRegistration { .map(|ty| format!("_: {}", engine.format_param_type(ty))) .collect::>(); + if FUNC::return_type() != TypeId::of::<()>() { param_type_names .push(engine.format_param_type(FUNC::return_type_name()).into()); diff --git a/src/serde/de.rs b/src/serde/de.rs index dffe45653..07b07456b 100644 --- a/src/serde/de.rs +++ b/src/serde/de.rs @@ -174,6 +174,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> { Union::Variant(ref value, ..) if value.is::() => self.deserialize_u128(visitor), Union::Variant(..) => self.type_error(), + Union::SharedVariant(..) => self.type_error(), #[cfg(not(feature = "no_closure"))] Union::Shared(..) => self.type_error(), diff --git a/src/serde/serialize.rs b/src/serde/serialize.rs index 252e3243d..05463c982 100644 --- a/src/serde/serialize.rs +++ b/src/serde/serialize.rs @@ -71,7 +71,8 @@ impl Serialize for Dynamic { #[cfg(not(feature = "no_time"))] Union::TimeStamp(ref x, ..) => ser.serialize_str(x.as_ref().type_name()), - Union::Variant(ref v, ..) => ser.serialize_str((***v).type_name()), + Union::Variant(ref v, ..) => ser.serialize_str(v.type_name()), + Union::SharedVariant(ref v, ..) => ser.serialize_str(v.type_name()), #[cfg(not(feature = "no_closure"))] #[cfg(not(feature = "sync"))] diff --git a/src/tests.rs b/src/tests.rs index fc4778ea6..6d87e2868 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -22,7 +22,7 @@ fn check_struct_sizes() { } else if IS_32_BIT { 12 } else { - 16 + 24 } ); assert_eq!( @@ -32,7 +32,7 @@ fn check_struct_sizes() { } else if IS_32_BIT { 12 } else { - 16 + 24 } ); assert_eq!( diff --git a/src/types/dynamic.rs b/src/types/dynamic.rs index 1a94dcbe0..bcedfe0b2 100644 --- a/src/types/dynamic.rs +++ b/src/types/dynamic.rs @@ -26,6 +26,7 @@ pub use instant::Instant; /// Exported under the `internals` feature only. #[derive(Debug, Eq, PartialEq, Hash, Copy, Clone)] #[non_exhaustive] +#[repr(u8)] pub enum AccessMode { /// Mutable. ReadWrite, @@ -33,6 +34,96 @@ pub enum AccessMode { ReadOnly, } +pub struct SharedVariantPtr(#[cfg(feature = "dangerous")] *const dyn Variant); +impl SharedVariantPtr { + fn type_id(&self) -> TypeId { + #[cfg(feature = "dangerous")] + unsafe { + (*self.0).type_id() + } + + #[cfg(not(feature = "dangerous"))] + unimplemented!("required `feature = dangerous`") + } + + pub fn type_name(&self) -> &'static str { + #[cfg(feature = "dangerous")] + unsafe { + (*self.0).type_name() + } + + #[cfg(not(feature = "dangerous"))] + unimplemented!("required `feature = dangerous`") + } + + fn as_any(&self) -> &dyn Any { + #[cfg(feature = "dangerous")] + unsafe { + (*self.0).as_any() + } + + #[cfg(not(feature = "dangerous"))] + unimplemented!("required `feature = dangerous`") + } + + fn clone(&self) -> Self { + #[cfg(feature = "dangerous")] + let _clone = SharedVariantPtr(self.0); + #[cfg(not(feature = "dangerous"))] + let _clone = unimplemented!("required `feature = dangerous`"); + #[allow(unreachable_code)] + _clone + } +} + +pub struct OwnedVariant(Box); +impl OwnedVariant { + fn new(boxed: Box) -> Self { + OwnedVariant(boxed) + } + + fn type_id(&self) -> TypeId { + (*(*self).0).type_id() + } + + pub fn type_name(&self) -> &'static str { + (*(*self).0).type_name() + } + + fn as_any(&self) -> &dyn Any { + (*(*self).0).as_any() + } + + fn as_boxed_any(self) -> Box { + self.0.as_boxed_any() + } + + fn as_any_mut(&mut self) -> &mut dyn Any { + (*(*self).0).as_any_mut() + } + + fn clone(&self) -> Self { + OwnedVariant(self.0.clone_object()) + } + + pub fn is(&self) -> bool { + self.0.is::() + } +} + +#[thread_local] +pub static DYNAMIC_GENERATION: std::sync::atomic::AtomicU16 = std::sync::atomic::AtomicU16::new(0); + +/// dynamic scope +pub fn dynamic_scope(func: impl FnOnce() -> R) -> R { + let current_generation = DYNAMIC_GENERATION.load(core::sync::atomic::Ordering::Acquire); + let result = func(); + if current_generation != DYNAMIC_GENERATION.fetch_add(1, core::sync::atomic::Ordering::AcqRel) { + panic!("nested dynnamic scopes not supproted yet"); + } + result +} + /// Arbitrary data attached to a [`Dynamic`] value. #[cfg(target_pointer_width = "64")] pub type Tag = i32; @@ -87,9 +178,12 @@ pub enum Union { /// Any type as a trait object. /// + /// We needed to support both variants shared and owned + /// /// An extra level of redirection is used in order to avoid bloating the size of [`Dynamic`] /// because `Box` is a fat pointer. - Variant(Box>, Tag, AccessMode), + Variant(OwnedVariant, Tag, AccessMode), + SharedVariant(SharedVariantPtr, Tag, AccessMode, u16), /// A _shared_ value of any type. #[cfg(not(feature = "no_closure"))] @@ -186,7 +280,8 @@ impl Dynamic { | Union::Char(_, tag, _) | Union::Int(_, tag, _) | Union::FnPtr(_, tag, _) - | Union::Variant(_, tag, _) => tag, + | Union::Variant(_, tag, _) + | Union::SharedVariant(_, tag, _, _) => tag, #[cfg(not(feature = "no_float"))] Union::Float(_, tag, _) => tag, @@ -211,7 +306,8 @@ impl Dynamic { | Union::Char(_, ref mut tag, _) | Union::Int(_, ref mut tag, _) | Union::FnPtr(_, ref mut tag, _) - | Union::Variant(_, ref mut tag, _) => *tag = value, + | Union::Variant(_, ref mut tag, _) + | Union::SharedVariant(_, ref mut tag, _, _) => *tag = value, #[cfg(not(feature = "no_float"))] Union::Float(_, ref mut tag, _) => *tag = value, @@ -233,7 +329,7 @@ impl Dynamic { #[inline(always)] #[must_use] pub const fn is_variant(&self) -> bool { - matches!(self.0, Union::Variant(..)) + matches!(self.0, Union::Variant(..)) || matches!(self.0, Union::SharedVariant(..)) } /// Is the value held by this [`Dynamic`] shared? /// @@ -333,7 +429,8 @@ impl Dynamic { #[cfg(not(feature = "no_time"))] Union::TimeStamp(..) => TypeId::of::(), - Union::Variant(ref v, ..) => (***v).type_id(), + Union::SharedVariant(ref v, ..) => v.type_id(), + Union::Variant(ref v, ..) => v.type_id(), #[cfg(not(feature = "no_closure"))] Union::Shared(ref cell, ..) => (*crate::func::locked_read(cell).unwrap()).type_id(), @@ -367,7 +464,8 @@ impl Dynamic { #[cfg(not(feature = "no_time"))] Union::TimeStamp(..) => "timestamp", - Union::Variant(ref v, ..) => (***v).type_name(), + Union::SharedVariant(ref v, ..) => v.type_name(), + Union::Variant(ref v, ..) => v.type_name(), #[cfg(not(feature = "no_closure"))] Union::Shared(ref cell, ..) => (*crate::func::locked_read(cell).unwrap()).type_name(), @@ -411,8 +509,12 @@ impl Hash for Dynamic { #[cfg(not(feature = "no_closure"))] Union::Shared(ref cell, ..) => (*crate::func::locked_read(cell).unwrap()).hash(state), - Union::Variant(ref v, ..) => { - let _value_any = (***v).as_any(); + Union::Variant(..) | Union::SharedVariant(..) => { + let _value_any = match self.0 { + Union::Variant(ref v, ..) => v.as_any(), + Union::SharedVariant(ref v, ..) => v.as_any(), + _ => unimplemented!("unknown type"), + }; #[cfg(not(feature = "only_i32"))] #[cfg(not(feature = "only_i64"))] @@ -491,8 +593,12 @@ impl fmt::Display for Dynamic { #[cfg(not(feature = "no_time"))] Union::TimeStamp(..) => f.write_str(""), - Union::Variant(ref v, ..) => { - let _value_any = (***v).as_any(); + Union::Variant(..) | Union::SharedVariant(..) => { + let (_value_any, _type_name) = match self.0 { + Union::Variant(ref v, ..) => (v.as_any(), v.type_name()), + Union::SharedVariant(ref v, ..) => (v.as_any(), v.type_name()), + _ => unimplemented!("unknown type"), + }; let _type_id = _value_any.type_id(); #[cfg(not(feature = "only_i32"))] @@ -549,7 +655,7 @@ impl fmt::Display for Dynamic { }; } - f.write_str((***v).type_name()) + f.write_str(_type_name) } #[cfg(not(feature = "no_closure"))] @@ -659,8 +765,12 @@ impl fmt::Debug for Dynamic { #[cfg(not(feature = "no_time"))] Union::TimeStamp(..) => write!(f, ""), - Union::Variant(ref v, ..) => { - let _value_any = (***v).as_any(); + Union::SharedVariant(..) | Union::Variant(..) => { + let (_value_any, _type_name) = match self.0 { + Union::Variant(ref v, ..) => (v.as_any(), v.type_name()), + Union::SharedVariant(ref v, ..) => (v.as_any(), v.type_name()), + _ => unimplemented!("unknown type"), + }; let _type_id = _value_any.type_id(); #[cfg(not(feature = "only_i32"))] @@ -717,7 +827,7 @@ impl fmt::Debug for Dynamic { }; } - f.write_str((***v).type_name()) + f.write_str(_type_name) } #[cfg(not(feature = "no_closure"))] @@ -836,10 +946,13 @@ impl Clone for Dynamic { #[cfg(not(feature = "no_time"))] Union::TimeStamp(ref v, tag, ..) => Self(Union::TimeStamp(v.clone(), tag, ReadWrite)), - Union::Variant(ref v, tag, ..) => Self(Union::Variant( - v.as_ref().as_ref().clone_object().into(), + Union::Variant(ref v, tag, ..) => Self(Union::Variant(v.clone(), tag, ReadWrite)), + + Union::SharedVariant(ref v, tag, ..) => Self(Union::SharedVariant( + v.clone(), tag, ReadWrite, + DYNAMIC_GENERATION.load(core::sync::atomic::Ordering::Relaxed), )), #[cfg(not(feature = "no_closure"))] @@ -1082,6 +1195,7 @@ impl Dynamic { | Union::Char(.., access) | Union::Int(.., access) | Union::FnPtr(.., access) + | Union::SharedVariant(.., access, _) | Union::Variant(.., access) => access, #[cfg(not(feature = "no_float"))] @@ -1107,6 +1221,7 @@ impl Dynamic { | Union::Char(.., ref mut access) | Union::Int(.., ref mut access) | Union::FnPtr(.., ref mut access) + | Union::SharedVariant(.., ref mut access, _) | Union::Variant(.., ref mut access) => *access = typ, #[cfg(not(feature = "no_float"))] @@ -1220,8 +1335,12 @@ impl Dynamic { #[cfg(not(feature = "no_time"))] Union::TimeStamp(..) => false, - Union::Variant(ref v, ..) => { - let _value_any = (***v).as_any(); + Union::SharedVariant(..) | Union::Variant(..) => { + let _value_any = match self.0 { + Union::Variant(ref v, ..) => v.as_any(), + Union::SharedVariant(ref v, ..) => v.as_any(), + _ => unimplemented!("unknown type"), + }; let _type_id = _value_any.type_id(); #[cfg(not(feature = "only_i32"))] @@ -1302,6 +1421,18 @@ impl Dynamic { } } } + + /// + #[cfg(feature = "dangerous")] + pub unsafe fn from_ref(value: &T) -> Self { + Self(Union::SharedVariant( + SharedVariantPtr(value as &dyn Variant as *const dyn Variant), + 0, + ReadOnly, + DYNAMIC_GENERATION.load(core::sync::atomic::Ordering::Relaxed) as u16, + )) + } + /// Create a [`Dynamic`] from any type. A [`Dynamic`] value is simply returned as is. /// /// # Arrays @@ -1401,7 +1532,7 @@ impl Dynamic { reify! { value => |v: crate::Shared>| return v.into() } Self(Union::Variant( - Box::new(Box::new(value)), + OwnedVariant::new(Box::new(value)), DEFAULT_TAG_VALUE, ReadWrite, )) @@ -1590,8 +1721,8 @@ impl Dynamic { } match self.0 { - Union::Variant(v, ..) if TypeId::of::() == (**v).type_id() => { - Ok((*v).as_boxed_any().downcast().map(|x| *x).unwrap()) + Union::Variant(v, ..) if TypeId::of::() == v.type_id() => { + Ok(v.as_boxed_any().downcast().map(|x| *x).unwrap()) } _ => Err(self), } @@ -1939,8 +2070,12 @@ impl Dynamic { } match self.0 { - Union::Variant(ref v, ..) => (***v).as_any().downcast_ref::(), + Union::Variant(ref v, ..) => v.as_any().downcast_ref::(), #[cfg(not(feature = "no_closure"))] + Union::SharedVariant(ref v, .., generation) => (generation + == DYNAMIC_GENERATION.load(core::sync::atomic::Ordering::Relaxed)) + .then(|| v.as_any().downcast_ref::()) + .flatten(), Union::Shared(..) => None, _ => None, } @@ -2042,7 +2177,7 @@ impl Dynamic { } match self.0 { - Union::Variant(ref mut v, ..) => (***v).as_any_mut().downcast_mut::(), + Union::Variant(ref mut v, ..) => v.as_any_mut().downcast_mut::(), #[cfg(not(feature = "no_closure"))] Union::Shared(..) => None, _ => None, diff --git a/tests/arrays.rs b/tests/arrays.rs index 35e15d250..c80b3eb33 100644 --- a/tests/arrays.rs +++ b/tests/arrays.rs @@ -187,7 +187,7 @@ fn test_array_with_structs() { self.x += 1000; } - fn get_x(&mut self) -> INT { + fn get_x(&self) -> INT { self.x } diff --git a/tests/closures.rs b/tests/closures.rs index 39bf88565..fffff83a0 100644 --- a/tests/closures.rs +++ b/tests/closures.rs @@ -328,7 +328,7 @@ fn test_closures_shared_obj() { // Register API on TestStruct engine .register_type_with_name::("TestStruct") - .register_get_set("data", |p: &mut TestStruct| *p.borrow(), |p: &mut TestStruct, value: INT| *p.borrow_mut() = value) + .register_get_set("data", |p: &TestStruct| *p.borrow(), |p: &mut TestStruct, value: INT| *p.borrow_mut() = value) .register_fn("+=", |p1: &mut TestStruct, p2: TestStruct| *p1.borrow_mut() += *p2.borrow()) .register_fn("-=", |p1: &mut TestStruct, p2: TestStruct| *p1.borrow_mut() -= *p2.borrow()); diff --git a/tests/constants.rs b/tests/constants.rs index cb8c810b2..a882866b9 100644 --- a/tests/constants.rs +++ b/tests/constants.rs @@ -46,7 +46,7 @@ fn test_constant_mut() { engine .register_type_with_name::("TestStruct") .register_fn("new_ts", || TestStruct(123)) - .register_get("value", |obj: &mut TestStruct| obj.0) + .register_get("value", |obj: &TestStruct| obj.0) .register_set("value", set_value) .register_fn("update_value", set_value); diff --git a/tests/expressions.rs b/tests/expressions.rs index 99c43875e..991493ef8 100644 --- a/tests/expressions.rs +++ b/tests/expressions.rs @@ -75,10 +75,10 @@ fn test_expressions_eval() { } impl AGENT { - pub fn get_gender(&mut self) -> String { + pub fn get_gender(&self) -> String { self.gender.clone() } - pub fn get_age(&mut self) -> INT { + pub fn get_age(&self) -> INT { self.age } } diff --git a/tests/float.rs b/tests/float.rs index 8796b296b..416879a9f 100644 --- a/tests/float.rs +++ b/tests/float.rs @@ -44,7 +44,7 @@ fn test_struct_with_float() { self.x += 5.789; } - fn get_x(&mut self) -> FLOAT { + fn get_x(&self) -> FLOAT { self.x } diff --git a/tests/get_set.rs b/tests/get_set.rs index d5d7e591f..532ce99f3 100644 --- a/tests/get_set.rs +++ b/tests/get_set.rs @@ -11,7 +11,7 @@ fn test_get_set() { } impl TestStruct { - fn get_x(&mut self) -> INT { + fn get_x(&self) -> INT { self.x } @@ -19,7 +19,7 @@ fn test_get_set() { self.x = new_x; } - fn get_y(&mut self) -> INT { + fn get_y(&self) -> INT { self.y } @@ -61,7 +61,7 @@ fn test_get_set_chain_with_write_back() { } impl TestChild { - fn get_x(&mut self) -> INT { + fn get_x(&self) -> INT { self.x } @@ -80,7 +80,7 @@ fn test_get_set_chain_with_write_back() { } impl TestParent { - fn get_child(&mut self) -> TestChild { + fn get_child(&self) -> TestChild { self.child.clone() } @@ -128,7 +128,7 @@ fn test_get_set_op_assignment() { struct Num(INT); impl Num { - fn get(&mut self) -> INT { + fn get(&self) -> INT { self.0 } fn set(&mut self, x: INT) { @@ -163,9 +163,9 @@ fn test_get_set_chain_without_write_back() { engine .register_type::() - .register_get_set("value", |t: &mut Inner| t.value, |_: NativeCallContext, _: &mut Inner, new: INT| panic!("Inner::value setter called with {}", new)) + .register_get_set("value", |t: &Inner| t.value, |_: NativeCallContext, _: &mut Inner, new: INT| panic!("Inner::value setter called with {}", new)) .register_type::() - .register_get_set("inner", |_: NativeCallContext, t: &mut Outer| t.inner.clone(), |_: &mut Outer, new: Inner| panic!("Outer::inner setter called with {:?}", new)); + .register_get_set("inner", |_: NativeCallContext, t: &Outer| t.inner.clone(), |_: &mut Outer, new: Inner| panic!("Outer::inner setter called with {:?}", new)); #[cfg(not(feature = "no_index"))] engine.register_indexer_get_set(|t: &mut Outer, n: INT| Inner { value: t.inner.value * n }, |_: &mut Outer, n: INT, new: Inner| panic!("Outer::inner index setter called with {} and {:?}", n, new)); @@ -193,7 +193,7 @@ fn test_get_set_collection() { .register_iterator::() .register_fn("new_bag", MyBag::new) .register_fn("len", |col: &mut MyBag| col.len() as INT) - .register_get("len", |col: &mut MyBag| col.len() as INT) + .register_get("len", |col: &MyBag| col.len() as INT) .register_fn("clear", |col: &mut MyBag| col.clear()) .register_fn("contains", |col: &mut MyBag, item: INT| col.contains(&item)) .register_fn("add", |col: &mut MyBag, item: MyItem| col.insert(item)) diff --git a/tests/side_effects.rs b/tests/side_effects.rs index 31e55bbfa..5a8039b80 100644 --- a/tests/side_effects.rs +++ b/tests/side_effects.rs @@ -45,7 +45,7 @@ fn test_side_effects_command() { let val = command.get(); command.action(val + x); }); - engine.register_get("value", |command: &mut API| command.lock().unwrap().get()); + engine.register_get("value", |command: &API| command.lock().unwrap().get()); assert_eq!( engine diff --git a/tests/switch.rs b/tests/switch.rs index 94915713c..02db4c9d4 100644 --- a/tests/switch.rs +++ b/tests/switch.rs @@ -146,7 +146,7 @@ mod test_switch_enum { } impl MyEnum { - fn get_enum_data(&mut self) -> Array { + fn get_enum_data(&self) -> Array { match self { Self::Foo => vec!["Foo".into()] as Array, Self::Bar(num) => vec!["Bar".into(), (*num).into()] as Array, diff --git a/tests/var_scope.rs b/tests/var_scope.rs index 2d83387e1..962fe2d1a 100644 --- a/tests/var_scope.rs +++ b/tests/var_scope.rs @@ -444,7 +444,7 @@ fn test_var_scope_cloning() { } let mut engine = Engine::new(); - engine.register_get_set("field", |foo: &mut Foo| foo.field, |foo: &mut Foo, value| foo.field = value); + engine.register_get_set("field", |foo: &Foo| foo.field, |foo: &mut Foo, value| foo.field = value); let mut scope = Scope::new(); scope.push("foo", Foo { field: 1 });