Merge branch 'master' into plugins
This commit is contained in:
80
src/any.rs
80
src/any.rs
@@ -5,7 +5,7 @@ use crate::parser::{ImmutableString, INT};
|
||||
use crate::r#unsafe::{unsafe_cast_box, unsafe_try_cast};
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
use crate::fn_native::SharedMut;
|
||||
use crate::fn_native::{shared_try_take, Shared};
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
use crate::parser::FLOAT;
|
||||
@@ -134,6 +134,7 @@ impl<T: Any + Clone + SendSync> Variant for T {
|
||||
|
||||
impl dyn Variant {
|
||||
/// Is this `Variant` a specific type?
|
||||
#[inline(always)]
|
||||
pub fn is<T: Any>(&self) -> bool {
|
||||
TypeId::of::<T>() == self.type_id()
|
||||
}
|
||||
@@ -158,9 +159,15 @@ pub enum Union {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Map(Box<Map>),
|
||||
FnPtr(Box<FnPtr>),
|
||||
|
||||
Variant(Box<Box<dyn Variant>>),
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Shared(SharedMut<Dynamic>),
|
||||
#[cfg(not(feature = "sync"))]
|
||||
Shared(Shared<RefCell<Dynamic>>),
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(feature = "sync")]
|
||||
Shared(Shared<RwLock<Dynamic>>),
|
||||
}
|
||||
|
||||
/// Underlying `Variant` read guard for `Dynamic`.
|
||||
@@ -175,6 +182,7 @@ pub struct DynamicReadLock<'d, T: Variant + Clone>(DynamicReadLockInner<'d, T>);
|
||||
enum DynamicReadLockInner<'d, T: Variant + Clone> {
|
||||
/// A simple reference to a non-shared value.
|
||||
Reference(&'d T),
|
||||
|
||||
/// A read guard to a shared `RefCell`.
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "sync"))]
|
||||
@@ -211,6 +219,7 @@ pub struct DynamicWriteLock<'d, T: Variant + Clone>(DynamicWriteLockInner<'d, T>
|
||||
enum DynamicWriteLockInner<'d, T: Variant + Clone> {
|
||||
/// A simple mutable reference to a non-shared value.
|
||||
Reference(&'d mut T),
|
||||
|
||||
/// A write guard to a shared `RefCell`.
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "sync"))]
|
||||
@@ -250,6 +259,7 @@ impl<'d, T: Variant + Clone> DerefMut for DynamicWriteLock<'d, T> {
|
||||
impl Dynamic {
|
||||
/// Does this `Dynamic` hold a variant data type
|
||||
/// instead of one of the support system primitive types?
|
||||
#[inline(always)]
|
||||
pub fn is_variant(&self) -> bool {
|
||||
match self.0 {
|
||||
Union::Variant(_) => true,
|
||||
@@ -259,6 +269,7 @@ impl Dynamic {
|
||||
|
||||
/// Does this `Dynamic` hold a shared data type
|
||||
/// instead of one of the supported system primitive types?
|
||||
#[inline(always)]
|
||||
pub fn is_shared(&self) -> bool {
|
||||
match self.0 {
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
@@ -271,6 +282,7 @@ impl Dynamic {
|
||||
///
|
||||
/// If the `Dynamic` is a Shared variant checking is performed on
|
||||
/// top of it's internal value.
|
||||
#[inline(always)]
|
||||
pub fn is<T: Variant + Clone>(&self) -> bool {
|
||||
let mut target_type_id = TypeId::of::<T>();
|
||||
|
||||
@@ -301,7 +313,9 @@ impl Dynamic {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Union::Map(_) => TypeId::of::<Map>(),
|
||||
Union::FnPtr(_) => TypeId::of::<FnPtr>(),
|
||||
|
||||
Union::Variant(value) => (***value).type_id(),
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "sync"))]
|
||||
Union::Shared(cell) => (*cell.borrow()).type_id(),
|
||||
@@ -335,6 +349,7 @@ impl Dynamic {
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
Union::Variant(value) if value.is::<Instant>() => "timestamp",
|
||||
Union::Variant(value) => (***value).type_name(),
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "sync"))]
|
||||
Union::Shared(cell) => cell
|
||||
@@ -399,6 +414,7 @@ impl fmt::Display for Dynamic {
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
Union::Variant(value) if value.is::<Instant>() => f.write_str("<timestamp>"),
|
||||
Union::Variant(value) => f.write_str((*value).type_name()),
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "sync"))]
|
||||
Union::Shared(cell) => {
|
||||
@@ -437,6 +453,7 @@ impl fmt::Debug for Dynamic {
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
Union::Variant(value) if value.is::<Instant>() => write!(f, "<timestamp>"),
|
||||
Union::Variant(value) => write!(f, "{}", (*value).type_name()),
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "sync"))]
|
||||
Union::Shared(cell) => {
|
||||
@@ -468,7 +485,9 @@ impl Clone for Dynamic {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Union::Map(ref value) => Self(Union::Map(value.clone())),
|
||||
Union::FnPtr(ref value) => Self(Union::FnPtr(value.clone())),
|
||||
|
||||
Union::Variant(ref value) => (***value).clone_into_dynamic(),
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(ref cell) => Self(Union::Shared(cell.clone())),
|
||||
}
|
||||
@@ -476,6 +495,7 @@ impl Clone for Dynamic {
|
||||
}
|
||||
|
||||
impl Default for Dynamic {
|
||||
#[inline(always)]
|
||||
fn default() -> Self {
|
||||
Self(Union::Unit(()))
|
||||
}
|
||||
@@ -769,25 +789,46 @@ impl Dynamic {
|
||||
self.try_cast::<T>().unwrap()
|
||||
}
|
||||
|
||||
/// Get a copy of the `Dynamic` as a specific type.
|
||||
/// Dereference the `Dynamic`.
|
||||
///
|
||||
/// If the `Dynamic` is not a shared value, it returns a cloned copy of the value.
|
||||
/// If the `Dynamic` is not a shared value, it returns a cloned copy.
|
||||
///
|
||||
/// If the `Dynamic` is a shared value, it returns a cloned copy of the shared value.
|
||||
///
|
||||
/// Returns `None` if the cast fails.
|
||||
/// If the `Dynamic` is a shared value, it a cloned copy of the shared value.
|
||||
#[inline(always)]
|
||||
pub fn clone_inner_data<T: Variant + Clone>(self) -> Option<T> {
|
||||
pub fn get_inner_clone(&self) -> Self {
|
||||
match &self.0 {
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(cell) => {
|
||||
#[cfg(not(feature = "sync"))]
|
||||
return cell.borrow().clone();
|
||||
|
||||
#[cfg(feature = "sync")]
|
||||
return cell.read().unwrap().clone();
|
||||
}
|
||||
_ => self.clone(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Flatten the `Dynamic`.
|
||||
///
|
||||
/// If the `Dynamic` is not a shared value, it returns itself.
|
||||
///
|
||||
/// If the `Dynamic` is a shared value, it returns the shared value if there are
|
||||
/// no outstanding references, or a cloned copy.
|
||||
#[inline(always)]
|
||||
pub fn flatten(self) -> Self {
|
||||
match self.0 {
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
Union::Shared(cell) => {
|
||||
#[cfg(not(feature = "sync"))]
|
||||
return Some(cell.borrow().downcast_ref::<T>().unwrap().clone());
|
||||
return shared_try_take(cell)
|
||||
.map_or_else(|c| c.borrow().clone(), RefCell::into_inner);
|
||||
|
||||
#[cfg(feature = "sync")]
|
||||
return Some(cell.read().unwrap().downcast_ref::<T>().unwrap().clone());
|
||||
return shared_try_take(cell)
|
||||
.map_or_else(|c| c.read().unwrap().clone(), RwLock::into_inner);
|
||||
}
|
||||
_ => self.try_cast(),
|
||||
_ => self,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1050,6 +1091,7 @@ impl Dynamic {
|
||||
|
||||
/// Cast the `Dynamic` as the system integer type `INT` and return it.
|
||||
/// Returns the name of the actual type if the cast fails.
|
||||
#[inline(always)]
|
||||
pub fn as_int(&self) -> Result<INT, &'static str> {
|
||||
match self.0 {
|
||||
Union::Int(n) => Ok(n),
|
||||
@@ -1062,6 +1104,7 @@ impl Dynamic {
|
||||
/// Cast the `Dynamic` as the system floating-point type `FLOAT` and return it.
|
||||
/// Returns the name of the actual type if the cast fails.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
#[inline(always)]
|
||||
pub fn as_float(&self) -> Result<FLOAT, &'static str> {
|
||||
match self.0 {
|
||||
Union::Float(n) => Ok(n),
|
||||
@@ -1073,6 +1116,7 @@ impl Dynamic {
|
||||
|
||||
/// Cast the `Dynamic` as a `bool` and return it.
|
||||
/// Returns the name of the actual type if the cast fails.
|
||||
#[inline(always)]
|
||||
pub fn as_bool(&self) -> Result<bool, &'static str> {
|
||||
match self.0 {
|
||||
Union::Bool(b) => Ok(b),
|
||||
@@ -1084,6 +1128,7 @@ impl Dynamic {
|
||||
|
||||
/// Cast the `Dynamic` as a `char` and return it.
|
||||
/// Returns the name of the actual type if the cast fails.
|
||||
#[inline(always)]
|
||||
pub fn as_char(&self) -> Result<char, &'static str> {
|
||||
match self.0 {
|
||||
Union::Char(n) => Ok(n),
|
||||
@@ -1097,6 +1142,7 @@ impl Dynamic {
|
||||
/// Returns the name of the actual type if the cast fails.
|
||||
///
|
||||
/// Cast is failing if `self` is Shared Dynamic
|
||||
#[inline(always)]
|
||||
pub fn as_str(&self) -> Result<&str, &'static str> {
|
||||
match &self.0 {
|
||||
Union::Str(s) => Ok(s),
|
||||
@@ -1107,6 +1153,7 @@ impl Dynamic {
|
||||
|
||||
/// Convert the `Dynamic` into `String` and return it.
|
||||
/// Returns the name of the actual type if the cast fails.
|
||||
#[inline(always)]
|
||||
pub fn take_string(self) -> Result<String, &'static str> {
|
||||
self.take_immutable_string()
|
||||
.map(ImmutableString::into_owned)
|
||||
@@ -1145,38 +1192,45 @@ impl Dynamic {
|
||||
}
|
||||
|
||||
impl From<()> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: ()) -> Self {
|
||||
Self(Union::Unit(value))
|
||||
}
|
||||
}
|
||||
impl From<bool> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: bool) -> Self {
|
||||
Self(Union::Bool(value))
|
||||
}
|
||||
}
|
||||
impl From<INT> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: INT) -> Self {
|
||||
Self(Union::Int(value))
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl From<FLOAT> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: FLOAT) -> Self {
|
||||
Self(Union::Float(value))
|
||||
}
|
||||
}
|
||||
impl From<char> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: char) -> Self {
|
||||
Self(Union::Char(value))
|
||||
}
|
||||
}
|
||||
impl<S: Into<ImmutableString>> From<S> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: S) -> Self {
|
||||
Self(Union::Str(value.into()))
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
impl<T: Variant + Clone> From<Vec<T>> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: Vec<T>) -> Self {
|
||||
Self(Union::Array(Box::new(
|
||||
value.into_iter().map(Dynamic::from).collect(),
|
||||
@@ -1185,6 +1239,7 @@ impl<T: Variant + Clone> From<Vec<T>> for Dynamic {
|
||||
}
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
impl<T: Variant + Clone> From<&[T]> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: &[T]) -> Self {
|
||||
Self(Union::Array(Box::new(
|
||||
value.iter().cloned().map(Dynamic::from).collect(),
|
||||
@@ -1193,6 +1248,7 @@ impl<T: Variant + Clone> From<&[T]> for Dynamic {
|
||||
}
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
impl<K: Into<ImmutableString>, T: Variant + Clone> From<HashMap<K, T>> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: HashMap<K, T>) -> Self {
|
||||
Self(Union::Map(Box::new(
|
||||
value
|
||||
@@ -1203,11 +1259,13 @@ impl<K: Into<ImmutableString>, T: Variant + Clone> From<HashMap<K, T>> for Dynam
|
||||
}
|
||||
}
|
||||
impl From<FnPtr> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: FnPtr) -> Self {
|
||||
Self(Union::FnPtr(Box::new(value)))
|
||||
}
|
||||
}
|
||||
impl From<Box<FnPtr>> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: Box<FnPtr>) -> Self {
|
||||
Self(Union::FnPtr(value))
|
||||
}
|
||||
|
208
src/api.rs
208
src/api.rs
@@ -18,7 +18,7 @@ use crate::engine::{FN_IDX_GET, FN_IDX_SET};
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
use crate::{
|
||||
engine::{make_getter, make_setter, Map},
|
||||
fn_register::RegisterFn,
|
||||
fn_register::{RegisterFn, RegisterResultFn},
|
||||
token::Token,
|
||||
};
|
||||
|
||||
@@ -224,6 +224,54 @@ impl Engine {
|
||||
self.register_fn(&make_getter(name), callback)
|
||||
}
|
||||
|
||||
/// Register a getter function for a member of a registered type with the `Engine`.
|
||||
/// Returns `Result<Dynamic, Box<EvalAltResult>>`.
|
||||
///
|
||||
/// The function signature must start with `&mut self` and not `&self`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rhai::{Engine, Dynamic, EvalAltResult, RegisterFn};
|
||||
///
|
||||
/// #[derive(Clone)]
|
||||
/// struct TestStruct {
|
||||
/// field: i64
|
||||
/// }
|
||||
///
|
||||
/// impl TestStruct {
|
||||
/// fn new() -> Self { TestStruct { field: 1 } }
|
||||
///
|
||||
/// // Even a getter must start with `&mut self` and not `&self`.
|
||||
/// fn get_field(&mut self) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
/// Ok(self.field.into())
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||
/// let mut engine = Engine::new();
|
||||
///
|
||||
/// // Register the custom type.
|
||||
/// engine.register_type::<TestStruct>();
|
||||
///
|
||||
/// engine.register_fn("new_ts", TestStruct::new);
|
||||
///
|
||||
/// // Register a getter on a property (notice it doesn't have to be the same name).
|
||||
/// engine.register_get_result("xyz", TestStruct::get_field);
|
||||
///
|
||||
/// assert_eq!(engine.eval::<i64>("let a = new_ts(); a.xyz")?, 1);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
pub fn register_get_result<T: Variant + Clone>(
|
||||
&mut self,
|
||||
name: &str,
|
||||
callback: impl Fn(&mut T) -> Result<Dynamic, Box<EvalAltResult>> + SendSync + 'static,
|
||||
) -> &mut Self {
|
||||
self.register_result_fn(&make_getter(name), callback)
|
||||
}
|
||||
|
||||
/// Register a setter function for a member of a registered type with the `Engine`.
|
||||
///
|
||||
/// # Example
|
||||
@@ -273,6 +321,59 @@ impl Engine {
|
||||
self.register_fn(&make_setter(name), callback)
|
||||
}
|
||||
|
||||
/// Register a setter function for a member of a registered type with the `Engine`.
|
||||
/// Returns `Result<Dynamic, Box<EvalAltResult>>`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rhai::{Engine, Dynamic, EvalAltResult, RegisterFn};
|
||||
///
|
||||
/// #[derive(Debug, Clone, Eq, PartialEq)]
|
||||
/// struct TestStruct {
|
||||
/// field: i64
|
||||
/// }
|
||||
///
|
||||
/// impl TestStruct {
|
||||
/// fn new() -> Self { TestStruct { field: 1 } }
|
||||
/// fn set_field(&mut self, new_val: i64) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
/// self.field = new_val;
|
||||
/// Ok(().into())
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||
/// let mut engine = Engine::new();
|
||||
///
|
||||
/// // Register the custom type.
|
||||
/// engine.register_type::<TestStruct>();
|
||||
///
|
||||
/// engine.register_fn("new_ts", TestStruct::new);
|
||||
///
|
||||
/// // Register a setter on a property (notice it doesn't have to be the same name)
|
||||
/// engine.register_set_result("xyz", TestStruct::set_field);
|
||||
///
|
||||
/// // Notice that, with a getter, there is no way to get the property value
|
||||
/// assert_eq!(
|
||||
/// engine.eval::<TestStruct>("let a = new_ts(); a.xyz = 42; a")?,
|
||||
/// TestStruct { field: 42 }
|
||||
/// );
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
pub fn register_set_result<T, U>(
|
||||
&mut self,
|
||||
name: &str,
|
||||
callback: impl Fn(&mut T, U) -> Result<Dynamic, Box<EvalAltResult>> + SendSync + 'static,
|
||||
) -> &mut Self
|
||||
where
|
||||
T: Variant + Clone,
|
||||
U: Variant + Clone,
|
||||
{
|
||||
self.register_result_fn(&make_setter(name), callback)
|
||||
}
|
||||
|
||||
/// Shorthand for registering both getter and setter functions
|
||||
/// of a registered type with the `Engine`.
|
||||
///
|
||||
@@ -375,6 +476,58 @@ impl Engine {
|
||||
self.register_fn(FN_IDX_GET, callback)
|
||||
}
|
||||
|
||||
/// Register an index getter for a registered type with the `Engine`.
|
||||
/// Returns `Result<Dynamic, Box<EvalAltResult>>`.
|
||||
///
|
||||
/// The function signature must start with `&mut self` and not `&self`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rhai::{Engine, Dynamic, EvalAltResult, RegisterFn};
|
||||
///
|
||||
/// #[derive(Clone)]
|
||||
/// struct TestStruct {
|
||||
/// fields: Vec<i64>
|
||||
/// }
|
||||
///
|
||||
/// impl TestStruct {
|
||||
/// fn new() -> Self { TestStruct { fields: vec![1, 2, 3, 4, 5] } }
|
||||
///
|
||||
/// // Even a getter must start with `&mut self` and not `&self`.
|
||||
/// fn get_field(&mut self, index: i64) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
/// Ok(self.fields[index as usize].into())
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||
/// let mut engine = Engine::new();
|
||||
///
|
||||
/// // Register the custom type.
|
||||
/// engine.register_type::<TestStruct>();
|
||||
///
|
||||
/// engine.register_fn("new_ts", TestStruct::new);
|
||||
///
|
||||
/// // Register an indexer.
|
||||
/// engine.register_indexer_get_result(TestStruct::get_field);
|
||||
///
|
||||
/// assert_eq!(engine.eval::<i64>("let a = new_ts(); a[2]")?, 3);
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
pub fn register_indexer_get_result<T, X>(
|
||||
&mut self,
|
||||
callback: impl Fn(&mut T, X) -> Result<Dynamic, Box<EvalAltResult>> + SendSync + 'static,
|
||||
) -> &mut Self
|
||||
where
|
||||
T: Variant + Clone,
|
||||
X: Variant + Clone,
|
||||
{
|
||||
self.register_result_fn(FN_IDX_GET, callback)
|
||||
}
|
||||
|
||||
/// Register an index setter for a registered type with the `Engine`.
|
||||
///
|
||||
/// # Example
|
||||
@@ -424,6 +577,59 @@ impl Engine {
|
||||
self.register_fn(FN_IDX_SET, callback)
|
||||
}
|
||||
|
||||
/// Register an index setter for a registered type with the `Engine`.
|
||||
/// Returns `Result<Dynamic, Box<EvalAltResult>>`.
|
||||
///
|
||||
/// # Example
|
||||
///
|
||||
/// ```
|
||||
/// use rhai::{Engine, Dynamic, EvalAltResult, RegisterFn};
|
||||
///
|
||||
/// #[derive(Clone)]
|
||||
/// struct TestStruct {
|
||||
/// fields: Vec<i64>
|
||||
/// }
|
||||
///
|
||||
/// impl TestStruct {
|
||||
/// fn new() -> Self { TestStruct { fields: vec![1, 2, 3, 4, 5] } }
|
||||
/// fn set_field(&mut self, index: i64, value: i64) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||
/// self.fields[index as usize] = value;
|
||||
/// Ok(().into())
|
||||
/// }
|
||||
/// }
|
||||
///
|
||||
/// # fn main() -> Result<(), Box<rhai::EvalAltResult>> {
|
||||
/// let mut engine = Engine::new();
|
||||
///
|
||||
/// // Register the custom type.
|
||||
/// engine.register_type::<TestStruct>();
|
||||
///
|
||||
/// engine.register_fn("new_ts", TestStruct::new);
|
||||
///
|
||||
/// // Register an indexer.
|
||||
/// engine.register_indexer_set_result(TestStruct::set_field);
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// engine.eval::<TestStruct>("let a = new_ts(); a[2] = 42; a")?.fields[2],
|
||||
/// 42
|
||||
/// );
|
||||
/// # Ok(())
|
||||
/// # }
|
||||
/// ```
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
pub fn register_indexer_set_result<T, X, U>(
|
||||
&mut self,
|
||||
callback: impl Fn(&mut T, X, U) -> Result<Dynamic, Box<EvalAltResult>> + SendSync + 'static,
|
||||
) -> &mut Self
|
||||
where
|
||||
T: Variant + Clone,
|
||||
U: Variant + Clone,
|
||||
X: Variant + Clone,
|
||||
{
|
||||
self.register_result_fn(FN_IDX_SET, callback)
|
||||
}
|
||||
|
||||
/// Shorthand for register both index getter and setter functions for a registered type with the `Engine`.
|
||||
///
|
||||
/// # Example
|
||||
|
@@ -147,6 +147,7 @@ pub enum Target<'a> {
|
||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||
impl Target<'_> {
|
||||
/// Is the `Target` a reference pointing to other data?
|
||||
#[inline(always)]
|
||||
pub fn is_ref(&self) -> bool {
|
||||
match self {
|
||||
Self::Ref(_) => true,
|
||||
@@ -159,6 +160,7 @@ impl Target<'_> {
|
||||
}
|
||||
}
|
||||
/// Is the `Target` an owned value?
|
||||
#[inline(always)]
|
||||
pub fn is_value(&self) -> bool {
|
||||
match self {
|
||||
Self::Ref(_) => false,
|
||||
@@ -171,6 +173,7 @@ impl Target<'_> {
|
||||
}
|
||||
}
|
||||
/// Is the `Target` a shared value?
|
||||
#[inline(always)]
|
||||
pub fn is_shared(&self) -> bool {
|
||||
match self {
|
||||
Self::Ref(r) => r.is_shared(),
|
||||
@@ -184,6 +187,7 @@ impl Target<'_> {
|
||||
}
|
||||
/// Is the `Target` a specific type?
|
||||
#[allow(dead_code)]
|
||||
#[inline(always)]
|
||||
pub fn is<T: Variant + Clone>(&self) -> bool {
|
||||
match self {
|
||||
Target::Ref(r) => r.is::<T>(),
|
||||
@@ -196,6 +200,7 @@ impl Target<'_> {
|
||||
}
|
||||
}
|
||||
/// Get the value of the `Target` as a `Dynamic`, cloning a referenced value if necessary.
|
||||
#[inline(always)]
|
||||
pub fn clone_into_dynamic(self) -> Dynamic {
|
||||
match self {
|
||||
Self::Ref(r) => r.clone(), // Referenced value is cloned
|
||||
@@ -208,6 +213,7 @@ impl Target<'_> {
|
||||
}
|
||||
}
|
||||
/// Get a mutable reference from the `Target`.
|
||||
#[inline(always)]
|
||||
pub fn as_mut(&mut self) -> &mut Dynamic {
|
||||
match self {
|
||||
Self::Ref(r) => *r,
|
||||
@@ -258,6 +264,7 @@ impl Target<'_> {
|
||||
|
||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||
impl<'a> From<&'a mut Dynamic> for Target<'a> {
|
||||
#[inline(always)]
|
||||
fn from(value: &'a mut Dynamic) -> Self {
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
@@ -273,6 +280,7 @@ impl<'a> From<&'a mut Dynamic> for Target<'a> {
|
||||
|
||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||
impl<T: Into<Dynamic>> From<T> for Target<'_> {
|
||||
#[inline(always)]
|
||||
fn from(value: T) -> Self {
|
||||
Self::Value(value.into())
|
||||
}
|
||||
@@ -301,6 +309,7 @@ pub struct State {
|
||||
|
||||
impl State {
|
||||
/// Create a new `State`.
|
||||
#[inline(always)]
|
||||
pub fn new() -> Self {
|
||||
Default::default()
|
||||
}
|
||||
@@ -407,6 +416,7 @@ pub struct Engine {
|
||||
}
|
||||
|
||||
impl fmt::Debug for Engine {
|
||||
#[inline(always)]
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
match self.id.as_ref() {
|
||||
Some(id) => write!(f, "Engine({})", id),
|
||||
@@ -689,7 +699,7 @@ impl Engine {
|
||||
idx_values: &mut StaticVec<Dynamic>,
|
||||
chain_type: ChainType,
|
||||
level: usize,
|
||||
mut _new_val: Option<Dynamic>,
|
||||
new_val: Option<Dynamic>,
|
||||
) -> Result<(Dynamic, bool), Box<EvalAltResult>> {
|
||||
if chain_type == ChainType::None {
|
||||
panic!();
|
||||
@@ -722,12 +732,12 @@ impl Engine {
|
||||
|
||||
self.eval_dot_index_chain_helper(
|
||||
state, lib, this_ptr, obj_ptr, expr, idx_values, next_chain, level,
|
||||
_new_val,
|
||||
new_val,
|
||||
)
|
||||
.map_err(|err| err.new_position(*pos))
|
||||
}
|
||||
// xxx[rhs] = new_val
|
||||
_ if _new_val.is_some() => {
|
||||
_ if new_val.is_some() => {
|
||||
let mut idx_val2 = idx_val.clone();
|
||||
|
||||
// `call_setter` is introduced to bypass double mutable borrowing of target
|
||||
@@ -737,7 +747,7 @@ impl Engine {
|
||||
// Indexed value is a reference - update directly
|
||||
Ok(ref mut obj_ptr) => {
|
||||
obj_ptr
|
||||
.set_value(_new_val.unwrap())
|
||||
.set_value(new_val.unwrap())
|
||||
.map_err(|err| err.new_position(rhs.position()))?;
|
||||
|
||||
None
|
||||
@@ -747,7 +757,7 @@ impl Engine {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
EvalAltResult::ErrorIndexingType(_, _) => {
|
||||
// Raise error if there is no index getter nor setter
|
||||
Some(_new_val.unwrap())
|
||||
Some(new_val.unwrap())
|
||||
}
|
||||
// Any other error - return
|
||||
err => return Err(Box::new(err)),
|
||||
@@ -799,13 +809,13 @@ impl Engine {
|
||||
// xxx.module::fn_name(...) - syntax error
|
||||
Expr::FnCall(_) => unreachable!(),
|
||||
// {xxx:map}.id = ???
|
||||
Expr::Property(x) if target.is::<Map>() && _new_val.is_some() => {
|
||||
Expr::Property(x) if target.is::<Map>() && new_val.is_some() => {
|
||||
let ((prop, _, _), pos) = x.as_ref();
|
||||
let index = prop.clone().into();
|
||||
let mut val = self
|
||||
.get_indexed_mut(state, lib, target, index, *pos, true, false, level)?;
|
||||
|
||||
val.set_value(_new_val.unwrap())
|
||||
val.set_value(new_val.unwrap())
|
||||
.map_err(|err| err.new_position(rhs.position()))?;
|
||||
Ok((Default::default(), true))
|
||||
}
|
||||
@@ -820,9 +830,10 @@ impl Engine {
|
||||
Ok((val.clone_into_dynamic(), false))
|
||||
}
|
||||
// xxx.id = ???
|
||||
Expr::Property(x) if _new_val.is_some() => {
|
||||
Expr::Property(x) if new_val.is_some() => {
|
||||
let ((_, _, setter), pos) = x.as_ref();
|
||||
let mut args = [target.as_mut(), _new_val.as_mut().unwrap()];
|
||||
let mut new_val = new_val;
|
||||
let mut args = [target.as_mut(), new_val.as_mut().unwrap()];
|
||||
self.exec_fn_call(
|
||||
state, lib, setter, 0, &mut args, is_ref, true, false, None, None,
|
||||
level,
|
||||
@@ -872,7 +883,7 @@ impl Engine {
|
||||
|
||||
self.eval_dot_index_chain_helper(
|
||||
state, lib, this_ptr, &mut val, expr, idx_values, next_chain, level,
|
||||
_new_val,
|
||||
new_val,
|
||||
)
|
||||
.map_err(|err| err.new_position(*pos))
|
||||
}
|
||||
@@ -905,7 +916,7 @@ impl Engine {
|
||||
idx_values,
|
||||
next_chain,
|
||||
level,
|
||||
_new_val,
|
||||
new_val,
|
||||
)
|
||||
.map_err(|err| err.new_position(*pos))?;
|
||||
|
||||
@@ -944,7 +955,7 @@ impl Engine {
|
||||
|
||||
self.eval_dot_index_chain_helper(
|
||||
state, lib, this_ptr, target, expr, idx_values, next_chain,
|
||||
level, _new_val,
|
||||
level, new_val,
|
||||
)
|
||||
.map_err(|err| err.new_position(*pos))
|
||||
}
|
||||
@@ -1114,7 +1125,7 @@ impl Engine {
|
||||
state: &mut State,
|
||||
_lib: &Module,
|
||||
target: &'a mut Target,
|
||||
mut _idx: Dynamic,
|
||||
idx: Dynamic,
|
||||
idx_pos: Position,
|
||||
_create: bool,
|
||||
_indexers: bool,
|
||||
@@ -1132,7 +1143,7 @@ impl Engine {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Dynamic(Union::Array(arr)) => {
|
||||
// val_array[idx]
|
||||
let index = _idx
|
||||
let index = idx
|
||||
.as_int()
|
||||
.map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_pos))?;
|
||||
|
||||
@@ -1153,13 +1164,13 @@ impl Engine {
|
||||
Dynamic(Union::Map(map)) => {
|
||||
// val_map[idx]
|
||||
Ok(if _create {
|
||||
let index = _idx
|
||||
let index = idx
|
||||
.take_immutable_string()
|
||||
.map_err(|_| EvalAltResult::ErrorStringIndexExpr(idx_pos))?;
|
||||
|
||||
map.entry(index).or_insert(Default::default()).into()
|
||||
} else {
|
||||
let index = _idx
|
||||
let index = idx
|
||||
.read_lock::<ImmutableString>()
|
||||
.ok_or_else(|| EvalAltResult::ErrorStringIndexExpr(idx_pos))?;
|
||||
|
||||
@@ -1173,7 +1184,7 @@ impl Engine {
|
||||
Dynamic(Union::Str(s)) => {
|
||||
// val_string[idx]
|
||||
let chars_len = s.chars().count();
|
||||
let index = _idx
|
||||
let index = idx
|
||||
.as_int()
|
||||
.map_err(|_| EvalAltResult::ErrorNumericIndexExpr(idx_pos))?;
|
||||
|
||||
@@ -1192,7 +1203,8 @@ impl Engine {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
_ if _indexers => {
|
||||
let type_name = val.type_name();
|
||||
let args = &mut [val, &mut _idx];
|
||||
let mut idx = idx;
|
||||
let args = &mut [val, &mut idx];
|
||||
self.exec_fn_call(
|
||||
state, _lib, FN_IDX_GET, 0, args, is_ref, true, false, None, None, _level,
|
||||
)
|
||||
@@ -1331,11 +1343,11 @@ impl Engine {
|
||||
)),
|
||||
// Normal assignment
|
||||
ScopeEntryType::Normal if op.is_empty() => {
|
||||
let rhs_val = rhs_val.clone_inner_data().unwrap();
|
||||
let value = rhs_val.flatten();
|
||||
if cfg!(not(feature = "no_closure")) && lhs_ptr.is_shared() {
|
||||
*lhs_ptr.write_lock::<Dynamic>().unwrap() = rhs_val;
|
||||
*lhs_ptr.write_lock::<Dynamic>().unwrap() = value;
|
||||
} else {
|
||||
*lhs_ptr = rhs_val;
|
||||
*lhs_ptr = value;
|
||||
}
|
||||
Ok(Default::default())
|
||||
}
|
||||
@@ -1378,7 +1390,7 @@ impl Engine {
|
||||
)
|
||||
.map_err(|err| err.new_position(*op_pos))?;
|
||||
|
||||
let value = value.clone_inner_data().unwrap();
|
||||
let value = value.flatten();
|
||||
if cfg!(not(feature = "no_closure")) && lhs_ptr.is_shared() {
|
||||
*lhs_ptr.write_lock::<Dynamic>().unwrap() = value;
|
||||
} else {
|
||||
@@ -1674,14 +1686,14 @@ impl Engine {
|
||||
let index = scope.len() - 1;
|
||||
state.scope_level += 1;
|
||||
|
||||
for loop_var in func(iter_type) {
|
||||
let for_var = scope.get_mut(index).0;
|
||||
let value = loop_var.clone_inner_data().unwrap();
|
||||
for iter_value in func(iter_type) {
|
||||
let (loop_var, _) = scope.get_mut(index);
|
||||
|
||||
if cfg!(not(feature = "no_closure")) && for_var.is_shared() {
|
||||
*for_var.write_lock().unwrap() = value;
|
||||
let value = iter_value.flatten();
|
||||
if cfg!(not(feature = "no_closure")) && loop_var.is_shared() {
|
||||
*loop_var.write_lock().unwrap() = value;
|
||||
} else {
|
||||
*for_var = value;
|
||||
*loop_var = value;
|
||||
}
|
||||
|
||||
self.inc_operations(state)
|
||||
@@ -1750,8 +1762,7 @@ impl Engine {
|
||||
let expr = expr.as_ref().unwrap();
|
||||
let val = self
|
||||
.eval_expr(scope, mods, state, lib, this_ptr, expr, level)?
|
||||
.clone_inner_data()
|
||||
.unwrap();
|
||||
.flatten();
|
||||
let var_name = unsafe_cast_var_name_to_lifetime(var_name, &state);
|
||||
scope.push_dynamic_value(var_name, ScopeEntryType::Normal, val, false);
|
||||
Ok(Default::default())
|
||||
@@ -1769,8 +1780,7 @@ impl Engine {
|
||||
let ((var_name, _), expr, _) = x.as_ref();
|
||||
let val = self
|
||||
.eval_expr(scope, mods, state, lib, this_ptr, &expr, level)?
|
||||
.clone_inner_data()
|
||||
.unwrap();
|
||||
.flatten();
|
||||
let var_name = unsafe_cast_var_name_to_lifetime(var_name, &state);
|
||||
scope.push_dynamic_value(var_name, ScopeEntryType::Constant, val, true);
|
||||
Ok(Default::default())
|
||||
@@ -2000,6 +2010,7 @@ impl Engine {
|
||||
}
|
||||
|
||||
/// Map a type_name into a pretty-print name
|
||||
#[inline(always)]
|
||||
pub(crate) fn map_type_name<'a>(&'a self, name: &'a str) -> &'a str {
|
||||
self.type_names
|
||||
.as_ref()
|
||||
|
@@ -929,11 +929,11 @@ impl Engine {
|
||||
self.inc_operations(state)
|
||||
.map_err(|err| err.new_position(pos))?;
|
||||
|
||||
// Turn it into a method call only if the object is not shared
|
||||
args = if target.is_shared() {
|
||||
arg_values.insert(0, target.clone().clone_inner_data().unwrap());
|
||||
arg_values.insert(0, target.get_inner_clone());
|
||||
arg_values.iter_mut().collect()
|
||||
} else {
|
||||
// Turn it into a method call only if the object is not shared
|
||||
is_ref = true;
|
||||
once(target).chain(arg_values.iter_mut()).collect()
|
||||
};
|
||||
|
@@ -22,13 +22,6 @@ use crate::stdlib::rc::Rc;
|
||||
#[cfg(feature = "sync")]
|
||||
use crate::stdlib::sync::Arc;
|
||||
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "sync"))]
|
||||
use crate::stdlib::cell::RefCell;
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(feature = "sync")]
|
||||
use crate::stdlib::sync::RwLock;
|
||||
|
||||
/// Trait that maps to `Send + Sync` only under the `sync` feature.
|
||||
#[cfg(feature = "sync")]
|
||||
pub trait SendSync: Send + Sync {}
|
||||
@@ -50,15 +43,6 @@ pub type Shared<T> = Rc<T>;
|
||||
#[cfg(feature = "sync")]
|
||||
pub type Shared<T> = Arc<T>;
|
||||
|
||||
/// Mutable reference-counted container (read-write lock)
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(not(feature = "sync"))]
|
||||
pub type SharedMut<T> = Shared<RefCell<T>>;
|
||||
/// Mutable reference-counted container (read-write lock)
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
#[cfg(feature = "sync")]
|
||||
pub type SharedMut<T> = Shared<RwLock<T>>;
|
||||
|
||||
/// Consume a `Shared` resource and return a mutable reference to the wrapped value.
|
||||
/// If the resource is shared (i.e. has other outstanding references), a cloned copy is used.
|
||||
pub fn shared_make_mut<T: Clone>(value: &mut Shared<T>) -> &mut T {
|
||||
@@ -68,16 +52,21 @@ pub fn shared_make_mut<T: Clone>(value: &mut Shared<T>) -> &mut T {
|
||||
return Arc::make_mut(value);
|
||||
}
|
||||
|
||||
/// Consume a `Shared` resource if is unique (i.e. not shared).
|
||||
pub fn shared_try_take<T: Clone>(value: Shared<T>) -> Result<T, Shared<T>> {
|
||||
#[cfg(not(feature = "sync"))]
|
||||
return Rc::try_unwrap(value);
|
||||
#[cfg(feature = "sync")]
|
||||
return Arc::try_unwrap(value);
|
||||
}
|
||||
|
||||
/// Consume a `Shared` resource, assuming that it is unique (i.e. not shared).
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the resource is shared (i.e. has other outstanding references).
|
||||
pub fn shared_take<T: Clone>(value: Shared<T>) -> T {
|
||||
#[cfg(not(feature = "sync"))]
|
||||
return Rc::try_unwrap(value).map_err(|_| ()).unwrap();
|
||||
#[cfg(feature = "sync")]
|
||||
return Arc::try_unwrap(value).map_err(|_| ()).unwrap();
|
||||
shared_try_take(value).map_err(|_| ()).unwrap()
|
||||
}
|
||||
|
||||
pub type FnCallArgs<'a> = [&'a mut Dynamic];
|
||||
|
@@ -338,7 +338,7 @@ impl<'a> Scope<'a> {
|
||||
/// ```
|
||||
pub fn get_value<T: Variant + Clone>(&self, name: &str) -> Option<T> {
|
||||
self.get_entry(name)
|
||||
.and_then(|Entry { value, .. }| value.clone().clone_inner_data::<T>())
|
||||
.and_then(|Entry { value, .. }| value.get_inner_clone().try_cast())
|
||||
}
|
||||
|
||||
/// Update the value of the named entry.
|
||||
@@ -441,7 +441,7 @@ impl<'a> Scope<'a> {
|
||||
/// ```
|
||||
pub fn iter(&self) -> impl Iterator<Item = (&str, Dynamic)> {
|
||||
self.iter_raw()
|
||||
.map(|(name, value)| (name, value.clone().clone_inner_data().unwrap()))
|
||||
.map(|(name, value)| (name, value.get_inner_clone()))
|
||||
}
|
||||
|
||||
/// Get an iterator to entries in the Scope.
|
||||
|
Reference in New Issue
Block a user