Add Dynamic::is_XXX API.
This commit is contained in:
parent
ad018aaae3
commit
ce046422f0
@ -25,6 +25,11 @@ Breaking changes
|
|||||||
New features
|
New features
|
||||||
------------
|
------------
|
||||||
|
|
||||||
|
### `Dynamic` detection API
|
||||||
|
|
||||||
|
* New methods are added to `Dynamic` in the form of `is_XXX()` where `XXX` is a type (e.g. `is_int`, `is_unit`, `is_bool`, `is_array`).
|
||||||
|
* This new API is to make it easier to detect the data type, instead of having to call `is::<XXX>()`.
|
||||||
|
|
||||||
### Loop expressions
|
### Loop expressions
|
||||||
|
|
||||||
* Loops (such as `loop`, `do`, `while` and `for`) can now act as _expressions_, with the `break` statement returning an optional value.
|
* Loops (such as `loop`, `do`, `while` and `for`) can now act as _expressions_, with the `break` statement returning an optional value.
|
||||||
@ -37,9 +42,9 @@ New features
|
|||||||
* This is necessary when using Rhai across shared-library boundaries.
|
* This is necessary when using Rhai across shared-library boundaries.
|
||||||
* A build script is used to extract the environment variable (`RHAI_AHASH_SEED`, if any) and splice it into the source code before compilation.
|
* A build script is used to extract the environment variable (`RHAI_AHASH_SEED`, if any) and splice it into the source code before compilation.
|
||||||
|
|
||||||
### No Timestamps
|
### `no_time` for no timestamps
|
||||||
|
|
||||||
* A new feature, `no_time`, is added to disable support timestamps.
|
* A new feature, `no_time`, is added to disable support for timestamps.
|
||||||
* This may be necessary when building for architectures without time support, such as raw WASM.
|
* This may be necessary when building for architectures without time support, such as raw WASM.
|
||||||
|
|
||||||
### Serializable `Scope`
|
### Serializable `Scope`
|
||||||
|
@ -99,6 +99,10 @@ impl Engine {
|
|||||||
///
|
///
|
||||||
/// To define a pretty-print name, call [`with_name`][`TypeBuilder::with_name`],
|
/// To define a pretty-print name, call [`with_name`][`TypeBuilder::with_name`],
|
||||||
/// to use [`Engine::register_type_with_name`] instead.
|
/// to use [`Engine::register_type_with_name`] instead.
|
||||||
|
///
|
||||||
|
/// # WARNING - Volatile Type
|
||||||
|
///
|
||||||
|
/// This type is volatile and may change in the future.
|
||||||
#[deprecated = "This type is NOT deprecated, but it is considered volatile and may change in the future."]
|
#[deprecated = "This type is NOT deprecated, but it is considered volatile and may change in the future."]
|
||||||
pub struct TypeBuilder<'a, T: Variant + Clone> {
|
pub struct TypeBuilder<'a, T: Variant + Clone> {
|
||||||
engine: &'a mut Engine,
|
engine: &'a mut Engine,
|
||||||
|
@ -89,6 +89,7 @@ impl Expression<'_> {
|
|||||||
/// # WARNING - Low Level API
|
/// # WARNING - Low Level API
|
||||||
///
|
///
|
||||||
/// This function is _extremely_ low level. It evaluates an expression from an [`AST`][crate::AST].
|
/// This function is _extremely_ low level. It evaluates an expression from an [`AST`][crate::AST].
|
||||||
|
#[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn eval_with_context_raw(
|
pub fn eval_with_context_raw(
|
||||||
&self,
|
&self,
|
||||||
|
@ -166,7 +166,7 @@ pub fn format_map_as_json(map: &Map) -> String {
|
|||||||
|
|
||||||
if let Some(val) = value.read_lock::<Map>() {
|
if let Some(val) = value.read_lock::<Map>() {
|
||||||
result.push_str(&format_map_as_json(&*val));
|
result.push_str(&format_map_as_json(&*val));
|
||||||
} else if value.is::<()>() {
|
} else if value.is_unit() {
|
||||||
result.push_str("null");
|
result.push_str("null");
|
||||||
} else {
|
} else {
|
||||||
write!(result, "{:?}", value).unwrap();
|
write!(result, "{:?}", value).unwrap();
|
||||||
|
@ -559,7 +559,7 @@ fn main() {
|
|||||||
// Evaluate
|
// Evaluate
|
||||||
engine.eval_ast_with_scope::<Dynamic>(&mut scope, &main_ast)
|
engine.eval_ast_with_scope::<Dynamic>(&mut scope, &main_ast)
|
||||||
}) {
|
}) {
|
||||||
Ok(result) if !result.is::<()>() => {
|
Ok(result) if !result.is_unit() => {
|
||||||
println!("=> {result:?}");
|
println!("=> {result:?}");
|
||||||
println!();
|
println!();
|
||||||
}
|
}
|
||||||
|
@ -63,7 +63,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
ChainType::Indexing => {
|
ChainType::Indexing => {
|
||||||
// Check for existence with the null conditional operator
|
// Check for existence with the null conditional operator
|
||||||
if parent_options.contains(ASTFlags::NEGATED) && target.is::<()>() {
|
if parent_options.contains(ASTFlags::NEGATED) && target.is_unit() {
|
||||||
return Ok((Dynamic::UNIT, false));
|
return Ok((Dynamic::UNIT, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +189,7 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_object"))]
|
#[cfg(not(feature = "no_object"))]
|
||||||
ChainType::Dotting => {
|
ChainType::Dotting => {
|
||||||
// Check for existence with the Elvis operator
|
// Check for existence with the Elvis operator
|
||||||
if parent_options.contains(ASTFlags::NEGATED) && target.is::<()>() {
|
if parent_options.contains(ASTFlags::NEGATED) && target.is_unit() {
|
||||||
return Ok((Dynamic::UNIT, false));
|
return Ok((Dynamic::UNIT, false));
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -229,7 +229,7 @@ impl Engine {
|
|||||||
unreachable!("function call in dot chain should not be namespace-qualified")
|
unreachable!("function call in dot chain should not be namespace-qualified")
|
||||||
}
|
}
|
||||||
// {xxx:map}.id op= ???
|
// {xxx:map}.id op= ???
|
||||||
Expr::Property(x, pos) if target.is::<crate::Map>() && new_val.is_some() => {
|
Expr::Property(x, pos) if target.is_map() && new_val.is_some() => {
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
self.run_debugger(global, caches, lib, scope, this_ptr, rhs)?;
|
self.run_debugger(global, caches, lib, scope, this_ptr, rhs)?;
|
||||||
|
|
||||||
@ -247,7 +247,7 @@ impl Engine {
|
|||||||
Ok((Dynamic::UNIT, true))
|
Ok((Dynamic::UNIT, true))
|
||||||
}
|
}
|
||||||
// {xxx:map}.id
|
// {xxx:map}.id
|
||||||
Expr::Property(x, pos) if target.is::<crate::Map>() => {
|
Expr::Property(x, pos) if target.is_map() => {
|
||||||
#[cfg(feature = "debugging")]
|
#[cfg(feature = "debugging")]
|
||||||
self.run_debugger(global, caches, lib, scope, this_ptr, rhs)?;
|
self.run_debugger(global, caches, lib, scope, this_ptr, rhs)?;
|
||||||
|
|
||||||
@ -351,7 +351,7 @@ impl Engine {
|
|||||||
}
|
}
|
||||||
// {xxx:map}.sub_lhs[expr] | {xxx:map}.sub_lhs.expr
|
// {xxx:map}.sub_lhs[expr] | {xxx:map}.sub_lhs.expr
|
||||||
Expr::Index(x, options, x_pos) | Expr::Dot(x, options, x_pos)
|
Expr::Index(x, options, x_pos) | Expr::Dot(x, options, x_pos)
|
||||||
if target.is::<crate::Map>() =>
|
if target.is_map() =>
|
||||||
{
|
{
|
||||||
let _node = &x.lhs;
|
let _node = &x.lhs;
|
||||||
|
|
||||||
|
@ -287,7 +287,7 @@ impl Engine {
|
|||||||
|
|
||||||
// `... ${...} ...`
|
// `... ${...} ...`
|
||||||
Expr::InterpolatedString(x, _) => {
|
Expr::InterpolatedString(x, _) => {
|
||||||
let mut concat = self.get_interned_string("").into();
|
let mut concat = self.const_empty_string().into();
|
||||||
let target = &mut concat;
|
let target = &mut concat;
|
||||||
|
|
||||||
let mut op_info = OpAssignment::new_op_assignment(OP_CONCAT, Position::NONE);
|
let mut op_info = OpAssignment::new_op_assignment(OP_CONCAT, Position::NONE);
|
||||||
@ -296,7 +296,9 @@ impl Engine {
|
|||||||
let result = x
|
let result = x
|
||||||
.iter()
|
.iter()
|
||||||
.try_for_each(|expr| {
|
.try_for_each(|expr| {
|
||||||
let item = self.eval_expr(global, caches, lib, scope, this_ptr, expr)?;
|
let item = self
|
||||||
|
.eval_expr(global, caches, lib, scope, this_ptr, expr)?
|
||||||
|
.flatten();
|
||||||
|
|
||||||
op_info.pos = expr.start_position();
|
op_info.pos = expr.start_position();
|
||||||
|
|
||||||
@ -394,7 +396,7 @@ impl Engine {
|
|||||||
Expr::Coalesce(x, ..) => {
|
Expr::Coalesce(x, ..) => {
|
||||||
let value = self.eval_expr(global, caches, lib, scope, this_ptr, &x.lhs)?;
|
let value = self.eval_expr(global, caches, lib, scope, this_ptr, &x.lhs)?;
|
||||||
|
|
||||||
if value.is::<()>() {
|
if value.is_unit() {
|
||||||
self.eval_expr(global, caches, lib, scope, this_ptr, &x.rhs)
|
self.eval_expr(global, caches, lib, scope, this_ptr, &x.rhs)
|
||||||
} else {
|
} else {
|
||||||
Ok(value)
|
Ok(value)
|
||||||
|
@ -8,7 +8,10 @@ use crate::ast::{
|
|||||||
use crate::func::{get_builtin_op_assignment_fn, get_hasher};
|
use crate::func::{get_builtin_op_assignment_fn, get_hasher};
|
||||||
use crate::types::dynamic::{AccessMode, Union};
|
use crate::types::dynamic::{AccessMode, Union};
|
||||||
use crate::types::RestoreOnDrop;
|
use crate::types::RestoreOnDrop;
|
||||||
use crate::{Dynamic, Engine, Position, RhaiResult, RhaiResultOf, Scope, SharedModule, ERR, INT};
|
use crate::{
|
||||||
|
Dynamic, Engine, ImmutableString, Position, RhaiResult, RhaiResultOf, Scope, SharedModule, ERR,
|
||||||
|
INT,
|
||||||
|
};
|
||||||
use std::hash::{Hash, Hasher};
|
use std::hash::{Hash, Hasher};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -174,8 +177,7 @@ impl Engine {
|
|||||||
global, caches, lib, op, token, *hash_op, args, true, *op_pos,
|
global, caches, lib, op, token, *hash_op, args, true, *op_pos,
|
||||||
)
|
)
|
||||||
.map_err(|err| err.fill_position(op_info.pos))?
|
.map_err(|err| err.fill_position(op_info.pos))?
|
||||||
.0
|
.0;
|
||||||
.flatten();
|
|
||||||
}
|
}
|
||||||
Err(err) => return Err(err),
|
Err(err) => return Err(err),
|
||||||
}
|
}
|
||||||
@ -183,6 +185,13 @@ impl Engine {
|
|||||||
self.check_data_size(args[0], root.1)?;
|
self.check_data_size(args[0], root.1)?;
|
||||||
} else {
|
} else {
|
||||||
// Normal assignment
|
// Normal assignment
|
||||||
|
|
||||||
|
// If value is a string, intern it
|
||||||
|
if new_val.is_string() {
|
||||||
|
let value = new_val.into_immutable_string().expect("`ImmutableString`");
|
||||||
|
new_val = self.get_interned_string(value).into();
|
||||||
|
}
|
||||||
|
|
||||||
*target.write_lock::<Dynamic>().unwrap() = new_val;
|
*target.write_lock::<Dynamic>().unwrap() = new_val;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -257,34 +266,27 @@ impl Engine {
|
|||||||
let root = (var_name, pos);
|
let root = (var_name, pos);
|
||||||
let lhs_ptr = &mut lhs_ptr;
|
let lhs_ptr = &mut lhs_ptr;
|
||||||
|
|
||||||
return self
|
self.eval_op_assignment(global, caches, lib, op_info, lhs_ptr, root, rhs_val)?;
|
||||||
.eval_op_assignment(global, caches, lib, op_info, lhs_ptr, root, rhs_val)
|
|
||||||
.map(|_| Dynamic::UNIT);
|
return Ok(Dynamic::UNIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||||
{
|
{
|
||||||
let rhs_val = self.eval_expr(global, caches, lib, scope, this_ptr, rhs)?;
|
let mut rhs_val = self
|
||||||
|
.eval_expr(global, caches, lib, scope, this_ptr, rhs)?
|
||||||
|
.flatten();
|
||||||
|
|
||||||
// Check if the result is a string. If so, intern it.
|
// If value is a string, intern it
|
||||||
#[cfg(not(feature = "no_closure"))]
|
if rhs_val.is_string() {
|
||||||
let is_string = !rhs_val.is_shared() && rhs_val.is::<crate::ImmutableString>();
|
let value = rhs_val.into_immutable_string().expect("`ImmutableString`");
|
||||||
#[cfg(feature = "no_closure")]
|
rhs_val = self.get_interned_string(value).into();
|
||||||
let is_string = rhs_val.is::<crate::ImmutableString>();
|
}
|
||||||
|
|
||||||
let rhs_val = if is_string {
|
|
||||||
self.get_interned_string(
|
|
||||||
rhs_val.into_immutable_string().expect("`ImmutableString`"),
|
|
||||||
)
|
|
||||||
.into()
|
|
||||||
} else {
|
|
||||||
rhs_val.flatten()
|
|
||||||
};
|
|
||||||
|
|
||||||
let _new_val = &mut Some((rhs_val, op_info));
|
let _new_val = &mut Some((rhs_val, op_info));
|
||||||
|
|
||||||
// Must be either `var[index] op= val` or `var.prop op= val`
|
// Must be either `var[index] op= val` or `var.prop op= val`
|
||||||
return match lhs {
|
match lhs {
|
||||||
// name op= rhs (handled above)
|
// name op= rhs (handled above)
|
||||||
Expr::Variable(..) => {
|
Expr::Variable(..) => {
|
||||||
unreachable!("Expr::Variable case is already handled")
|
unreachable!("Expr::Variable case is already handled")
|
||||||
@ -298,8 +300,9 @@ impl Engine {
|
|||||||
Expr::Dot(..) => self
|
Expr::Dot(..) => self
|
||||||
.eval_dot_index_chain(global, caches, lib, scope, this_ptr, lhs, _new_val),
|
.eval_dot_index_chain(global, caches, lib, scope, this_ptr, lhs, _new_val),
|
||||||
_ => unreachable!("cannot assign to expression: {:?}", lhs),
|
_ => unreachable!("cannot assign to expression: {:?}", lhs),
|
||||||
}
|
}?;
|
||||||
.map(|_| Dynamic::UNIT);
|
|
||||||
|
return Ok(Dynamic::UNIT);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -381,7 +384,7 @@ impl Engine {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if value.is::<INT>() && !ranges.is_empty() {
|
} else if value.is_int() && !ranges.is_empty() {
|
||||||
// Then check integer ranges
|
// Then check integer ranges
|
||||||
let value = value.as_int().expect("`INT`");
|
let value = value.as_int().expect("`INT`");
|
||||||
|
|
||||||
@ -803,8 +806,8 @@ impl Engine {
|
|||||||
|
|
||||||
let v = self.eval_expr(global, caches, lib, scope, this_ptr, expr)?;
|
let v = self.eval_expr(global, caches, lib, scope, this_ptr, expr)?;
|
||||||
let typ = v.type_name();
|
let typ = v.type_name();
|
||||||
let path = v.try_cast::<crate::ImmutableString>().ok_or_else(|| {
|
let path = v.try_cast::<ImmutableString>().ok_or_else(|| {
|
||||||
self.make_type_mismatch_err::<crate::ImmutableString>(typ, expr.position())
|
self.make_type_mismatch_err::<ImmutableString>(typ, expr.position())
|
||||||
})?;
|
})?;
|
||||||
|
|
||||||
use crate::ModuleResolver;
|
use crate::ModuleResolver;
|
||||||
@ -832,7 +835,7 @@ impl Engine {
|
|||||||
let (export, must_be_indexed) = if !export.is_empty() {
|
let (export, must_be_indexed) = if !export.is_empty() {
|
||||||
(export.name.clone(), true)
|
(export.name.clone(), true)
|
||||||
} else {
|
} else {
|
||||||
(self.get_interned_string(""), false)
|
(self.const_empty_string(), false)
|
||||||
};
|
};
|
||||||
|
|
||||||
if !must_be_indexed || module.is_indexed() {
|
if !must_be_indexed || module.is_indexed() {
|
||||||
|
@ -145,7 +145,7 @@ impl Engine {
|
|||||||
format!(
|
format!(
|
||||||
"{fn_name} ({})",
|
"{fn_name} ({})",
|
||||||
args.iter()
|
args.iter()
|
||||||
.map(|a| if a.is::<ImmutableString>() {
|
.map(|a| if a.is_string() {
|
||||||
"&str | ImmutableString | String"
|
"&str | ImmutableString | String"
|
||||||
} else {
|
} else {
|
||||||
self.map_type_name(a.type_name())
|
self.map_type_name(a.type_name())
|
||||||
@ -574,7 +574,7 @@ impl Engine {
|
|||||||
// Handle is_def_fn()
|
// Handle is_def_fn()
|
||||||
#[cfg(not(feature = "no_function"))]
|
#[cfg(not(feature = "no_function"))]
|
||||||
crate::engine::KEYWORD_IS_DEF_FN
|
crate::engine::KEYWORD_IS_DEF_FN
|
||||||
if args.len() == 2 && args[0].is::<FnPtr>() && args[1].is::<crate::INT>() =>
|
if args.len() == 2 && args[0].is_fnptr() && args[1].is_int() =>
|
||||||
{
|
{
|
||||||
let fn_name = args[0].read_lock::<ImmutableString>().expect("`FnPtr`");
|
let fn_name = args[0].read_lock::<ImmutableString>().expect("`FnPtr`");
|
||||||
let num_params = args[1].as_int().expect("`INT`");
|
let num_params = args[1].as_int().expect("`INT`");
|
||||||
@ -731,7 +731,7 @@ impl Engine {
|
|||||||
let is_ref_mut = target.is_ref();
|
let is_ref_mut = target.is_ref();
|
||||||
|
|
||||||
let (result, updated) = match fn_name {
|
let (result, updated) = match fn_name {
|
||||||
KEYWORD_FN_PTR_CALL if target.is::<FnPtr>() => {
|
KEYWORD_FN_PTR_CALL if target.is_fnptr() => {
|
||||||
// FnPtr call
|
// FnPtr call
|
||||||
let fn_ptr = target.read_lock::<FnPtr>().expect("`FnPtr`");
|
let fn_ptr = target.read_lock::<FnPtr>().expect("`FnPtr`");
|
||||||
|
|
||||||
@ -775,7 +775,7 @@ impl Engine {
|
|||||||
if call_args.is_empty() {
|
if call_args.is_empty() {
|
||||||
let typ = self.map_type_name(target.type_name());
|
let typ = self.map_type_name(target.type_name());
|
||||||
return Err(self.make_type_mismatch_err::<FnPtr>(typ, fn_call_pos));
|
return Err(self.make_type_mismatch_err::<FnPtr>(typ, fn_call_pos));
|
||||||
} else if !call_args[0].is::<FnPtr>() {
|
} else if !call_args[0].is_fnptr() {
|
||||||
let typ = self.map_type_name(call_args[0].type_name());
|
let typ = self.map_type_name(call_args[0].type_name());
|
||||||
return Err(self.make_type_mismatch_err::<FnPtr>(typ, first_arg_pos));
|
return Err(self.make_type_mismatch_err::<FnPtr>(typ, first_arg_pos));
|
||||||
}
|
}
|
||||||
@ -827,7 +827,7 @@ impl Engine {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
KEYWORD_FN_PTR_CURRY => {
|
KEYWORD_FN_PTR_CURRY => {
|
||||||
if !target.is::<FnPtr>() {
|
if !target.is_fnptr() {
|
||||||
let typ = self.map_type_name(target.type_name());
|
let typ = self.map_type_name(target.type_name());
|
||||||
return Err(self.make_type_mismatch_err::<FnPtr>(typ, fn_call_pos));
|
return Err(self.make_type_mismatch_err::<FnPtr>(typ, fn_call_pos));
|
||||||
}
|
}
|
||||||
@ -969,7 +969,7 @@ impl Engine {
|
|||||||
let (arg_value, arg_pos) =
|
let (arg_value, arg_pos) =
|
||||||
self.get_arg_value(global, caches, lib, scope, this_ptr, arg)?;
|
self.get_arg_value(global, caches, lib, scope, this_ptr, arg)?;
|
||||||
|
|
||||||
if !arg_value.is::<FnPtr>() {
|
if !arg_value.is_fnptr() {
|
||||||
let typ = self.map_type_name(arg_value.type_name());
|
let typ = self.map_type_name(arg_value.type_name());
|
||||||
return Err(self.make_type_mismatch_err::<FnPtr>(typ, arg_pos));
|
return Err(self.make_type_mismatch_err::<FnPtr>(typ, arg_pos));
|
||||||
}
|
}
|
||||||
@ -1025,7 +1025,7 @@ impl Engine {
|
|||||||
let (arg_value, arg_pos) =
|
let (arg_value, arg_pos) =
|
||||||
self.get_arg_value(global, caches, lib, scope, this_ptr, first)?;
|
self.get_arg_value(global, caches, lib, scope, this_ptr, first)?;
|
||||||
|
|
||||||
if !arg_value.is::<FnPtr>() {
|
if !arg_value.is_fnptr() {
|
||||||
let typ = self.map_type_name(arg_value.type_name());
|
let typ = self.map_type_name(arg_value.type_name());
|
||||||
return Err(self.make_type_mismatch_err::<FnPtr>(typ, arg_pos));
|
return Err(self.make_type_mismatch_err::<FnPtr>(typ, arg_pos));
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ pub use callable_function::CallableFunction;
|
|||||||
pub use func::Func;
|
pub use func::Func;
|
||||||
pub use hashing::{calc_fn_hash, calc_fn_hash_full, calc_var_hash, get_hasher, StraightHashMap};
|
pub use hashing::{calc_fn_hash, calc_fn_hash_full, calc_var_hash, get_hasher, StraightHashMap};
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
|
#[allow(deprecated)]
|
||||||
pub use native::NativeCallContextStore;
|
pub use native::NativeCallContextStore;
|
||||||
pub use native::{
|
pub use native::{
|
||||||
locked_read, locked_write, shared_get_mut, shared_make_mut, shared_take, shared_take_or_clone,
|
locked_read, locked_write, shared_get_mut, shared_make_mut, shared_take, shared_take_or_clone,
|
||||||
|
@ -81,6 +81,11 @@ pub struct NativeCallContext<'a> {
|
|||||||
|
|
||||||
/// _(internals)_ Context of a native Rust function call.
|
/// _(internals)_ Context of a native Rust function call.
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
|
///
|
||||||
|
/// # WARNING - Volatile Type
|
||||||
|
///
|
||||||
|
/// This type is volatile and may change in the future.
|
||||||
|
#[deprecated = "This type is NOT deprecated, but it is considered volatile and may change in the future."]
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
pub struct NativeCallContextStore {
|
pub struct NativeCallContextStore {
|
||||||
@ -97,8 +102,14 @@ pub struct NativeCallContextStore {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
|
#[allow(deprecated)]
|
||||||
impl NativeCallContextStore {
|
impl NativeCallContextStore {
|
||||||
/// Create a [`NativeCallContext`] from a [`NativeCallContextClone`].
|
/// Create a [`NativeCallContext`] from a [`NativeCallContextClone`].
|
||||||
|
///
|
||||||
|
/// # WARNING - Unstable API
|
||||||
|
///
|
||||||
|
/// This API is volatile and may change in the future.
|
||||||
|
#[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub fn create_context<'a>(&'a self, engine: &'a Engine) -> NativeCallContext<'a> {
|
pub fn create_context<'a>(&'a self, engine: &'a Engine) -> NativeCallContext<'a> {
|
||||||
@ -167,9 +178,15 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
|
|
||||||
/// _(internals)_ Create a [`NativeCallContext`] from a [`NativeCallContextClone`].
|
/// _(internals)_ Create a [`NativeCallContext`] from a [`NativeCallContextClone`].
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
|
///
|
||||||
|
/// # WARNING - Unstable API
|
||||||
|
///
|
||||||
|
/// This API is volatile and may change in the future.
|
||||||
|
#[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."]
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
#[allow(deprecated)]
|
||||||
pub fn from_stored_data(engine: &'a Engine, context: &'a NativeCallContextStore) -> Self {
|
pub fn from_stored_data(engine: &'a Engine, context: &'a NativeCallContextStore) -> Self {
|
||||||
Self {
|
Self {
|
||||||
engine,
|
engine,
|
||||||
@ -182,9 +199,15 @@ impl<'a> NativeCallContext<'a> {
|
|||||||
}
|
}
|
||||||
/// _(internals)_ Store this [`NativeCallContext`] into a [`NativeCallContextClone`].
|
/// _(internals)_ Store this [`NativeCallContext`] into a [`NativeCallContextClone`].
|
||||||
/// Exported under the `internals` feature only.
|
/// Exported under the `internals` feature only.
|
||||||
|
///
|
||||||
|
/// # WARNING - Unstable API
|
||||||
|
///
|
||||||
|
/// This API is volatile and may change in the future.
|
||||||
|
#[deprecated = "This API is NOT deprecated, but it is considered volatile and may change in the future."]
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
#[inline]
|
#[inline]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
|
#[allow(deprecated)]
|
||||||
pub fn store_data(&self) -> NativeCallContextStore {
|
pub fn store_data(&self) -> NativeCallContextStore {
|
||||||
NativeCallContextStore {
|
NativeCallContextStore {
|
||||||
fn_name: self.fn_name.to_string(),
|
fn_name: self.fn_name.to_string(),
|
||||||
|
@ -111,10 +111,10 @@ impl Engine {
|
|||||||
#[cfg(not(feature = "no_module"))]
|
#[cfg(not(feature = "no_module"))]
|
||||||
let (lib, constants) = if let Some(ref environ) = fn_def.environ {
|
let (lib, constants) = if let Some(ref environ) = fn_def.environ {
|
||||||
let crate::ast::EncapsulatedEnviron {
|
let crate::ast::EncapsulatedEnviron {
|
||||||
lib: fn_lib,
|
lib: ref fn_lib,
|
||||||
imports,
|
ref imports,
|
||||||
constants,
|
ref constants,
|
||||||
} = environ.as_ref();
|
} = **environ;
|
||||||
|
|
||||||
imports
|
imports
|
||||||
.iter()
|
.iter()
|
||||||
|
14
src/lib.rs
14
src/lib.rs
@ -304,17 +304,15 @@ pub use types::dynamic::{AccessMode, DynamicReadLock, DynamicWriteLock, Variant}
|
|||||||
pub use types::FloatWrapper;
|
pub use types::FloatWrapper;
|
||||||
|
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
pub use tokenizer::{get_next_token, parse_string_literal};
|
pub use types::StringsInterner;
|
||||||
|
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
pub use tokenizer::{
|
pub use tokenizer::{
|
||||||
is_valid_function_name, is_valid_identifier, InputStream, MultiInputsStream, Span, Token,
|
get_next_token, is_valid_function_name, is_valid_identifier, parse_string_literal, InputStream,
|
||||||
TokenIterator, TokenizeState, TokenizerControl, TokenizerControlBlock,
|
MultiInputsStream, Span, Token, TokenIterator, TokenizeState, TokenizerControl,
|
||||||
|
TokenizerControlBlock,
|
||||||
};
|
};
|
||||||
|
|
||||||
#[cfg(feature = "internals")]
|
|
||||||
pub use types::StringsInterner;
|
|
||||||
|
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
pub use parser::ParseState;
|
pub use parser::ParseState;
|
||||||
|
|
||||||
@ -340,6 +338,10 @@ pub use ast::EncapsulatedEnviron;
|
|||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
pub use eval::{Caches, FnResolutionCache, FnResolutionCacheEntry, GlobalRuntimeState};
|
pub use eval::{Caches, FnResolutionCache, FnResolutionCacheEntry, GlobalRuntimeState};
|
||||||
|
|
||||||
|
#[cfg(feature = "internals")]
|
||||||
|
#[allow(deprecated)]
|
||||||
|
pub use func::NativeCallContextStore;
|
||||||
|
|
||||||
#[cfg(feature = "internals")]
|
#[cfg(feature = "internals")]
|
||||||
#[cfg(feature = "metadata")]
|
#[cfg(feature = "metadata")]
|
||||||
pub use api::definitions::Definitions;
|
pub use api::definitions::Definitions;
|
||||||
|
@ -12,7 +12,7 @@ use crate::tokenizer::Token;
|
|||||||
use crate::types::dynamic::AccessMode;
|
use crate::types::dynamic::AccessMode;
|
||||||
use crate::{
|
use crate::{
|
||||||
calc_fn_hash, calc_fn_hash_full, Dynamic, Engine, FnPtr, Identifier, ImmutableString, Position,
|
calc_fn_hash, calc_fn_hash_full, Dynamic, Engine, FnPtr, Identifier, ImmutableString, Position,
|
||||||
Scope, StaticVec, AST, INT,
|
Scope, StaticVec, AST,
|
||||||
};
|
};
|
||||||
#[cfg(feature = "no_std")]
|
#[cfg(feature = "no_std")]
|
||||||
use std::prelude::v1::*;
|
use std::prelude::v1::*;
|
||||||
@ -592,7 +592,7 @@ fn optimize_stmt(stmt: &mut Stmt, state: &mut OptimizerState, preserve_result: b
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Then check ranges
|
// Then check ranges
|
||||||
if value.is::<INT>() && !ranges.is_empty() {
|
if value.is_int() && !ranges.is_empty() {
|
||||||
let value = value.as_int().unwrap();
|
let value = value.as_int().unwrap();
|
||||||
|
|
||||||
// Only one range or all ranges without conditions
|
// Only one range or all ranges without conditions
|
||||||
|
@ -39,7 +39,7 @@ pub fn print_with_func(
|
|||||||
value: &mut Dynamic,
|
value: &mut Dynamic,
|
||||||
) -> crate::ImmutableString {
|
) -> crate::ImmutableString {
|
||||||
match ctx.call_native_fn_raw(fn_name, true, &mut [value]) {
|
match ctx.call_native_fn_raw(fn_name, true, &mut [value]) {
|
||||||
Ok(result) if result.is::<crate::ImmutableString>() => {
|
Ok(result) if result.is_string() => {
|
||||||
result.into_immutable_string().expect("`ImmutableString`")
|
result.into_immutable_string().expect("`ImmutableString`")
|
||||||
}
|
}
|
||||||
Ok(result) => ctx.engine().map_type_name(result.type_name()).into(),
|
Ok(result) => ctx.engine().map_type_name(result.type_name()).into(),
|
||||||
@ -75,7 +75,7 @@ mod print_debug_functions {
|
|||||||
/// Return the empty string.
|
/// Return the empty string.
|
||||||
#[rhai_fn(name = "print", name = "debug")]
|
#[rhai_fn(name = "print", name = "debug")]
|
||||||
pub fn print_empty_string(ctx: NativeCallContext) -> ImmutableString {
|
pub fn print_empty_string(ctx: NativeCallContext) -> ImmutableString {
|
||||||
ctx.engine().get_interned_string("")
|
ctx.engine().const_empty_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Return the `string`.
|
/// Return the `string`.
|
||||||
@ -121,7 +121,7 @@ mod print_debug_functions {
|
|||||||
#[rhai_fn(name = "print", name = "to_string")]
|
#[rhai_fn(name = "print", name = "to_string")]
|
||||||
pub fn print_unit(ctx: NativeCallContext, unit: ()) -> ImmutableString {
|
pub fn print_unit(ctx: NativeCallContext, unit: ()) -> ImmutableString {
|
||||||
let _ = unit;
|
let _ = unit;
|
||||||
ctx.engine().get_interned_string("")
|
ctx.engine().const_empty_string()
|
||||||
}
|
}
|
||||||
/// Convert the unit into a string in debug format.
|
/// Convert the unit into a string in debug format.
|
||||||
#[rhai_fn(name = "debug", name = "to_debug")]
|
#[rhai_fn(name = "debug", name = "to_debug")]
|
||||||
|
@ -348,7 +348,7 @@ mod string_functions {
|
|||||||
len: INT,
|
len: INT,
|
||||||
) -> ImmutableString {
|
) -> ImmutableString {
|
||||||
if string.is_empty() || len <= 0 {
|
if string.is_empty() || len <= 0 {
|
||||||
return ctx.engine().get_interned_string("");
|
return ctx.engine().const_empty_string();
|
||||||
}
|
}
|
||||||
let len = len.min(MAX_USIZE_INT) as usize;
|
let len = len.min(MAX_USIZE_INT) as usize;
|
||||||
|
|
||||||
@ -896,18 +896,18 @@ mod string_functions {
|
|||||||
len: INT,
|
len: INT,
|
||||||
) -> ImmutableString {
|
) -> ImmutableString {
|
||||||
if string.is_empty() {
|
if string.is_empty() {
|
||||||
return ctx.engine().get_interned_string("");
|
return ctx.engine().const_empty_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
let mut chars = StaticVec::with_capacity(string.len());
|
let mut chars = StaticVec::with_capacity(string.len());
|
||||||
|
|
||||||
let offset = if string.is_empty() || len <= 0 {
|
let offset = if string.is_empty() || len <= 0 {
|
||||||
return ctx.engine().get_interned_string("");
|
return ctx.engine().const_empty_string();
|
||||||
} else if start < 0 {
|
} else if start < 0 {
|
||||||
let abs_start = start.unsigned_abs();
|
let abs_start = start.unsigned_abs();
|
||||||
|
|
||||||
if abs_start as u64 > MAX_USIZE_INT as u64 {
|
if abs_start as u64 > MAX_USIZE_INT as u64 {
|
||||||
return ctx.engine().get_interned_string("");
|
return ctx.engine().const_empty_string();
|
||||||
}
|
}
|
||||||
|
|
||||||
let abs_start = abs_start as usize;
|
let abs_start = abs_start as usize;
|
||||||
@ -918,7 +918,7 @@ mod string_functions {
|
|||||||
chars.len() - abs_start
|
chars.len() - abs_start
|
||||||
}
|
}
|
||||||
} else if start > MAX_USIZE_INT || start as usize >= string.chars().count() {
|
} else if start > MAX_USIZE_INT || start as usize >= string.chars().count() {
|
||||||
return ctx.engine().get_interned_string("");
|
return ctx.engine().const_empty_string();
|
||||||
} else {
|
} else {
|
||||||
start as usize
|
start as usize
|
||||||
};
|
};
|
||||||
@ -964,7 +964,7 @@ mod string_functions {
|
|||||||
start: INT,
|
start: INT,
|
||||||
) -> ImmutableString {
|
) -> ImmutableString {
|
||||||
if string.is_empty() {
|
if string.is_empty() {
|
||||||
ctx.engine().get_interned_string("")
|
ctx.engine().const_empty_string()
|
||||||
} else {
|
} else {
|
||||||
let len = string.len() as INT;
|
let len = string.len() as INT;
|
||||||
sub_string(ctx, string, start, len)
|
sub_string(ctx, string, start, len)
|
||||||
@ -1348,7 +1348,7 @@ mod string_functions {
|
|||||||
|
|
||||||
if abs_index as u64 > MAX_USIZE_INT as u64 {
|
if abs_index as u64 > MAX_USIZE_INT as u64 {
|
||||||
return vec![
|
return vec![
|
||||||
ctx.engine().get_interned_string("").into(),
|
ctx.engine().const_empty_string().into(),
|
||||||
string.as_str().into(),
|
string.as_str().into(),
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
@ -1357,7 +1357,7 @@ mod string_functions {
|
|||||||
let num_chars = string.chars().count();
|
let num_chars = string.chars().count();
|
||||||
if abs_index > num_chars {
|
if abs_index > num_chars {
|
||||||
vec![
|
vec![
|
||||||
ctx.engine().get_interned_string("").into(),
|
ctx.engine().const_empty_string().into(),
|
||||||
string.as_str().into(),
|
string.as_str().into(),
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
@ -1368,7 +1368,7 @@ mod string_functions {
|
|||||||
} else if index > MAX_USIZE_INT {
|
} else if index > MAX_USIZE_INT {
|
||||||
vec![
|
vec![
|
||||||
string.as_str().into(),
|
string.as_str().into(),
|
||||||
ctx.engine().get_interned_string("").into(),
|
ctx.engine().const_empty_string().into(),
|
||||||
]
|
]
|
||||||
} else {
|
} else {
|
||||||
let prefix: String = string.chars().take(index as usize).collect();
|
let prefix: String = string.chars().take(index as usize).collect();
|
||||||
|
@ -374,7 +374,7 @@ impl Expr {
|
|||||||
fn ensure_bool_expr(self) -> ParseResult<Expr> {
|
fn ensure_bool_expr(self) -> ParseResult<Expr> {
|
||||||
let type_name = match self {
|
let type_name = match self {
|
||||||
Expr::Unit(..) => "()",
|
Expr::Unit(..) => "()",
|
||||||
Expr::DynamicConstant(ref v, ..) if !v.is::<bool>() => v.type_name(),
|
Expr::DynamicConstant(ref v, ..) if !v.is_bool() => v.type_name(),
|
||||||
Expr::IntegerConstant(..) => "a number",
|
Expr::IntegerConstant(..) => "a number",
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
Expr::FloatConstant(..) => "a floating-point number",
|
Expr::FloatConstant(..) => "a floating-point number",
|
||||||
@ -1248,7 +1248,7 @@ impl Engine {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if value.is::<INT>() && !ranges.is_empty() {
|
if value.is_int() && !ranges.is_empty() {
|
||||||
return Err(PERR::WrongSwitchIntegerCase.into_err(expr.start_position()));
|
return Err(PERR::WrongSwitchIntegerCase.into_err(expr.start_position()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -370,7 +370,7 @@ impl<'de> Deserializer<'de> for DynamicDeserializer<'de> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
fn deserialize_option<V: Visitor<'de>>(self, visitor: V) -> RhaiResultOf<V::Value> {
|
||||||
if self.0.is::<()>() {
|
if self.0.is_unit() {
|
||||||
visitor.visit_none()
|
visitor.visit_none()
|
||||||
} else {
|
} else {
|
||||||
visitor.visit_some(self)
|
visitor.visit_some(self)
|
||||||
|
@ -1626,6 +1626,194 @@ impl Dynamic {
|
|||||||
_ => None,
|
_ => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Return `true` if the [`Dynamic`] holds a `()`.
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_unit(&self) -> bool {
|
||||||
|
match self.0 {
|
||||||
|
Union::Unit(..) => true,
|
||||||
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
||||||
|
Union::Unit(..) => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Return `true` if the [`Dynamic`] holds the system integer type [`INT`].
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_int(&self) -> bool {
|
||||||
|
match self.0 {
|
||||||
|
Union::Int(..) => true,
|
||||||
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
||||||
|
Union::Int(..) => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Return `true` if the [`Dynamic`] holds the system floating-point type [`FLOAT`][crate::FLOAT].
|
||||||
|
///
|
||||||
|
/// Not available under `no_float`.
|
||||||
|
#[cfg(not(feature = "no_float"))]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_float(&self) -> bool {
|
||||||
|
match self.0 {
|
||||||
|
Union::Float(..) => true,
|
||||||
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
||||||
|
Union::Float(..) => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// _(decimal)_ Return `true` if the [`Dynamic`] holds a [`Decimal`][rust_decimal::Decimal].
|
||||||
|
///
|
||||||
|
/// Exported under the `decimal` feature only.
|
||||||
|
#[cfg(feature = "decimal")]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_decimal(&self) -> bool {
|
||||||
|
match self.0 {
|
||||||
|
Union::Decimal(..) => true,
|
||||||
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
||||||
|
Union::Decimal(..) => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Return `true` if the [`Dynamic`] holds a [`bool`].
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_bool(&self) -> bool {
|
||||||
|
match self.0 {
|
||||||
|
Union::Bool(..) => true,
|
||||||
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
||||||
|
Union::Bool(..) => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Return `true` if the [`Dynamic`] holds a [`char`].
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_char(&self) -> bool {
|
||||||
|
match self.0 {
|
||||||
|
Union::Char(..) => true,
|
||||||
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
||||||
|
Union::Char(..) => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Return `true` if the [`Dynamic`] holds an [`ImmutableString`].
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_string(&self) -> bool {
|
||||||
|
match self.0 {
|
||||||
|
Union::Str(..) => true,
|
||||||
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
||||||
|
Union::Str(..) => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Return `true` if the [`Dynamic`] holds an [`Array`][crate::Array].
|
||||||
|
///
|
||||||
|
/// Not available under `no_index`.
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_array(&self) -> bool {
|
||||||
|
match self.0 {
|
||||||
|
Union::Array(..) => true,
|
||||||
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
||||||
|
Union::Array(..) => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Return `true` if the [`Dynamic`] holds a [`Blob`][crate::Blob].
|
||||||
|
///
|
||||||
|
/// Not available under `no_index`.
|
||||||
|
#[cfg(not(feature = "no_index"))]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_blob(&self) -> bool {
|
||||||
|
match self.0 {
|
||||||
|
Union::Blob(..) => true,
|
||||||
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
||||||
|
Union::Blob(..) => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Return `true` if the [`Dynamic`] holds a [`Map`][crate::Map].
|
||||||
|
///
|
||||||
|
/// Not available under `no_object`.
|
||||||
|
#[cfg(not(feature = "no_object"))]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_map(&self) -> bool {
|
||||||
|
match self.0 {
|
||||||
|
Union::Map(..) => true,
|
||||||
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
||||||
|
Union::Map(..) => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Return `true` if the [`Dynamic`] holds a [`FnPtr`].
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub(crate) fn is_fnptr(&self) -> bool {
|
||||||
|
match self.0 {
|
||||||
|
Union::FnPtr(..) => true,
|
||||||
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
||||||
|
Union::FnPtr(..) => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
/// Return `true` if the [`Dynamic`] holds a [timestamp][Instant].
|
||||||
|
///
|
||||||
|
/// Not available under `no_time`.
|
||||||
|
#[cfg(not(feature = "no_time"))]
|
||||||
|
#[inline]
|
||||||
|
#[must_use]
|
||||||
|
pub fn is_timestamp(&self) -> bool {
|
||||||
|
match self.0 {
|
||||||
|
Union::TimeStamp(..) => true,
|
||||||
|
#[cfg(not(feature = "no_closure"))]
|
||||||
|
Union::Shared(ref cell, ..) => match crate::func::locked_read(cell).0 {
|
||||||
|
Union::TimeStamp(..) => true,
|
||||||
|
_ => false,
|
||||||
|
},
|
||||||
|
_ => false,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Cast the [`Dynamic`] as a unit `()`.
|
/// Cast the [`Dynamic`] as a unit `()`.
|
||||||
/// Returns the name of the actual type if the cast fails.
|
/// Returns the name of the actual type if the cast fails.
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -1698,6 +1886,7 @@ impl Dynamic {
|
|||||||
_ => Err(self.type_name()),
|
_ => Err(self.type_name()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Cast the [`Dynamic`] as a string slice.
|
/// Cast the [`Dynamic`] as a string slice.
|
||||||
/// Returns the name of the actual type if the cast fails.
|
/// Returns the name of the actual type if the cast fails.
|
||||||
///
|
///
|
||||||
@ -1741,6 +1930,8 @@ impl Dynamic {
|
|||||||
}
|
}
|
||||||
/// Convert the [`Dynamic`] into an [`Array`][crate::Array].
|
/// Convert the [`Dynamic`] into an [`Array`][crate::Array].
|
||||||
/// Returns the name of the actual type if the cast fails.
|
/// Returns the name of the actual type if the cast fails.
|
||||||
|
///
|
||||||
|
/// Not available under `no_index`.
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn into_array(self) -> Result<crate::Array, &'static str> {
|
pub fn into_array(self) -> Result<crate::Array, &'static str> {
|
||||||
@ -1760,6 +1951,8 @@ impl Dynamic {
|
|||||||
}
|
}
|
||||||
/// Convert the [`Dynamic`] into a [`Vec`].
|
/// Convert the [`Dynamic`] into a [`Vec`].
|
||||||
/// Returns the name of the actual type if any cast fails.
|
/// Returns the name of the actual type if any cast fails.
|
||||||
|
///
|
||||||
|
/// Not available under `no_index`.
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn into_typed_array<T: Variant + Clone>(self) -> Result<Vec<T>, &'static str> {
|
pub fn into_typed_array<T: Variant + Clone>(self) -> Result<Vec<T>, &'static str> {
|
||||||
@ -1814,6 +2007,8 @@ impl Dynamic {
|
|||||||
}
|
}
|
||||||
/// Convert the [`Dynamic`] into a [`Blob`][crate::Blob].
|
/// Convert the [`Dynamic`] into a [`Blob`][crate::Blob].
|
||||||
/// Returns the name of the actual type if the cast fails.
|
/// Returns the name of the actual type if the cast fails.
|
||||||
|
///
|
||||||
|
/// Not available under `no_index`.
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn into_blob(self) -> Result<crate::Blob, &'static str> {
|
pub fn into_blob(self) -> Result<crate::Blob, &'static str> {
|
||||||
|
@ -174,7 +174,7 @@ impl fmt::Display for EvalAltResult {
|
|||||||
Self::ErrorStackOverflow(..) => f.write_str("Stack overflow")?,
|
Self::ErrorStackOverflow(..) => f.write_str("Stack overflow")?,
|
||||||
Self::ErrorTerminated(..) => f.write_str("Script terminated")?,
|
Self::ErrorTerminated(..) => f.write_str("Script terminated")?,
|
||||||
|
|
||||||
Self::ErrorRuntime(d, ..) if d.is::<()>() => f.write_str("Runtime error")?,
|
Self::ErrorRuntime(d, ..) if d.is_unit() => f.write_str("Runtime error")?,
|
||||||
Self::ErrorRuntime(d, ..)
|
Self::ErrorRuntime(d, ..)
|
||||||
if d.read_lock::<ImmutableString>()
|
if d.read_lock::<ImmutableString>()
|
||||||
.map_or(false, |v| v.is_empty()) =>
|
.map_or(false, |v| v.is_empty()) =>
|
||||||
|
@ -19,11 +19,11 @@ use rust_decimal::Decimal;
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serde_ser_primary_types() -> Result<(), Box<EvalAltResult>> {
|
fn test_serde_ser_primary_types() -> Result<(), Box<EvalAltResult>> {
|
||||||
assert!(to_dynamic(42_u64)?.is::<INT>());
|
assert!(to_dynamic(42_u64)?.is_int());
|
||||||
assert!(to_dynamic(u64::MAX)?.is::<u64>());
|
assert!(to_dynamic(u64::MAX)?.is::<u64>());
|
||||||
assert!(to_dynamic(42 as INT)?.is::<INT>());
|
assert!(to_dynamic(42 as INT)?.is_int());
|
||||||
assert!(to_dynamic(true)?.is::<bool>());
|
assert!(to_dynamic(true)?.is_bool());
|
||||||
assert!(to_dynamic(())?.is::<()>());
|
assert!(to_dynamic(())?.is_unit());
|
||||||
|
|
||||||
#[cfg(not(feature = "no_float"))]
|
#[cfg(not(feature = "no_float"))]
|
||||||
{
|
{
|
||||||
@ -45,14 +45,14 @@ fn test_serde_ser_primary_types() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn test_serde_ser_integer_types() -> Result<(), Box<EvalAltResult>> {
|
fn test_serde_ser_integer_types() -> Result<(), Box<EvalAltResult>> {
|
||||||
assert!(to_dynamic(42_i8)?.is::<INT>());
|
assert!(to_dynamic(42_i8)?.is_int());
|
||||||
assert!(to_dynamic(42_i16)?.is::<INT>());
|
assert!(to_dynamic(42_i16)?.is_int());
|
||||||
assert!(to_dynamic(42_i32)?.is::<INT>());
|
assert!(to_dynamic(42_i32)?.is_int());
|
||||||
assert!(to_dynamic(42_i64)?.is::<INT>());
|
assert!(to_dynamic(42_i64)?.is_int());
|
||||||
assert!(to_dynamic(42_u8)?.is::<INT>());
|
assert!(to_dynamic(42_u8)?.is_int());
|
||||||
assert!(to_dynamic(42_u16)?.is::<INT>());
|
assert!(to_dynamic(42_u16)?.is_int());
|
||||||
assert!(to_dynamic(42_u32)?.is::<INT>());
|
assert!(to_dynamic(42_u32)?.is_int());
|
||||||
assert!(to_dynamic(42_u64)?.is::<INT>());
|
assert!(to_dynamic(42_u64)?.is_int());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -63,7 +63,7 @@ fn test_serde_ser_array() -> Result<(), Box<EvalAltResult>> {
|
|||||||
let arr: Vec<INT> = vec![123, 456, 42, 999];
|
let arr: Vec<INT> = vec![123, 456, 42, 999];
|
||||||
|
|
||||||
let d = to_dynamic(arr)?;
|
let d = to_dynamic(arr)?;
|
||||||
assert!(d.is::<Array>());
|
assert!(d.is_array());
|
||||||
assert_eq!(4, d.cast::<Array>().len());
|
assert_eq!(4, d.cast::<Array>().len());
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -94,7 +94,7 @@ fn test_serde_ser_struct() -> Result<(), Box<EvalAltResult>> {
|
|||||||
|
|
||||||
let d = to_dynamic(x)?;
|
let d = to_dynamic(x)?;
|
||||||
|
|
||||||
assert!(d.is::<Map>());
|
assert!(d.is_map());
|
||||||
|
|
||||||
let mut map = d.cast::<Map>();
|
let mut map = d.cast::<Map>();
|
||||||
let obj = map.remove("obj").unwrap().cast::<Map>();
|
let obj = map.remove("obj").unwrap().cast::<Map>();
|
||||||
@ -734,7 +734,7 @@ fn test_serde_json() -> serde_json::Result<()> {
|
|||||||
|
|
||||||
let d2: Dynamic = serde_json::from_str(&json)?;
|
let d2: Dynamic = serde_json::from_str(&json)?;
|
||||||
|
|
||||||
assert!(d2.is::<Map>());
|
assert!(d2.is_map());
|
||||||
|
|
||||||
let mut m = d2.cast::<Map>();
|
let mut m = d2.cast::<Map>();
|
||||||
|
|
||||||
|
@ -11,7 +11,7 @@ fn test_throw() {
|
|||||||
|
|
||||||
assert!(matches!(
|
assert!(matches!(
|
||||||
*engine.run(r#"throw"#).expect_err("expects error"),
|
*engine.run(r#"throw"#).expect_err("expects error"),
|
||||||
EvalAltResult::ErrorRuntime(s, ..) if s.is::<()>()
|
EvalAltResult::ErrorRuntime(s, ..) if s.is_unit()
|
||||||
));
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user