Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rhai shared scoped refs #901

Open
wants to merge 6 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,8 @@ unstable = []
## Running under a testing environment.
testing-environ = []

dangerous = []

[[bin]]
name = "rhai-repl"
required-features = ["rustyline"]
Expand Down
4 changes: 2 additions & 2 deletions benches/eval_type.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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) {
Expand All @@ -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 }
}
}
Expand Down
51 changes: 48 additions & 3 deletions examples/simple_fn.rs
Original file line number Diff line number Diff line change
@@ -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<INT>,
}

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<EvalAltResult>> {
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::<i64>("add(40, 2)")?;
engine.eval_with_scope::<i64>(
&mut scope,
r#"
ts.y
// xx1(ts) // <- this is impossible
// xx2(ts) // <- this is also impossible
"#,
)
})?;

drop(target);
println!("Answer: {result}"); // prints 42

Ok(())
Expand Down
4 changes: 2 additions & 2 deletions src/api/deprecated.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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")))]
Expand Down Expand Up @@ -221,7 +221,7 @@ impl Engine {
pub fn register_get_result<T: Variant + Clone, const X: bool, R: Variant + Clone>(
&mut self,
name: impl AsRef<str>,
get_fn: impl RhaiNativeFunc<(Mut<T>,), 1, X, R, true> + SendSync + 'static,
get_fn: impl RhaiNativeFunc<(Ref<T>,), 1, X, R, true> + SendSync + 'static,
) -> &mut Self {
self.register_get(name, get_fn)
}
Expand Down
11 changes: 5 additions & 6 deletions src/api/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -74,7 +74,6 @@ impl Engine {
func: impl RhaiNativeFunc<A, N, X, R, F> + SendSync + 'static,
) -> &mut Self {
FuncRegistration::new(name.into()).register_into_engine(self, func);

self
}
/// Register a function of the [`Engine`].
Expand Down Expand Up @@ -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
/// }
/// }
Expand All @@ -305,7 +304,7 @@ impl Engine {
pub fn register_get<T: Variant + Clone, const X: bool, R: Variant + Clone, const F: bool>(
&mut self,
name: impl AsRef<str>,
get_fn: impl RhaiNativeFunc<(Mut<T>,), 1, X, R, F> + SendSync + 'static,
get_fn: impl RhaiNativeFunc<(Ref<T>,), 1, X, R, F> + SendSync + 'static,
) -> &mut Self {
self.register_fn(crate::engine::make_getter(name.as_ref()), get_fn)
}
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -417,7 +416,7 @@ impl Engine {
>(
&mut self,
name: impl AsRef<str>,
get_fn: impl RhaiNativeFunc<(Mut<T>,), 1, X1, R, F1> + SendSync + 'static,
get_fn: impl RhaiNativeFunc<(Ref<T>,), 1, X1, R, F1> + SendSync + 'static,
set_fn: impl RhaiNativeFunc<(Mut<T>, R), 2, X2, (), F2> + SendSync + 'static,
) -> &mut Self {
self.register_get(&name, get_fn).register_set(&name, set_fn)
Expand Down
7 changes: 7 additions & 0 deletions src/func/call.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()))
});

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -1866,6 +1872,7 @@ impl Engine {
}
_ => (),
},
(Union::SharedVariant(..), _) | (_, Union::SharedVariant(..)) => (),
(Union::Variant(..), _) | (_, Union::Variant(..)) => (),
_ => {
if let Some((func, need_context)) =
Expand Down
14 changes: 11 additions & 3 deletions src/func/register.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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::*;
Expand All @@ -35,7 +35,7 @@ use std::{
///
/// These types are not actually used anywhere.
pub struct Mut<T>(T);
//pub struct Ref<T>(T);
pub struct Ref<T>(T);

/// Dereference into [`DynamicWriteLock`]
#[inline(always)]
Expand All @@ -44,6 +44,12 @@ pub fn by_ref<T: Variant + Clone>(data: &mut Dynamic) -> DynamicWriteLock<T> {
data.write_lock::<T>().unwrap()
}

#[inline(always)]
pub fn by_ref_read<T: Variant + Clone>(data: &mut Dynamic) -> DynamicReadLock<T> {
// Directly cast the &mut Dynamic into DynamicWriteLock to access the underlying data.
data.read_lock::<T>().unwrap()
}

/// Dereference into value.
#[inline(always)]
#[must_use]
Expand Down Expand Up @@ -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()); )*
Expand Down Expand Up @@ -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),*);

Expand Down Expand Up @@ -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)
Expand Down
3 changes: 2 additions & 1 deletion src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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};
Expand Down
1 change: 1 addition & 0 deletions src/module/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -407,6 +407,7 @@ impl FuncRegistration {
.map(|ty| format!("_: {}", engine.format_param_type(ty)))
.collect::<crate::FnArgsVec<_>>();


if FUNC::return_type() != TypeId::of::<()>() {
param_type_names
.push(engine.format_param_type(FUNC::return_type_name()).into());
Expand Down
1 change: 1 addition & 0 deletions src/serde/de.rs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
Union::Variant(ref value, ..) if value.is::<u128>() => self.deserialize_u128(visitor),

Union::Variant(..) => self.type_error(),
Union::SharedVariant(..) => self.type_error(),

#[cfg(not(feature = "no_closure"))]
Union::Shared(..) => self.type_error(),
Expand Down
3 changes: 2 additions & 1 deletion src/serde/serialize.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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"))]
Expand Down
4 changes: 2 additions & 2 deletions src/tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ fn check_struct_sizes() {
} else if IS_32_BIT {
12
} else {
16
24
}
);
assert_eq!(
Expand All @@ -32,7 +32,7 @@ fn check_struct_sizes() {
} else if IS_32_BIT {
12
} else {
16
24
}
);
assert_eq!(
Expand Down
Loading