commit
aa9b48820b
22
CHANGELOG.md
22
CHANGELOG.md
@ -4,19 +4,23 @@ Rhai Release Notes
|
||||
Version 1.3.0
|
||||
=============
|
||||
|
||||
This version adds native support for `BLOB`'s (byte arrays), as well as a number of configuration
|
||||
settings to fine-tun language features.
|
||||
|
||||
Compiler requirement
|
||||
--------------------
|
||||
|
||||
* Minimum compiler version is bumped to 1.51.
|
||||
* Minimum compiler version is now 1.51.
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
* BLOB's no longer panic when accessed with an out-of-bounds index.
|
||||
* `from_dynamic` now supports deserializing `Option`.
|
||||
|
||||
New features
|
||||
------------
|
||||
|
||||
* `BLOB` (essentially a byte array) is added as a supported primitive value type parallel to arrays.
|
||||
* New options for `Engine` which allows disabling `if`-expressions, `switch`-expressions, statement expressions, anonymous functions and/or looping (i.e. `while`, `loop`, `do` and `for` statements):
|
||||
* `Engine::set_allow_if_expression`
|
||||
* `Engine::set_allow_switch_expression`
|
||||
@ -28,9 +32,12 @@ New features
|
||||
Enhancements
|
||||
------------
|
||||
|
||||
* Two double quotes (`""`) in a string literal now maps to `"`; two back-ticks (``` `` ```) in a literal string now maps to `` ` ``.
|
||||
* Added `Engine::register_type_with_name_raw` to register a custom type based on a fully-qualified type path.
|
||||
* Added `into_array` and `into_typed_array` for `Dynamic`.
|
||||
* Added `FnPtr::call` and `FnPtr::call_within_context` to simplify calling a function pointer.
|
||||
* BLob's can now be deserialized (using `from_dynamic`) into `Vec<u8>` via [`serde_bytes`](https://crates.io/crates/serde_bytes).
|
||||
* A function's hashes are included in its JSON metadata to assist in debugging. Each function's `baseHash` field in the JSON object should map directly to the pre-calculated hash in the function call.
|
||||
* `Expression` now derefs to `Expr`.
|
||||
|
||||
Deprecated and Gated API's
|
||||
--------------------------
|
||||
@ -41,15 +48,6 @@ Deprecated and Gated API's
|
||||
* `FnPtr::call_dynamic` is deprecated in favor of `FnPtr::call_raw`.
|
||||
|
||||
|
||||
Version 1.2.2
|
||||
=============
|
||||
|
||||
Bug fixes
|
||||
---------
|
||||
|
||||
* `from_dynamic` now supports deserializing `Option`.
|
||||
|
||||
|
||||
Version 1.2.1
|
||||
=============
|
||||
|
||||
|
@ -66,7 +66,8 @@ For those who actually want their own language
|
||||
---------------------------------------------
|
||||
|
||||
* Use as a [DSL](https://rhai.rs/book/engine/dsl.html).
|
||||
* Restrict the language by surgically [disabling keywords and operators](https://rhai.rs/book/engine/disable.html).
|
||||
* Disable certain [language features](https://rhai.rs/book/engine/options.html#language-features) such as [looping](https://rhai.rs/book/engine/disable-looping.html).
|
||||
* Further restrict the language by surgically [disabling keywords and operators](https://rhai.rs/book/engine/disable-keywords.html).
|
||||
* Define [custom operators](https://rhai.rs/book/engine/custom-op.html).
|
||||
* Extend the language with [custom syntax](https://rhai.rs/book/engine/custom-syntax.html).
|
||||
|
||||
|
@ -5,9 +5,6 @@ use crate::{Engine, ParseError, Scope, AST};
|
||||
#[cfg(feature = "no_std")]
|
||||
use std::prelude::v1::*;
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
use crate::Map;
|
||||
|
||||
impl Engine {
|
||||
/// Compile a string into an [`AST`], which can be used later for evaluation.
|
||||
///
|
||||
@ -313,7 +310,7 @@ impl Engine {
|
||||
self.optimization_level,
|
||||
)
|
||||
}
|
||||
/// Parse a JSON string into an [object map][`Map`].
|
||||
/// Parse a JSON string into an [object map][crate::Map].
|
||||
/// This is a light-weight alternative to using, say,
|
||||
/// [`serde_json`](https://crates.io/crates/serde_json) to deserialize the JSON.
|
||||
///
|
||||
@ -362,14 +359,14 @@ impl Engine {
|
||||
&self,
|
||||
json: impl AsRef<str>,
|
||||
has_null: bool,
|
||||
) -> Result<Map, Box<crate::EvalAltResult>> {
|
||||
) -> Result<crate::Map, Box<crate::EvalAltResult>> {
|
||||
use crate::tokenizer::Token;
|
||||
|
||||
fn parse_json_inner(
|
||||
engine: &Engine,
|
||||
json: &str,
|
||||
has_null: bool,
|
||||
) -> Result<Map, Box<crate::EvalAltResult>> {
|
||||
) -> Result<crate::Map, Box<crate::EvalAltResult>> {
|
||||
let mut scope = Scope::new();
|
||||
let json_text = json.trim_start();
|
||||
let scripts = if json_text.starts_with(Token::MapStart.literal_syntax()) {
|
||||
|
@ -4,7 +4,6 @@ use crate::{
|
||||
Dynamic, Engine, EvalAltResult, FnPtr, ImmutableString, NativeCallContext, RhaiResult, Scope,
|
||||
AST,
|
||||
};
|
||||
|
||||
#[cfg(feature = "no_std")]
|
||||
use std::prelude::v1::*;
|
||||
|
||||
|
@ -2,11 +2,10 @@
|
||||
#![cfg(not(feature = "unchecked"))]
|
||||
|
||||
use crate::Engine;
|
||||
use std::num::{NonZeroU64, NonZeroUsize};
|
||||
#[cfg(feature = "no_std")]
|
||||
use std::prelude::v1::*;
|
||||
|
||||
use std::num::{NonZeroU64, NonZeroUsize};
|
||||
|
||||
/// A type containing all the limits imposed by the [`Engine`].
|
||||
///
|
||||
/// Not available under `unchecked`.
|
||||
|
@ -157,7 +157,7 @@ impl Engine {
|
||||
}
|
||||
/// Register a custom operator with a precedence into the language.
|
||||
///
|
||||
/// The operator must be a valid identifier (i.e. it cannot be a symbol).
|
||||
/// The operator can be a valid identifier, a reserved symbol, a disabled operator or a disabled keyword.
|
||||
///
|
||||
/// The precedence cannot be zero.
|
||||
///
|
||||
@ -169,15 +169,15 @@ impl Engine {
|
||||
///
|
||||
/// let mut engine = Engine::new();
|
||||
///
|
||||
/// // Register a custom operator called 'foo' and give it
|
||||
/// // Register a custom operator called '#' and give it
|
||||
/// // a precedence of 160 (i.e. between +|- and *|/).
|
||||
/// engine.register_custom_operator("foo", 160).expect("should succeed");
|
||||
/// engine.register_custom_operator("#", 160).expect("should succeed");
|
||||
///
|
||||
/// // Register a binary function named 'foo'
|
||||
/// engine.register_fn("foo", |x: i64, y: i64| (x * y) - (x + y));
|
||||
/// // Register a binary function named '#'
|
||||
/// engine.register_fn("#", |x: i64, y: i64| (x * y) - (x + y));
|
||||
///
|
||||
/// assert_eq!(
|
||||
/// engine.eval_expression::<i64>("1 + 2 * 3 foo 4 - 5 / 6")?,
|
||||
/// engine.eval_expression::<i64>("1 + 2 * 3 # 4 - 5 / 6")?,
|
||||
/// 15
|
||||
/// );
|
||||
/// # Ok(())
|
||||
|
@ -4,17 +4,12 @@ use crate::func::{FnCallArgs, RegisterNativeFunction, SendSync};
|
||||
use crate::types::dynamic::Variant;
|
||||
use crate::{
|
||||
Engine, EvalAltResult, FnAccess, FnNamespace, Identifier, Module, NativeCallContext, Shared,
|
||||
SmartString,
|
||||
};
|
||||
use std::any::{type_name, TypeId};
|
||||
#[cfg(feature = "no_std")]
|
||||
use std::prelude::v1::*;
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
use crate::Array;
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
use crate::Map;
|
||||
|
||||
impl Engine {
|
||||
/// Get the global namespace module (which is the last module in `global_modules`).
|
||||
#[inline(always)]
|
||||
@ -152,11 +147,12 @@ impl Engine {
|
||||
///
|
||||
/// # WARNING - Low Level API
|
||||
///
|
||||
/// This function is very low level. It takes a list of [`TypeId`][std::any::TypeId]'s indicating the actual types of the parameters.
|
||||
/// This function is very low level. It takes a list of [`TypeId`][std::any::TypeId]'s
|
||||
/// indicating the actual types of the parameters.
|
||||
///
|
||||
/// ## Arguments
|
||||
///
|
||||
/// Arguments are simply passed in as a mutable array of [`&mut Dynamic`][crate::Dynamic],
|
||||
/// Arguments are simply passed in as a mutable array of [`&mut Dynamic`][crate::Dynamic].
|
||||
/// The arguments are guaranteed to be of the correct types matching the [`TypeId`][std::any::TypeId]'s.
|
||||
///
|
||||
/// To access a primary argument value (i.e. cloning is cheap), use: `args[n].as_xxx().unwrap()`
|
||||
@ -269,9 +265,23 @@ impl Engine {
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn register_type_with_name<T: Variant + Clone>(&mut self, name: &str) -> &mut Self {
|
||||
self.register_type_with_name_raw(type_name::<T>(), name)
|
||||
}
|
||||
/// Register a custom type for use with the [`Engine`], with a pretty-print name
|
||||
/// for the `type_of` function. The type must implement [`Clone`].
|
||||
///
|
||||
/// # WARNING - Low Level API
|
||||
///
|
||||
/// This function is low level.
|
||||
#[inline(always)]
|
||||
pub fn register_type_with_name_raw(
|
||||
&mut self,
|
||||
fully_qualified_type_path: impl Into<SmartString>,
|
||||
name: impl Into<SmartString>,
|
||||
) -> &mut Self {
|
||||
// Add the pretty-print type name into the map
|
||||
self.type_names
|
||||
.insert(type_name::<T>().into(), Box::new(name.into()));
|
||||
.insert(fully_qualified_type_path.into(), name.into());
|
||||
self
|
||||
}
|
||||
/// Register an type iterator for an iterable type with the [`Engine`].
|
||||
@ -529,7 +539,7 @@ impl Engine {
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the type is [`Array`], [`Map`], [`String`],
|
||||
/// Panics if the type is [`Array`][crate::Array], [`Map`][crate::Map], [`String`],
|
||||
/// [`ImmutableString`][crate::ImmutableString], `&str` or [`INT`][crate::INT].
|
||||
/// Indexers for arrays, object maps, strings and integers cannot be registered.
|
||||
///
|
||||
@ -573,11 +583,11 @@ impl Engine {
|
||||
get_fn: impl Fn(&mut T, X) -> V + SendSync + 'static,
|
||||
) -> &mut Self {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<Array>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<crate::Array>() {
|
||||
panic!("Cannot register indexer for arrays.");
|
||||
}
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<Map>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<crate::Map>() {
|
||||
panic!("Cannot register indexer for object maps.");
|
||||
}
|
||||
if TypeId::of::<T>() == TypeId::of::<String>()
|
||||
@ -600,7 +610,7 @@ impl Engine {
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the type is [`Array`], [`Map`], [`String`],
|
||||
/// Panics if the type is [`Array`][crate::Array], [`Map`][crate::Map], [`String`],
|
||||
/// [`ImmutableString`][crate::ImmutableString], `&str` or [`INT`][crate::INT].
|
||||
/// Indexers for arrays, object maps, strings and integers cannot be registered.
|
||||
///
|
||||
@ -650,11 +660,11 @@ impl Engine {
|
||||
get_fn: impl Fn(&mut T, X) -> Result<V, Box<EvalAltResult>> + SendSync + 'static,
|
||||
) -> &mut Self {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<Array>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<crate::Array>() {
|
||||
panic!("Cannot register indexer for arrays.");
|
||||
}
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<Map>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<crate::Map>() {
|
||||
panic!("Cannot register indexer for object maps.");
|
||||
}
|
||||
if TypeId::of::<T>() == TypeId::of::<String>()
|
||||
@ -675,7 +685,7 @@ impl Engine {
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the type is [`Array`], [`Map`], [`String`],
|
||||
/// Panics if the type is [`Array`][crate::Array], [`Map`][crate::Map], [`String`],
|
||||
/// [`ImmutableString`][crate::ImmutableString], `&str` or [`INT`][crate::INT].
|
||||
/// Indexers for arrays, object maps, strings and integers cannot be registered.
|
||||
///
|
||||
@ -721,11 +731,11 @@ impl Engine {
|
||||
set_fn: impl Fn(&mut T, X, V) + SendSync + 'static,
|
||||
) -> &mut Self {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<Array>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<crate::Array>() {
|
||||
panic!("Cannot register indexer for arrays.");
|
||||
}
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<Map>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<crate::Map>() {
|
||||
panic!("Cannot register indexer for object maps.");
|
||||
}
|
||||
if TypeId::of::<T>() == TypeId::of::<String>()
|
||||
@ -746,7 +756,7 @@ impl Engine {
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the type is [`Array`], [`Map`], [`String`],
|
||||
/// Panics if the type is [`Array`][crate::Array], [`Map`][crate::Map], [`String`],
|
||||
/// [`ImmutableString`][crate::ImmutableString], `&str` or [`INT`][crate::INT].
|
||||
/// Indexers for arrays, object maps, strings and integers cannot be registered.
|
||||
///
|
||||
@ -799,11 +809,11 @@ impl Engine {
|
||||
set_fn: impl Fn(&mut T, X, V) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
||||
) -> &mut Self {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<Array>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<crate::Array>() {
|
||||
panic!("Cannot register indexer for arrays.");
|
||||
}
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<Map>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<crate::Map>() {
|
||||
panic!("Cannot register indexer for object maps.");
|
||||
}
|
||||
if TypeId::of::<T>() == TypeId::of::<String>()
|
||||
@ -824,7 +834,7 @@ impl Engine {
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the type is [`Array`], [`Map`], [`String`],
|
||||
/// Panics if the type is [`Array`][crate::Array], [`Map`][crate::Map], [`String`],
|
||||
/// [`ImmutableString`][crate::ImmutableString], `&str` or [`INT`][crate::INT].
|
||||
/// Indexers for arrays, object maps, strings and integers cannot be registered.
|
||||
///
|
||||
|
43
src/ast.rs
43
src/ast.rs
@ -1,6 +1,7 @@
|
||||
//! Module defining the AST (abstract syntax tree).
|
||||
|
||||
use crate::calc_fn_hash;
|
||||
use crate::func::hashing::ALT_ZERO_HASH;
|
||||
use crate::module::NamespaceRef;
|
||||
use crate::tokenizer::Token;
|
||||
use crate::types::dynamic::Union;
|
||||
@ -24,15 +25,9 @@ use std::{
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
use std::str::FromStr;
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
use crate::FLOAT;
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
use num_traits::Float;
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
use crate::Array;
|
||||
|
||||
/// A type representing the access mode of a function.
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
pub enum FnAccess {
|
||||
@ -1799,9 +1794,9 @@ impl OpAssignment<'_> {
|
||||
/// to possible function overloading for different parameter types.
|
||||
#[derive(Clone, Copy, Eq, PartialEq, Hash, Default)]
|
||||
pub struct FnCallHashes {
|
||||
/// Pre-calculated hash for a script-defined function ([`None`] if native functions only).
|
||||
/// Pre-calculated hash for a script-defined function (zero if native functions only).
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
pub script: Option<u64>,
|
||||
pub script: u64,
|
||||
/// Pre-calculated hash for a native Rust function with no parameter types.
|
||||
pub native: u64,
|
||||
}
|
||||
@ -1809,11 +1804,11 @@ pub struct FnCallHashes {
|
||||
impl fmt::Debug for FnCallHashes {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
if let Some(script) = self.script {
|
||||
return if script == self.native {
|
||||
if self.script != 0 {
|
||||
return if self.script == self.native {
|
||||
fmt::Debug::fmt(&self.native, f)
|
||||
} else {
|
||||
write!(f, "({}, {})", script, self.native)
|
||||
write!(f, "({}, {})", self.script, self.native)
|
||||
};
|
||||
}
|
||||
|
||||
@ -1824,9 +1819,11 @@ impl fmt::Debug for FnCallHashes {
|
||||
impl From<u64> for FnCallHashes {
|
||||
#[inline(always)]
|
||||
fn from(hash: u64) -> Self {
|
||||
let hash = if hash == 0 { ALT_ZERO_HASH } else { hash };
|
||||
|
||||
Self {
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
script: Some(hash),
|
||||
script: hash,
|
||||
native: hash,
|
||||
}
|
||||
}
|
||||
@ -1839,8 +1836,8 @@ impl FnCallHashes {
|
||||
pub const fn from_native(hash: u64) -> Self {
|
||||
Self {
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
script: None,
|
||||
native: hash,
|
||||
script: 0,
|
||||
native: if hash == 0 { ALT_ZERO_HASH } else { hash },
|
||||
}
|
||||
}
|
||||
/// Create a [`FnCallHashes`] with both native Rust and script function hashes.
|
||||
@ -1849,8 +1846,8 @@ impl FnCallHashes {
|
||||
pub const fn from_all(#[cfg(not(feature = "no_function"))] script: u64, native: u64) -> Self {
|
||||
Self {
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
script: Some(script),
|
||||
native,
|
||||
script: if script == 0 { ALT_ZERO_HASH } else { script },
|
||||
native: if native == 0 { ALT_ZERO_HASH } else { native },
|
||||
}
|
||||
}
|
||||
/// Is this [`FnCallHashes`] native Rust only?
|
||||
@ -1858,7 +1855,7 @@ impl FnCallHashes {
|
||||
#[must_use]
|
||||
pub const fn is_native_only(&self) -> bool {
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
return self.script.is_none();
|
||||
return self.script == 0;
|
||||
|
||||
#[cfg(feature = "no_function")]
|
||||
return true;
|
||||
@ -1915,7 +1912,7 @@ impl FnCallExpr {
|
||||
pub struct FloatWrapper<F>(F);
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl Hash for FloatWrapper<FLOAT> {
|
||||
impl Hash for FloatWrapper<crate::FLOAT> {
|
||||
#[inline(always)]
|
||||
fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
|
||||
self.0.to_ne_bytes().hash(state);
|
||||
@ -2019,11 +2016,11 @@ impl<F: Float> FloatWrapper<F> {
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl FloatWrapper<FLOAT> {
|
||||
impl FloatWrapper<crate::FLOAT> {
|
||||
/// Create a new [`FloatWrapper`].
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub const fn new_const(value: FLOAT) -> Self {
|
||||
pub const fn new_const(value: crate::FLOAT) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
@ -2034,7 +2031,7 @@ impl FloatWrapper<FLOAT> {
|
||||
pub enum Expr {
|
||||
/// Dynamic constant.
|
||||
///
|
||||
/// Used to hold complex constants such as [`Array`] or [`Map`][crate::Map] for quick cloning.
|
||||
/// Used to hold complex constants such as [`Array`][crate::Array] or [`Map`][crate::Map] for quick cloning.
|
||||
/// Primitive data types should use the appropriate variants to avoid an allocation.
|
||||
DynamicConstant(Box<Dynamic>, Position),
|
||||
/// Boolean constant.
|
||||
@ -2045,7 +2042,7 @@ pub enum Expr {
|
||||
///
|
||||
/// Not available under `no_float`.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
FloatConstant(FloatWrapper<FLOAT>, Position),
|
||||
FloatConstant(FloatWrapper<crate::FLOAT>, Position),
|
||||
/// Character constant.
|
||||
CharConstant(char, Position),
|
||||
/// [String][ImmutableString] constant.
|
||||
@ -2221,7 +2218,7 @@ impl Expr {
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Self::Array(x, _) if self.is_constant() => {
|
||||
let mut arr = Array::with_capacity(x.len());
|
||||
let mut arr = crate::Array::with_capacity(x.len());
|
||||
arr.extend(
|
||||
x.iter()
|
||||
.map(|v| v.get_literal_value().expect("constant value")),
|
||||
|
@ -10,9 +10,9 @@ use crate::{
|
||||
Engine, Identifier, ImmutableString, LexError, ParseError, Position, RhaiResult, Shared,
|
||||
StaticVec, INT,
|
||||
};
|
||||
use std::any::TypeId;
|
||||
#[cfg(feature = "no_std")]
|
||||
use std::prelude::v1::*;
|
||||
use std::{any::TypeId, ops::Deref};
|
||||
|
||||
/// Collection of special markers for custom syntax definition.
|
||||
pub mod markers {
|
||||
@ -71,12 +71,6 @@ impl Expression<'_> {
|
||||
pub fn get_variable_name(&self) -> Option<&str> {
|
||||
self.0.get_variable_name(true)
|
||||
}
|
||||
/// Get the expression.
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub(crate) const fn expr(&self) -> &Expr {
|
||||
&self.0
|
||||
}
|
||||
/// Get the position of this expression.
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
@ -134,6 +128,22 @@ impl Expression<'_> {
|
||||
}
|
||||
}
|
||||
|
||||
impl AsRef<Expr> for Expression<'_> {
|
||||
#[inline(always)]
|
||||
fn as_ref(&self) -> &Expr {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for Expression<'_> {
|
||||
type Target = Expr;
|
||||
|
||||
#[inline(always)]
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl EvalContext<'_, '_, '_, '_, '_, '_, '_, '_> {
|
||||
/// Evaluate an [expression tree][Expression].
|
||||
///
|
||||
@ -148,7 +158,7 @@ impl EvalContext<'_, '_, '_, '_, '_, '_, '_, '_> {
|
||||
self.state,
|
||||
self.lib,
|
||||
self.this_ptr,
|
||||
expr.expr(),
|
||||
expr,
|
||||
self.level,
|
||||
)
|
||||
}
|
||||
|
@ -29,15 +29,6 @@ use std::{
|
||||
ops::{Deref, DerefMut},
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
use crate::{Array, Blob};
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
use crate::Map;
|
||||
|
||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||
use crate::ast::FnCallHashes;
|
||||
|
||||
pub type Precedence = NonZeroU8;
|
||||
|
||||
/// _(internals)_ A stack of imported [modules][Module] plus mutable runtime global states.
|
||||
@ -246,7 +237,7 @@ impl Imports {
|
||||
/// Get the pre-calculated index getter hash.
|
||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||
#[must_use]
|
||||
pub(crate) fn fn_hash_idx_get(&mut self) -> u64 {
|
||||
pub(crate) fn hash_idx_get(&mut self) -> u64 {
|
||||
if self.fn_hash_indexing != (0, 0) {
|
||||
self.fn_hash_indexing.0
|
||||
} else {
|
||||
@ -259,7 +250,7 @@ impl Imports {
|
||||
/// Get the pre-calculated index setter hash.
|
||||
#[cfg(any(not(feature = "no_index"), not(feature = "no_object")))]
|
||||
#[must_use]
|
||||
pub(crate) fn fn_hash_idx_set(&mut self) -> u64 {
|
||||
pub(crate) fn hash_idx_set(&mut self) -> u64 {
|
||||
if self.fn_hash_indexing != (0, 0) {
|
||||
self.fn_hash_indexing.1
|
||||
} else {
|
||||
@ -559,7 +550,7 @@ impl<'a> Target<'a> {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Self::BitField(_, _, _) => TypeId::of::<T>() == TypeId::of::<bool>(),
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Self::BlobByte(_, _, _) => TypeId::of::<T>() == TypeId::of::<Blob>(),
|
||||
Self::BlobByte(_, _, _) => TypeId::of::<T>() == TypeId::of::<crate::Blob>(),
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Self::StringChar(_, _, _) => TypeId::of::<T>() == TypeId::of::<char>(),
|
||||
}
|
||||
@ -641,12 +632,12 @@ impl<'a> Target<'a> {
|
||||
))
|
||||
})?;
|
||||
|
||||
let value = &mut *value.write_lock::<Blob>().expect("`Blob`");
|
||||
let value = &mut *value.write_lock::<crate::Blob>().expect("`Blob`");
|
||||
|
||||
let index = *index;
|
||||
|
||||
if index < value.len() {
|
||||
value[index] = (new_byte & 0x000f) as u8;
|
||||
value[index] = (new_byte & 0x00ff) as u8;
|
||||
} else {
|
||||
unreachable!("blob index out of bounds: {}", index);
|
||||
}
|
||||
@ -945,7 +936,7 @@ pub struct Engine {
|
||||
pub(crate) module_resolver: Option<Box<dyn crate::ModuleResolver>>,
|
||||
|
||||
/// A map mapping type names to pretty-print names.
|
||||
pub(crate) type_names: BTreeMap<Identifier, Box<Identifier>>,
|
||||
pub(crate) type_names: BTreeMap<Identifier, Identifier>,
|
||||
|
||||
/// An empty [`ImmutableString`] for cloning purposes.
|
||||
pub(crate) empty_string: ImmutableString,
|
||||
@ -1372,7 +1363,8 @@ impl Engine {
|
||||
|
||||
if let Some(mut new_val) = try_setter {
|
||||
// Try to call index setter if value is changed
|
||||
let hash_set = FnCallHashes::from_native(mods.fn_hash_idx_set());
|
||||
let hash_set =
|
||||
crate::ast::FnCallHashes::from_native(mods.hash_idx_set());
|
||||
let args = &mut [target, &mut idx_val_for_setter, &mut new_val];
|
||||
|
||||
if let Err(err) = self.exec_fn_call(
|
||||
@ -1418,7 +1410,8 @@ impl Engine {
|
||||
|
||||
if let Some(mut new_val) = try_setter {
|
||||
// Try to call index setter
|
||||
let hash_set = FnCallHashes::from_native(mods.fn_hash_idx_set());
|
||||
let hash_set =
|
||||
crate::ast::FnCallHashes::from_native(mods.hash_idx_set());
|
||||
let args = &mut [target, &mut idx_val_for_setter, &mut new_val];
|
||||
|
||||
self.exec_fn_call(
|
||||
@ -1461,7 +1454,7 @@ impl Engine {
|
||||
unreachable!("function call in dot chain should not be namespace-qualified")
|
||||
}
|
||||
// {xxx:map}.id op= ???
|
||||
Expr::Property(x) if target.is::<Map>() && new_val.is_some() => {
|
||||
Expr::Property(x) if target.is::<crate::Map>() && new_val.is_some() => {
|
||||
let (name, pos) = &x.2;
|
||||
let ((new_val, new_pos), (op_info, op_pos)) = new_val.expect("`Some`");
|
||||
let index = name.into();
|
||||
@ -1479,7 +1472,7 @@ impl Engine {
|
||||
Ok((Dynamic::UNIT, true))
|
||||
}
|
||||
// {xxx:map}.id
|
||||
Expr::Property(x) if target.is::<Map>() => {
|
||||
Expr::Property(x) if target.is::<crate::Map>() => {
|
||||
let (name, pos) = &x.2;
|
||||
let index = name.into();
|
||||
let val = self.get_indexed_mut(
|
||||
@ -1493,7 +1486,7 @@ impl Engine {
|
||||
let ((mut new_val, new_pos), (op_info, op_pos)) = new_val.expect("`Some`");
|
||||
|
||||
if op_info.is_some() {
|
||||
let hash = FnCallHashes::from_native(*hash_get);
|
||||
let hash = crate::ast::FnCallHashes::from_native(*hash_get);
|
||||
let args = &mut [target.as_mut()];
|
||||
let (mut orig_val, _) = self
|
||||
.exec_fn_call(
|
||||
@ -1537,7 +1530,7 @@ impl Engine {
|
||||
new_val = orig_val;
|
||||
}
|
||||
|
||||
let hash = FnCallHashes::from_native(*hash_set);
|
||||
let hash = crate::ast::FnCallHashes::from_native(*hash_set);
|
||||
let args = &mut [target.as_mut(), &mut new_val];
|
||||
self.exec_fn_call(
|
||||
mods, state, lib, setter, hash, args, is_ref_mut, true, *pos, None,
|
||||
@ -1547,7 +1540,8 @@ impl Engine {
|
||||
// Try an indexer if property does not exist
|
||||
EvalAltResult::ErrorDotExpr(_, _) => {
|
||||
let args = &mut [target, &mut name.into(), &mut new_val];
|
||||
let hash_set = FnCallHashes::from_native(mods.fn_hash_idx_set());
|
||||
let hash_set =
|
||||
crate::ast::FnCallHashes::from_native(mods.hash_idx_set());
|
||||
let pos = Position::NONE;
|
||||
|
||||
self.exec_fn_call(
|
||||
@ -1567,7 +1561,7 @@ impl Engine {
|
||||
// xxx.id
|
||||
Expr::Property(x) => {
|
||||
let ((getter, hash_get), _, (name, pos)) = x.as_ref();
|
||||
let hash = FnCallHashes::from_native(*hash_get);
|
||||
let hash = crate::ast::FnCallHashes::from_native(*hash_get);
|
||||
let args = &mut [target.as_mut()];
|
||||
self.exec_fn_call(
|
||||
mods, state, lib, getter, hash, args, is_ref_mut, true, *pos, None,
|
||||
@ -1597,7 +1591,7 @@ impl Engine {
|
||||
}
|
||||
// {xxx:map}.sub_lhs[expr] | {xxx:map}.sub_lhs.expr
|
||||
Expr::Index(x, term, x_pos) | Expr::Dot(x, term, x_pos)
|
||||
if target.is::<Map>() =>
|
||||
if target.is::<crate::Map>() =>
|
||||
{
|
||||
let val_target = &mut match x.lhs {
|
||||
Expr::Property(ref p) => {
|
||||
@ -1641,8 +1635,8 @@ impl Engine {
|
||||
let ((getter, hash_get), (setter, hash_set), (name, pos)) =
|
||||
p.as_ref();
|
||||
let rhs_chain = match_chaining_type(rhs);
|
||||
let hash_get = FnCallHashes::from_native(*hash_get);
|
||||
let hash_set = FnCallHashes::from_native(*hash_set);
|
||||
let hash_get = crate::ast::FnCallHashes::from_native(*hash_get);
|
||||
let hash_set = crate::ast::FnCallHashes::from_native(*hash_set);
|
||||
let mut arg_values = [target.as_mut(), &mut Dynamic::UNIT.clone()];
|
||||
let args = &mut arg_values[..1];
|
||||
|
||||
@ -1705,9 +1699,10 @@ impl Engine {
|
||||
EvalAltResult::ErrorDotExpr(_, _) => {
|
||||
let args =
|
||||
&mut [target.as_mut(), &mut name.into(), val];
|
||||
let hash_set = FnCallHashes::from_native(
|
||||
mods.fn_hash_idx_set(),
|
||||
);
|
||||
let hash_set =
|
||||
crate::ast::FnCallHashes::from_native(
|
||||
mods.hash_idx_set(),
|
||||
);
|
||||
self.exec_fn_call(
|
||||
mods, state, lib, FN_IDX_SET, hash_set, args,
|
||||
is_ref_mut, true, *pos, None, level,
|
||||
@ -2160,7 +2155,7 @@ impl Engine {
|
||||
|
||||
_ if use_indexers => {
|
||||
let args = &mut [target, &mut idx];
|
||||
let hash_get = FnCallHashes::from_native(mods.fn_hash_idx_get());
|
||||
let hash_get = crate::ast::FnCallHashes::from_native(mods.hash_idx_get());
|
||||
let idx_pos = Position::NONE;
|
||||
|
||||
self.exec_fn_call(
|
||||
@ -2267,7 +2262,7 @@ impl Engine {
|
||||
Expr::Array(x, _) => Ok(x
|
||||
.iter()
|
||||
.try_fold(
|
||||
Array::with_capacity(x.len()),
|
||||
crate::Array::with_capacity(x.len()),
|
||||
|mut arr, item| -> Result<_, Box<EvalAltResult>> {
|
||||
arr.push(
|
||||
self.eval_expr(scope, mods, state, lib, this_ptr, item, level)?
|
||||
@ -2950,7 +2945,7 @@ impl Engine {
|
||||
}
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
_ => {
|
||||
let mut err_map = Map::new();
|
||||
let mut err_map = crate::Map::new();
|
||||
let err_pos = err.take_position();
|
||||
|
||||
err_map.insert("message".into(), err.to_string().into());
|
||||
|
@ -23,9 +23,6 @@ use std::{
|
||||
mem,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
use crate::Map;
|
||||
|
||||
/// Arguments to a function call, which is a list of [`&mut Dynamic`][Dynamic].
|
||||
pub type FnCallArgs<'a> = [&'a mut Dynamic];
|
||||
|
||||
@ -177,6 +174,10 @@ impl Engine {
|
||||
allow_dynamic: bool,
|
||||
is_op_assignment: bool,
|
||||
) -> Option<&'s FnResolutionCacheEntry> {
|
||||
if hash_script == 0 {
|
||||
return None;
|
||||
}
|
||||
|
||||
let fn_name = fn_name.as_ref();
|
||||
|
||||
let mut hash = args.as_ref().map_or(hash_script, |args| {
|
||||
@ -562,13 +563,10 @@ impl Engine {
|
||||
|
||||
// Scripted function call?
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
let hash_script = hashes.script;
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
if let Some(FnResolutionCacheEntry { func, source }) = hash_script.and_then(|hash| {
|
||||
self.resolve_fn(mods, state, lib, fn_name, hash, None, false, false)
|
||||
.cloned()
|
||||
}) {
|
||||
if let Some(FnResolutionCacheEntry { func, source }) = self
|
||||
.resolve_fn(mods, state, lib, fn_name, hashes.script, None, false, false)
|
||||
.cloned()
|
||||
{
|
||||
// Script function call
|
||||
assert!(func.is_script());
|
||||
|
||||
@ -579,11 +577,12 @@ impl Engine {
|
||||
}
|
||||
|
||||
let mut empty_scope;
|
||||
let scope = if let Some(scope) = _scope {
|
||||
scope
|
||||
} else {
|
||||
empty_scope = Scope::new();
|
||||
&mut empty_scope
|
||||
let scope = match _scope {
|
||||
Some(scope) => scope,
|
||||
None => {
|
||||
empty_scope = Scope::new();
|
||||
&mut empty_scope
|
||||
}
|
||||
};
|
||||
|
||||
let result = if _is_method_call {
|
||||
@ -840,7 +839,7 @@ impl Engine {
|
||||
|
||||
// Check if it is a map method call in OOP style
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
if let Some(map) = target.read_lock::<Map>() {
|
||||
if let Some(map) = target.read_lock::<crate::Map>() {
|
||||
if let Some(val) = map.get(fn_name) {
|
||||
if let Some(fn_ptr) = val.read_lock::<FnPtr>() {
|
||||
// Remap the function name
|
||||
|
@ -8,7 +8,24 @@ use std::{
|
||||
iter::empty,
|
||||
};
|
||||
|
||||
/// A hasher that only takes one single [`u64`] and returns it as a hash key.
|
||||
/// Dummy hash value to map zeros to. This value can be anything.
|
||||
///
|
||||
/// # Notes
|
||||
///
|
||||
/// Hashes are `u64`, and they can be zero (although extremely unlikely).
|
||||
/// It is possible to hijack the zero value to indicate non-existence,
|
||||
/// like [`None`] in [`Option<u64>`].
|
||||
///
|
||||
/// When a hash is calculated to be zero, it gets mapped to this alternate hash value.
|
||||
/// This has the effect of releasing the zero value at the expense of causing the probability of
|
||||
/// this value to double, which has minor impacts.
|
||||
pub const ALT_ZERO_HASH: u64 = 42;
|
||||
|
||||
/// A hasher that only takes one single [`u64`] and returns it as a non-zero hash key.
|
||||
///
|
||||
/// # Zeros
|
||||
///
|
||||
/// If the value is zero, it is mapped to `ALT_ZERO_HASH`.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
@ -29,6 +46,10 @@ impl Hasher for StraightHasher {
|
||||
key.copy_from_slice(bytes);
|
||||
|
||||
self.0 = u64::from_ne_bytes(key);
|
||||
|
||||
if self.0 == 0 {
|
||||
self.0 = ALT_ZERO_HASH
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -41,7 +62,7 @@ impl BuildHasher for StraightHasherBuilder {
|
||||
|
||||
#[inline(always)]
|
||||
fn build_hasher(&self) -> Self::Hasher {
|
||||
StraightHasher(42)
|
||||
StraightHasher(ALT_ZERO_HASH)
|
||||
}
|
||||
}
|
||||
|
||||
@ -52,11 +73,15 @@ pub fn get_hasher() -> ahash::AHasher {
|
||||
ahash::AHasher::default()
|
||||
}
|
||||
|
||||
/// Calculate a [`u64`] hash key from a namespace-qualified variable name.
|
||||
/// Calculate a non-zero [`u64`] hash key from a namespace-qualified variable name.
|
||||
///
|
||||
/// Module names are passed in via `&str` references from an iterator.
|
||||
/// Parameter types are passed in via [`TypeId`] values from an iterator.
|
||||
///
|
||||
/// # Zeros
|
||||
///
|
||||
/// If the hash happens to be zero, it is mapped to `DEFAULT_HASH`.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// The first module name is skipped. Hashing starts from the _second_ module in the chain.
|
||||
@ -76,15 +101,23 @@ pub fn calc_qualified_var_hash<'a>(
|
||||
.for_each(|m| m.as_ref().hash(s));
|
||||
len.hash(s);
|
||||
var_name.as_ref().hash(s);
|
||||
s.finish()
|
||||
|
||||
match s.finish() {
|
||||
0 => ALT_ZERO_HASH,
|
||||
r => r,
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate a [`u64`] hash key from a namespace-qualified function name
|
||||
/// Calculate a non-zero [`u64`] hash key from a namespace-qualified function name
|
||||
/// and the number of parameters, but no parameter types.
|
||||
///
|
||||
/// Module names are passed in via `&str` references from an iterator.
|
||||
/// Parameter types are passed in via [`TypeId`] values from an iterator.
|
||||
///
|
||||
/// # Zeros
|
||||
///
|
||||
/// If the hash happens to be zero, it is mapped to `DEFAULT_HASH`.
|
||||
///
|
||||
/// # Note
|
||||
///
|
||||
/// The first module name is skipped. Hashing starts from the _second_ module in the chain.
|
||||
@ -106,22 +139,34 @@ pub fn calc_qualified_fn_hash(
|
||||
len.hash(s);
|
||||
fn_name.as_ref().hash(s);
|
||||
num.hash(s);
|
||||
s.finish()
|
||||
|
||||
match s.finish() {
|
||||
0 => ALT_ZERO_HASH,
|
||||
r => r,
|
||||
}
|
||||
}
|
||||
|
||||
/// Calculate a [`u64`] hash key from a non-namespace-qualified function name
|
||||
/// Calculate a non-zero [`u64`] hash key from a non-namespace-qualified function name
|
||||
/// and the number of parameters, but no parameter types.
|
||||
///
|
||||
/// Parameter types are passed in via [`TypeId`] values from an iterator.
|
||||
///
|
||||
/// # Zeros
|
||||
///
|
||||
/// If the hash happens to be zero, it is mapped to `DEFAULT_HASH`.
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub fn calc_fn_hash(fn_name: impl AsRef<str>, num: usize) -> u64 {
|
||||
calc_qualified_fn_hash(empty::<&str>(), fn_name, num)
|
||||
}
|
||||
|
||||
/// Calculate a [`u64`] hash key from a list of parameter types.
|
||||
/// Calculate a non-zero [`u64`] hash key from a list of parameter types.
|
||||
///
|
||||
/// Parameter types are passed in via [`TypeId`] values from an iterator.
|
||||
///
|
||||
/// # Zeros
|
||||
///
|
||||
/// If the hash happens to be zero, it is mapped to `DEFAULT_HASH`.
|
||||
#[inline]
|
||||
#[must_use]
|
||||
pub fn calc_fn_params_hash(params: impl Iterator<Item = TypeId>) -> u64 {
|
||||
@ -129,12 +174,23 @@ pub fn calc_fn_params_hash(params: impl Iterator<Item = TypeId>) -> u64 {
|
||||
let mut len = 0;
|
||||
params.inspect(|_| len += 1).for_each(|t| t.hash(s));
|
||||
len.hash(s);
|
||||
s.finish()
|
||||
|
||||
match s.finish() {
|
||||
0 => ALT_ZERO_HASH,
|
||||
r => r,
|
||||
}
|
||||
}
|
||||
|
||||
/// Combine two [`u64`] hashes by taking the XOR of them.
|
||||
///
|
||||
/// # Zeros
|
||||
///
|
||||
/// If the hash happens to be zero, it is mapped to `DEFAULT_HASH`.
|
||||
#[inline(always)]
|
||||
#[must_use]
|
||||
pub const fn combine_hashes(a: u64, b: u64) -> u64 {
|
||||
a ^ b
|
||||
match a ^ b {
|
||||
0 => ALT_ZERO_HASH,
|
||||
r => r,
|
||||
}
|
||||
}
|
||||
|
@ -23,12 +23,6 @@ use std::{
|
||||
ops::{Add, AddAssign, Deref, DerefMut},
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
use crate::Array;
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
use crate::Map;
|
||||
|
||||
/// A type representing the namespace of a function.
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
||||
pub enum FnNamespace {
|
||||
@ -96,8 +90,7 @@ impl FuncInfo {
|
||||
}
|
||||
}
|
||||
|
||||
/// _(internals)_ Calculate a [`u64`] hash key from a namespace-qualified function name and
|
||||
/// parameter types.
|
||||
/// _(internals)_ Calculate a non-zero [`u64`] hash key from a namespace-qualified function name and parameter types.
|
||||
/// Exported under the `internals` feature only.
|
||||
///
|
||||
/// Module names are passed in via `&str` references from an iterator.
|
||||
@ -107,7 +100,7 @@ impl FuncInfo {
|
||||
///
|
||||
/// The first module name is skipped. Hashing starts from the _second_ module in the chain.
|
||||
#[inline]
|
||||
fn calc_native_fn_hash(
|
||||
pub fn calc_native_fn_hash(
|
||||
modules: impl Iterator<Item = impl AsRef<str>>,
|
||||
fn_name: impl AsRef<str>,
|
||||
params: &[TypeId],
|
||||
@ -180,8 +173,7 @@ impl fmt::Debug for Module {
|
||||
d.field(
|
||||
"functions",
|
||||
&self
|
||||
.functions
|
||||
.values()
|
||||
.iter_fn()
|
||||
.map(|f| f.func.to_string())
|
||||
.collect::<BTreeSet<_>>(),
|
||||
);
|
||||
@ -359,9 +351,8 @@ impl Module {
|
||||
#[cfg(feature = "metadata")]
|
||||
#[inline]
|
||||
pub fn gen_fn_signatures(&self) -> impl Iterator<Item = String> + '_ {
|
||||
self.functions
|
||||
.values()
|
||||
.filter(|f| match f.access {
|
||||
self.iter_fn()
|
||||
.filter(|&f| match f.access {
|
||||
FnAccess::Public => true,
|
||||
FnAccess::Private => false,
|
||||
})
|
||||
@ -502,8 +493,7 @@ impl Module {
|
||||
} else {
|
||||
let name = name.as_ref();
|
||||
|
||||
self.functions
|
||||
.values()
|
||||
self.iter_fn()
|
||||
.find(|f| f.params == num_params && f.name == name)
|
||||
.and_then(|f| f.func.get_script_fn_def())
|
||||
}
|
||||
@ -667,7 +657,7 @@ impl Module {
|
||||
type_id
|
||||
}
|
||||
|
||||
/// Set a Rust function into the [`Module`], returning a hash key.
|
||||
/// Set a Rust function into the [`Module`], returning a non-zero hash key.
|
||||
///
|
||||
/// If there is an existing Rust function of the same hash, it is replaced.
|
||||
///
|
||||
@ -729,7 +719,7 @@ impl Module {
|
||||
|
||||
/// Set a Rust function taking a reference to the scripting [`Engine`][crate::Engine],
|
||||
/// the current set of functions, plus a list of mutable [`Dynamic`] references
|
||||
/// into the [`Module`], returning a hash key.
|
||||
/// into the [`Module`], returning a non-zero hash key.
|
||||
///
|
||||
/// Use this to register a built-in function which must reference settings on the scripting
|
||||
/// [`Engine`][crate::Engine] (e.g. to prevent growing an array beyond the allowed maximum size),
|
||||
@ -822,7 +812,7 @@ impl Module {
|
||||
)
|
||||
}
|
||||
|
||||
/// Set a Rust function into the [`Module`], returning a hash key.
|
||||
/// Set a Rust function into the [`Module`], returning a non-zero hash key.
|
||||
///
|
||||
/// If there is a similar existing Rust function, it is replaced.
|
||||
///
|
||||
@ -861,7 +851,7 @@ impl Module {
|
||||
)
|
||||
}
|
||||
|
||||
/// Set a Rust getter function taking one mutable parameter, returning a hash key.
|
||||
/// Set a Rust getter function taking one mutable parameter, returning a non-zero hash key.
|
||||
/// This function is automatically exposed to the global namespace.
|
||||
///
|
||||
/// If there is a similar existing Rust getter function, it is replaced.
|
||||
@ -898,7 +888,7 @@ impl Module {
|
||||
}
|
||||
|
||||
/// Set a Rust setter function taking two parameters (the first one mutable) into the [`Module`],
|
||||
/// returning a hash key.
|
||||
/// returning a non-zero hash key.
|
||||
/// This function is automatically exposed to the global namespace.
|
||||
///
|
||||
/// If there is a similar existing setter Rust function, it is replaced.
|
||||
@ -939,14 +929,14 @@ impl Module {
|
||||
}
|
||||
|
||||
/// Set a Rust index getter taking two parameters (the first one mutable) into the [`Module`],
|
||||
/// returning a hash key.
|
||||
/// returning a non-zero hash key.
|
||||
/// This function is automatically exposed to the global namespace.
|
||||
///
|
||||
/// If there is a similar existing setter Rust function, it is replaced.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the type is [`Array`] or [`Map`].
|
||||
/// Panics if the type is [`Array`][crate::Array] or [`Map`][crate::Map].
|
||||
/// Indexers for arrays, object maps and strings cannot be registered.
|
||||
///
|
||||
/// # Function Metadata
|
||||
@ -975,11 +965,11 @@ impl Module {
|
||||
F: Fn(&mut A, B) -> Result<T, Box<EvalAltResult>> + SendSync + 'static,
|
||||
{
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
if TypeId::of::<A>() == TypeId::of::<Array>() {
|
||||
if TypeId::of::<A>() == TypeId::of::<crate::Array>() {
|
||||
panic!("Cannot register indexer for arrays.");
|
||||
}
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
if TypeId::of::<A>() == TypeId::of::<Map>() {
|
||||
if TypeId::of::<A>() == TypeId::of::<crate::Map>() {
|
||||
panic!("Cannot register indexer for object maps.");
|
||||
}
|
||||
if TypeId::of::<A>() == TypeId::of::<String>()
|
||||
@ -1000,14 +990,14 @@ impl Module {
|
||||
}
|
||||
|
||||
/// Set a Rust index setter taking three parameters (the first one mutable) into the [`Module`],
|
||||
/// returning a hash key.
|
||||
/// returning a non-zero hash key.
|
||||
/// This function is automatically exposed to the global namespace.
|
||||
///
|
||||
/// If there is a similar existing Rust function, it is replaced.
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the type is [`Array`] or [`Map`].
|
||||
/// Panics if the type is [`Array`][crate::Array] or [`Map`][crate::Map].
|
||||
/// Indexers for arrays, object maps and strings cannot be registered.
|
||||
///
|
||||
/// # Function Metadata
|
||||
@ -1036,11 +1026,11 @@ impl Module {
|
||||
F: Fn(&mut A, B, C) -> Result<(), Box<EvalAltResult>> + SendSync + 'static,
|
||||
{
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
if TypeId::of::<A>() == TypeId::of::<Array>() {
|
||||
if TypeId::of::<A>() == TypeId::of::<crate::Array>() {
|
||||
panic!("Cannot register indexer for arrays.");
|
||||
}
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
if TypeId::of::<A>() == TypeId::of::<Map>() {
|
||||
if TypeId::of::<A>() == TypeId::of::<crate::Map>() {
|
||||
panic!("Cannot register indexer for object maps.");
|
||||
}
|
||||
if TypeId::of::<A>() == TypeId::of::<String>()
|
||||
@ -1060,7 +1050,7 @@ impl Module {
|
||||
)
|
||||
}
|
||||
|
||||
/// Set a pair of Rust index getter and setter functions, returning both hash keys.
|
||||
/// Set a pair of Rust index getter and setter functions, returning both non-zero hash keys.
|
||||
/// This is a short-hand for [`set_indexer_get_fn`][Module::set_indexer_get_fn] and
|
||||
/// [`set_indexer_set_fn`][Module::set_indexer_set_fn].
|
||||
///
|
||||
@ -1068,7 +1058,7 @@ impl Module {
|
||||
///
|
||||
/// # Panics
|
||||
///
|
||||
/// Panics if the type is [`Array`] or [`Map`].
|
||||
/// Panics if the type is [`Array`][crate::Array] or [`Map`][crate::Map].
|
||||
/// Indexers for arrays, object maps and strings cannot be registered.
|
||||
///
|
||||
/// # Function Metadata
|
||||
@ -1233,7 +1223,7 @@ impl Module {
|
||||
other
|
||||
.functions
|
||||
.iter()
|
||||
.filter(|(_, f)| {
|
||||
.filter(|&(_, f)| {
|
||||
_filter(
|
||||
f.namespace,
|
||||
f.access,
|
||||
@ -1332,18 +1322,15 @@ impl Module {
|
||||
&Shared<crate::ast::ScriptFnDef>,
|
||||
),
|
||||
> + '_ {
|
||||
self.functions
|
||||
.values()
|
||||
.filter(|f| f.func.is_script())
|
||||
.map(|f| {
|
||||
(
|
||||
f.namespace,
|
||||
f.access,
|
||||
f.name.as_str(),
|
||||
f.params,
|
||||
f.func.get_script_fn_def().expect("scripted function"),
|
||||
)
|
||||
})
|
||||
self.iter_fn().filter(|&f| f.func.is_script()).map(|f| {
|
||||
(
|
||||
f.namespace,
|
||||
f.access,
|
||||
f.name.as_str(),
|
||||
f.params,
|
||||
f.func.get_script_fn_def().expect("scripted function"),
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
/// Get an iterator over all script-defined functions in the [`Module`].
|
||||
@ -1359,9 +1346,8 @@ impl Module {
|
||||
pub fn iter_script_fn_info(
|
||||
&self,
|
||||
) -> impl Iterator<Item = (FnNamespace, FnAccess, &str, usize)> {
|
||||
self.functions
|
||||
.values()
|
||||
.filter(|f| f.func.is_script())
|
||||
self.iter_fn()
|
||||
.filter(|&f| f.func.is_script())
|
||||
.map(|f| (f.namespace, f.access, f.name.as_str(), f.params))
|
||||
}
|
||||
|
||||
@ -1462,13 +1448,12 @@ impl Module {
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
if ast.has_functions() {
|
||||
ast.shared_lib()
|
||||
.functions
|
||||
.values()
|
||||
.filter(|f| match f.access {
|
||||
.iter_fn()
|
||||
.filter(|&f| match f.access {
|
||||
FnAccess::Public => true,
|
||||
FnAccess::Private => false,
|
||||
})
|
||||
.filter(|f| f.func.is_script())
|
||||
.filter(|&f| f.func.is_script())
|
||||
.for_each(|f| {
|
||||
// Encapsulate AST environment
|
||||
let mut func = f
|
||||
|
@ -31,7 +31,7 @@ pub trait ModuleResolver: SendSync {
|
||||
/// Returns [`None`] (default) if such resolution is not supported
|
||||
/// (e.g. if the module is Rust-based).
|
||||
///
|
||||
/// ## Low-Level API
|
||||
/// # WARNING - Low Level API
|
||||
///
|
||||
/// Override the default implementation of this method if the module resolver
|
||||
/// serves modules based on compiled Rhai scripts.
|
||||
|
@ -304,11 +304,9 @@ fn optimize_stmt_block(
|
||||
if reduce_return && !options.contains(AST_OPTION_BREAK_OUT) =>
|
||||
{
|
||||
state.set_dirty();
|
||||
*statements.last_mut().expect(">= 2 elements") = if let Some(expr) = expr {
|
||||
Stmt::Expr(mem::take(expr))
|
||||
} else {
|
||||
Stmt::Noop(pos)
|
||||
};
|
||||
*statements.last_mut().expect(">= 2 elements") = expr
|
||||
.as_mut()
|
||||
.map_or_else(|| Stmt::Noop(pos), |e| Stmt::Expr(mem::take(e)));
|
||||
}
|
||||
// { ...; stmt; noop } -> done
|
||||
[.., ref second_last_stmt, Stmt::Noop(_)]
|
||||
|
@ -205,22 +205,7 @@ mod array_functions {
|
||||
}
|
||||
#[rhai_fn(name = "extract")]
|
||||
pub fn extract_tail(array: &mut Array, start: INT) -> Array {
|
||||
if array.is_empty() {
|
||||
return Array::new();
|
||||
}
|
||||
|
||||
let start = if start < 0 {
|
||||
let arr_len = array.len();
|
||||
start
|
||||
.checked_abs()
|
||||
.map_or(0, |n| arr_len - (n as usize).min(arr_len))
|
||||
} else if start as usize >= array.len() {
|
||||
return Array::new();
|
||||
} else {
|
||||
start as usize
|
||||
};
|
||||
|
||||
array[start..].to_vec()
|
||||
extract(array, start, INT::MAX)
|
||||
}
|
||||
#[rhai_fn(name = "split")]
|
||||
pub fn split_at(array: &mut Array, start: INT) -> Array {
|
||||
|
@ -7,6 +7,9 @@ use crate::{def_package, Blob, Dynamic, EvalAltResult, NativeCallContext, Positi
|
||||
use std::prelude::v1::*;
|
||||
use std::{any::TypeId, mem};
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
use crate::FLOAT;
|
||||
|
||||
def_package!(crate:BasicBlobPackage:"Basic BLOB utilities.", lib, {
|
||||
lib.standard = true;
|
||||
|
||||
@ -48,7 +51,7 @@ mod blob_functions {
|
||||
}
|
||||
|
||||
let mut blob = Blob::new();
|
||||
blob.resize(len, (value & 0x000f) as u8);
|
||||
blob.resize(len, (value & 0x00ff) as u8);
|
||||
Ok(blob)
|
||||
}
|
||||
#[rhai_fn(name = "len", get = "len", pure)]
|
||||
@ -57,7 +60,7 @@ mod blob_functions {
|
||||
}
|
||||
#[rhai_fn(name = "push", name = "+=")]
|
||||
pub fn push(blob: &mut Blob, item: INT) {
|
||||
let item = (item & 0x000f) as u8;
|
||||
let item = (item & 0x00ff) as u8;
|
||||
blob.push(item);
|
||||
}
|
||||
#[rhai_fn(name = "append", name = "+=")]
|
||||
@ -82,7 +85,7 @@ mod blob_functions {
|
||||
blob
|
||||
}
|
||||
pub fn insert(blob: &mut Blob, position: INT, item: INT) {
|
||||
let item = (item & 0x000f) as u8;
|
||||
let item = (item & 0x00ff) as u8;
|
||||
|
||||
if blob.is_empty() {
|
||||
blob.push(item);
|
||||
@ -113,7 +116,7 @@ mod blob_functions {
|
||||
return Ok(());
|
||||
}
|
||||
|
||||
let item = (item & 0x000f) as u8;
|
||||
let item = (item & 0x00ff) as u8;
|
||||
let _ctx = ctx;
|
||||
|
||||
// Check if blob will be over max size limit
|
||||
@ -186,13 +189,13 @@ mod blob_functions {
|
||||
*blob = replace;
|
||||
return;
|
||||
}
|
||||
let blob_len = blob.len();
|
||||
|
||||
let start = if start < 0 {
|
||||
let arr_len = blob.len();
|
||||
start
|
||||
.checked_abs()
|
||||
.map_or(0, |n| arr_len - (n as usize).min(arr_len))
|
||||
} else if start as usize >= blob.len() {
|
||||
.map_or(0, |n| blob_len - (n as usize).min(blob_len))
|
||||
} else if start as usize >= blob_len {
|
||||
blob.extend(replace.into_iter());
|
||||
return;
|
||||
} else {
|
||||
@ -201,8 +204,8 @@ mod blob_functions {
|
||||
|
||||
let len = if len < 0 {
|
||||
0
|
||||
} else if len as usize > blob.len() - start {
|
||||
blob.len() - start
|
||||
} else if len as usize > blob_len - start {
|
||||
blob_len - start
|
||||
} else {
|
||||
len as usize
|
||||
};
|
||||
@ -213,50 +216,29 @@ mod blob_functions {
|
||||
if blob.is_empty() || len <= 0 {
|
||||
return Blob::new();
|
||||
}
|
||||
let blob_len = blob.len();
|
||||
|
||||
let start = if start < 0 {
|
||||
let arr_len = blob.len();
|
||||
start
|
||||
.checked_abs()
|
||||
.map_or(0, |n| arr_len - (n as usize).min(arr_len))
|
||||
} else if start as usize >= blob.len() {
|
||||
.map_or(0, |n| blob_len - (n as usize).min(blob_len))
|
||||
} else if start as usize >= blob_len {
|
||||
return Blob::new();
|
||||
} else {
|
||||
start as usize
|
||||
};
|
||||
|
||||
let len = if len <= 0 {
|
||||
0
|
||||
} else if len as usize > blob.len() - start {
|
||||
blob.len() - start
|
||||
let len = if len as usize > blob_len - start {
|
||||
blob_len - start
|
||||
} else {
|
||||
len as usize
|
||||
};
|
||||
|
||||
if len == 0 {
|
||||
Blob::new()
|
||||
} else {
|
||||
blob[start..start + len].to_vec()
|
||||
}
|
||||
blob[start..start + len].to_vec()
|
||||
}
|
||||
#[rhai_fn(name = "extract")]
|
||||
pub fn extract_tail(blob: &mut Blob, start: INT) -> Blob {
|
||||
if blob.is_empty() {
|
||||
return Blob::new();
|
||||
}
|
||||
|
||||
let start = if start < 0 {
|
||||
let arr_len = blob.len();
|
||||
start
|
||||
.checked_abs()
|
||||
.map_or(0, |n| arr_len - (n as usize).min(arr_len))
|
||||
} else if start as usize >= blob.len() {
|
||||
return Blob::new();
|
||||
} else {
|
||||
start as usize
|
||||
};
|
||||
|
||||
blob[start..].to_vec()
|
||||
extract(blob, start, INT::MAX)
|
||||
}
|
||||
#[rhai_fn(name = "split")]
|
||||
pub fn split_at(blob: &mut Blob, start: INT) -> Blob {
|
||||
@ -286,22 +268,20 @@ mod blob_functions {
|
||||
if blob.is_empty() || len <= 0 {
|
||||
return Blob::new();
|
||||
}
|
||||
let blob_len = blob.len();
|
||||
|
||||
let start = if start < 0 {
|
||||
let arr_len = blob.len();
|
||||
start
|
||||
.checked_abs()
|
||||
.map_or(0, |n| arr_len - (n as usize).min(arr_len))
|
||||
} else if start as usize >= blob.len() {
|
||||
.map_or(0, |n| blob_len - (n as usize).min(blob_len))
|
||||
} else if start as usize >= blob_len {
|
||||
return Blob::new();
|
||||
} else {
|
||||
start as usize
|
||||
};
|
||||
|
||||
let len = if len <= 0 {
|
||||
0
|
||||
} else if len as usize > blob.len() - start {
|
||||
blob.len() - start
|
||||
let len = if len as usize > blob_len - start {
|
||||
blob_len - start
|
||||
} else {
|
||||
len as usize
|
||||
};
|
||||
@ -312,22 +292,20 @@ mod blob_functions {
|
||||
if blob.is_empty() || len <= 0 {
|
||||
return Blob::new();
|
||||
}
|
||||
let blob_len = blob.len();
|
||||
|
||||
let start = if start < 0 {
|
||||
let arr_len = blob.len();
|
||||
start
|
||||
.checked_abs()
|
||||
.map_or(0, |n| arr_len - (n as usize).min(arr_len))
|
||||
} else if start as usize >= blob.len() {
|
||||
.map_or(0, |n| blob_len - (n as usize).min(blob_len))
|
||||
} else if start as usize >= blob_len {
|
||||
return mem::take(blob);
|
||||
} else {
|
||||
start as usize
|
||||
};
|
||||
|
||||
let len = if len < 0 {
|
||||
0
|
||||
} else if len as usize > blob.len() - start {
|
||||
blob.len() - start
|
||||
let len = if len as usize > blob_len - start {
|
||||
blob_len - start
|
||||
} else {
|
||||
len as usize
|
||||
};
|
||||
@ -337,18 +315,212 @@ mod blob_functions {
|
||||
|
||||
drained
|
||||
}
|
||||
pub fn contains(blob: &mut Blob, value: Dynamic) -> bool {
|
||||
if blob.is_empty() {
|
||||
return false;
|
||||
}
|
||||
|
||||
let value = match value.as_int() {
|
||||
Ok(value) => value as u8,
|
||||
_ => return false,
|
||||
};
|
||||
|
||||
blob.contains(&value)
|
||||
}
|
||||
#[rhai_fn(name = "==", pure)]
|
||||
pub fn equals(blob1: &mut Blob, blob2: Blob) -> bool {
|
||||
if blob1.len() != blob2.len() {
|
||||
false
|
||||
} else if blob1.is_empty() {
|
||||
true
|
||||
} else {
|
||||
blob1.iter().zip(blob2.iter()).all(|(&v1, &v2)| v1 == v2)
|
||||
}
|
||||
&*blob1 == &blob2
|
||||
}
|
||||
#[rhai_fn(name = "!=", pure)]
|
||||
pub fn not_equals(blob1: &mut Blob, blob2: Blob) -> bool {
|
||||
!equals(blob1, blob2)
|
||||
&*blob1 != &blob2
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn parse_int(blob: &mut Blob, start: INT, len: INT, is_le: bool) -> INT {
|
||||
if blob.is_empty() || len <= 0 {
|
||||
return 0;
|
||||
}
|
||||
let blob_len = blob.len();
|
||||
|
||||
let start = if start < 0 {
|
||||
start
|
||||
.checked_abs()
|
||||
.map_or(0, |n| blob_len - (n as usize).min(blob_len))
|
||||
} else if start as usize >= blob_len {
|
||||
return 0;
|
||||
} else {
|
||||
start as usize
|
||||
};
|
||||
|
||||
let len = if len as usize > blob_len - start {
|
||||
blob_len - start
|
||||
} else {
|
||||
len as usize
|
||||
};
|
||||
|
||||
const INT_BYTES: usize = mem::size_of::<INT>();
|
||||
|
||||
let len = usize::min(len, INT_BYTES);
|
||||
|
||||
let mut buf = [0_u8; INT_BYTES];
|
||||
|
||||
buf[..len].copy_from_slice(&blob[start..][..len]);
|
||||
|
||||
if is_le {
|
||||
INT::from_le_bytes(buf)
|
||||
} else {
|
||||
INT::from_be_bytes(buf)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse_le_int(blob: &mut Blob, start: INT, len: INT) -> INT {
|
||||
parse_int(blob, start, len, true)
|
||||
}
|
||||
pub fn parse_be_int(blob: &mut Blob, start: INT, len: INT) -> INT {
|
||||
parse_int(blob, start, len, false)
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn write_int(blob: &mut Blob, start: INT, len: INT, value: INT, is_le: bool) {
|
||||
if blob.is_empty() || len <= 0 {
|
||||
return;
|
||||
}
|
||||
let blob_len = blob.len();
|
||||
|
||||
let start = if start < 0 {
|
||||
start
|
||||
.checked_abs()
|
||||
.map_or(0, |n| blob_len - (n as usize).min(blob_len))
|
||||
} else if start as usize >= blob_len {
|
||||
return;
|
||||
} else {
|
||||
start as usize
|
||||
};
|
||||
|
||||
let len = if len as usize > blob_len - start {
|
||||
blob_len - start
|
||||
} else {
|
||||
len as usize
|
||||
};
|
||||
|
||||
const INT_BYTES: usize = mem::size_of::<INT>();
|
||||
|
||||
let len = usize::min(len, INT_BYTES);
|
||||
|
||||
let mut buf = [0_u8; INT_BYTES];
|
||||
|
||||
buf.copy_from_slice(&if is_le {
|
||||
value.to_le_bytes()
|
||||
} else {
|
||||
value.to_be_bytes()
|
||||
});
|
||||
|
||||
blob[start..][..len].copy_from_slice(&buf[..len]);
|
||||
}
|
||||
#[rhai_fn(name = "write_le")]
|
||||
pub fn write_le_int(blob: &mut Blob, start: INT, len: INT, value: INT) {
|
||||
write_int(blob, start, len, value, true)
|
||||
}
|
||||
#[rhai_fn(name = "write_be")]
|
||||
pub fn write_be_int(blob: &mut Blob, start: INT, len: INT, value: INT) {
|
||||
write_int(blob, start, len, value, false)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
#[inline]
|
||||
fn parse_float(blob: &mut Blob, start: INT, len: INT, is_le: bool) -> FLOAT {
|
||||
if blob.is_empty() || len <= 0 {
|
||||
return 0.0;
|
||||
}
|
||||
let blob_len = blob.len();
|
||||
|
||||
let start = if start < 0 {
|
||||
start
|
||||
.checked_abs()
|
||||
.map_or(0, |n| blob_len - (n as usize).min(blob_len))
|
||||
} else if start as usize >= blob_len {
|
||||
return 0.0;
|
||||
} else {
|
||||
start as usize
|
||||
};
|
||||
|
||||
let len = if len as usize > blob_len - start {
|
||||
blob_len - start
|
||||
} else {
|
||||
len as usize
|
||||
};
|
||||
|
||||
const FLOAT_BYTES: usize = mem::size_of::<FLOAT>();
|
||||
|
||||
let len = usize::min(len, FLOAT_BYTES);
|
||||
|
||||
let mut buf = [0_u8; FLOAT_BYTES];
|
||||
|
||||
buf[..len].copy_from_slice(&blob[start..][..len]);
|
||||
|
||||
if is_le {
|
||||
FLOAT::from_le_bytes(buf)
|
||||
} else {
|
||||
FLOAT::from_be_bytes(buf)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
pub fn parse_le_float(blob: &mut Blob, start: INT, len: INT) -> FLOAT {
|
||||
parse_float(blob, start, len, true)
|
||||
}
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
pub fn parse_be_float(blob: &mut Blob, start: INT, len: INT) -> FLOAT {
|
||||
parse_float(blob, start, len, false)
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
#[inline]
|
||||
fn write_float(blob: &mut Blob, start: INT, len: INT, value: FLOAT, is_le: bool) {
|
||||
if blob.is_empty() || len <= 0 {
|
||||
return;
|
||||
}
|
||||
let blob_len = blob.len();
|
||||
|
||||
let start = if start < 0 {
|
||||
start
|
||||
.checked_abs()
|
||||
.map_or(0, |n| blob_len - (n as usize).min(blob_len))
|
||||
} else if start as usize >= blob_len {
|
||||
return;
|
||||
} else {
|
||||
start as usize
|
||||
};
|
||||
|
||||
let len = if len as usize > blob_len - start {
|
||||
blob_len - start
|
||||
} else {
|
||||
len as usize
|
||||
};
|
||||
|
||||
const FLOAT_BYTES: usize = mem::size_of::<FLOAT>();
|
||||
|
||||
let len = usize::min(len, FLOAT_BYTES);
|
||||
|
||||
let mut buf = [0_u8; FLOAT_BYTES];
|
||||
|
||||
buf.copy_from_slice(&if is_le {
|
||||
value.to_le_bytes()
|
||||
} else {
|
||||
value.to_be_bytes()
|
||||
});
|
||||
|
||||
blob[start..][..len].copy_from_slice(&buf[..len]);
|
||||
}
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
#[rhai_fn(name = "write_le")]
|
||||
pub fn write_le_float(blob: &mut Blob, start: INT, len: INT, value: FLOAT) {
|
||||
write_float(blob, start, len, value, true)
|
||||
}
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
#[rhai_fn(name = "write_be")]
|
||||
pub fn write_be_float(blob: &mut Blob, start: INT, len: INT, value: FLOAT) {
|
||||
write_float(blob, start, len, value, false)
|
||||
}
|
||||
}
|
||||
|
@ -6,7 +6,7 @@ use crate::{def_package, Position, INT};
|
||||
use std::prelude::v1::*;
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
use crate::{EvalAltResult, FLOAT};
|
||||
use crate::FLOAT;
|
||||
|
||||
#[cfg(feature = "no_std")]
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
|
@ -37,10 +37,11 @@ pub use time_basic::BasicTimePackage;
|
||||
|
||||
/// Trait that all packages must implement.
|
||||
pub trait Package {
|
||||
/// Register all the functions in a package into a store.
|
||||
fn init(lib: &mut Module);
|
||||
/// Initialize the package.
|
||||
/// Functions should be registered into `module` here.
|
||||
fn init(module: &mut Module);
|
||||
|
||||
/// Retrieve the generic package library from this package.
|
||||
/// Get a reference to a shared module from this package.
|
||||
#[must_use]
|
||||
fn as_shared_module(&self) -> Shared<Module>;
|
||||
}
|
||||
@ -60,10 +61,10 @@ pub trait Package {
|
||||
///
|
||||
/// fn add(x: i64, y: i64) -> Result<i64, Box<EvalAltResult>> { Ok(x + y) }
|
||||
///
|
||||
/// def_package!(rhai:MyPackage:"My super-duper package", lib,
|
||||
/// def_package!(rhai:MyPackage:"My super-duper package", module,
|
||||
/// {
|
||||
/// // Load a binary function with all value parameters.
|
||||
/// lib.set_native_fn("my_add", add);
|
||||
/// module.set_native_fn("my_add", add);
|
||||
/// });
|
||||
/// ```
|
||||
#[macro_export]
|
||||
@ -76,7 +77,6 @@ macro_rules! def_package {
|
||||
fn as_shared_module(&self) -> $root::Shared<$root::Module> {
|
||||
self.0.clone()
|
||||
}
|
||||
|
||||
fn init($lib: &mut $root::Module) {
|
||||
$block
|
||||
}
|
||||
|
@ -27,12 +27,6 @@ use std::{
|
||||
ops::AddAssign,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
use crate::{custom_syntax::markers::CUSTOM_SYNTAX_MARKER_FLOAT, FLOAT};
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
use crate::FnAccess;
|
||||
|
||||
type PERR = ParseErrorType;
|
||||
|
||||
type FunctionsLib = BTreeMap<u64, Shared<ScriptFnDef>>;
|
||||
@ -1054,19 +1048,18 @@ fn parse_switch(
|
||||
};
|
||||
|
||||
let hash = if let Some(expr) = expr {
|
||||
if let Some(value) = expr.get_literal_value() {
|
||||
let hasher = &mut get_hasher();
|
||||
value.hash(hasher);
|
||||
let hash = hasher.finish();
|
||||
let value = expr.get_literal_value().ok_or_else(|| {
|
||||
PERR::ExprExpected("a literal".to_string()).into_err(expr.position())
|
||||
})?;
|
||||
let hasher = &mut get_hasher();
|
||||
value.hash(hasher);
|
||||
let hash = hasher.finish();
|
||||
|
||||
if table.contains_key(&hash) {
|
||||
return Err(PERR::DuplicatedSwitchCase.into_err(expr.position()));
|
||||
}
|
||||
|
||||
Some(hash)
|
||||
} else {
|
||||
return Err(PERR::ExprExpected("a literal".to_string()).into_err(expr.position()));
|
||||
if table.contains_key(&hash) {
|
||||
return Err(PERR::DuplicatedSwitchCase.into_err(expr.position()));
|
||||
}
|
||||
|
||||
Some(hash)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
@ -1087,11 +1080,12 @@ fn parse_switch(
|
||||
|
||||
let need_comma = !stmt.is_self_terminated();
|
||||
|
||||
def_stmt = if let Some(hash) = hash {
|
||||
table.insert(hash, (condition, stmt.into()).into());
|
||||
None
|
||||
} else {
|
||||
Some(stmt.into())
|
||||
def_stmt = match hash {
|
||||
Some(hash) => {
|
||||
table.insert(hash, (condition, stmt.into()).into());
|
||||
None
|
||||
}
|
||||
None => Some(stmt.into()),
|
||||
};
|
||||
|
||||
match input.peek().expect(NEVER_ENDS) {
|
||||
@ -1573,7 +1567,7 @@ fn parse_unary(
|
||||
.map(|i| Expr::IntegerConstant(i, pos))
|
||||
.or_else(|| {
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
return Some(Expr::FloatConstant((-(num as FLOAT)).into(), pos));
|
||||
return Some(Expr::FloatConstant((-(num as crate::FLOAT)).into(), pos));
|
||||
#[cfg(feature = "no_float")]
|
||||
return None;
|
||||
})
|
||||
@ -2173,19 +2167,23 @@ fn parse_custom_syntax(
|
||||
}
|
||||
},
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
CUSTOM_SYNTAX_MARKER_FLOAT => match input.next().expect(NEVER_ENDS) {
|
||||
(Token::FloatConstant(f), pos) => {
|
||||
inputs.push(Expr::FloatConstant(f, pos));
|
||||
segments.push(f.to_string().into());
|
||||
tokens.push(state.get_identifier(CUSTOM_SYNTAX_MARKER_FLOAT));
|
||||
crate::custom_syntax::markers::CUSTOM_SYNTAX_MARKER_FLOAT => {
|
||||
match input.next().expect(NEVER_ENDS) {
|
||||
(Token::FloatConstant(f), pos) => {
|
||||
inputs.push(Expr::FloatConstant(f, pos));
|
||||
segments.push(f.to_string().into());
|
||||
tokens.push(state.get_identifier(
|
||||
crate::custom_syntax::markers::CUSTOM_SYNTAX_MARKER_FLOAT,
|
||||
));
|
||||
}
|
||||
(_, pos) => {
|
||||
return Err(PERR::MissingSymbol(
|
||||
"Expecting a floating-point number".to_string(),
|
||||
)
|
||||
.into_err(pos))
|
||||
}
|
||||
}
|
||||
(_, pos) => {
|
||||
return Err(PERR::MissingSymbol(
|
||||
"Expecting a floating-point number".to_string(),
|
||||
)
|
||||
.into_err(pos))
|
||||
}
|
||||
},
|
||||
}
|
||||
CUSTOM_SYNTAX_MARKER_STRING => match input.next().expect(NEVER_ENDS) {
|
||||
(Token::StringConstant(s), pos) => {
|
||||
let s: ImmutableString = state.get_identifier(s).into();
|
||||
@ -2463,14 +2461,12 @@ fn parse_for(
|
||||
|
||||
let prev_stack_len = state.stack.len();
|
||||
|
||||
let counter_var = if let Some(name) = counter_name {
|
||||
let counter_var = counter_name.map(|name| {
|
||||
let name = state.get_identifier(name);
|
||||
let pos = counter_pos.expect("`Some`");
|
||||
state.stack.push((name.clone(), AccessMode::ReadWrite));
|
||||
Some(Ident { name, pos })
|
||||
} else {
|
||||
None
|
||||
};
|
||||
Ident { name, pos }
|
||||
});
|
||||
|
||||
let loop_var = state.get_identifier(name);
|
||||
state.stack.push((loop_var.clone(), AccessMode::ReadWrite));
|
||||
@ -2849,9 +2845,9 @@ fn parse_stmt(
|
||||
Token::Fn | Token::Private => {
|
||||
let access = if matches!(token, Token::Private) {
|
||||
eat_token(input, Token::Private);
|
||||
FnAccess::Private
|
||||
crate::FnAccess::Private
|
||||
} else {
|
||||
FnAccess::Public
|
||||
crate::FnAccess::Public
|
||||
};
|
||||
|
||||
match input.next().expect(NEVER_ENDS) {
|
||||
@ -3055,7 +3051,7 @@ fn parse_fn(
|
||||
input: &mut TokenStream,
|
||||
state: &mut ParseState,
|
||||
lib: &mut FunctionsLib,
|
||||
access: FnAccess,
|
||||
access: crate::FnAccess,
|
||||
settings: ParseSettings,
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
#[cfg(feature = "metadata")]
|
||||
@ -3281,7 +3277,7 @@ fn parse_anon_fn(
|
||||
// Define the function
|
||||
let script = ScriptFnDef {
|
||||
name: fn_name.clone(),
|
||||
access: FnAccess::Public,
|
||||
access: crate::FnAccess::Public,
|
||||
params,
|
||||
body: body.into(),
|
||||
lib: None,
|
||||
|
@ -8,12 +8,6 @@ use serde::{Deserialize, Deserializer};
|
||||
use std::prelude::v1::*;
|
||||
use std::{any::type_name, fmt};
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
use crate::{Array, Blob};
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
use crate::Map;
|
||||
|
||||
/// Deserializer for [`Dynamic`][crate::Dynamic] which is kept as a reference.
|
||||
///
|
||||
/// The reference is necessary because the deserialized type may hold references
|
||||
@ -363,7 +357,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
return self
|
||||
.value
|
||||
.downcast_ref::<Blob>()
|
||||
.downcast_ref::<crate::Blob>()
|
||||
.map_or_else(|| self.type_error(), |x| _visitor.visit_bytes(x));
|
||||
|
||||
#[cfg(feature = "no_index")]
|
||||
@ -412,7 +406,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
||||
|
||||
fn deserialize_seq<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
return self.value.downcast_ref::<Array>().map_or_else(
|
||||
return self.value.downcast_ref::<crate::Array>().map_or_else(
|
||||
|| self.type_error(),
|
||||
|arr| _visitor.visit_seq(IterateDynamicArray::new(arr.iter())),
|
||||
);
|
||||
@ -440,7 +434,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
||||
|
||||
fn deserialize_map<V: Visitor<'de>>(self, _visitor: V) -> Result<V::Value, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
return self.value.downcast_ref::<Map>().map_or_else(
|
||||
return self.value.downcast_ref::<crate::Map>().map_or_else(
|
||||
|| self.type_error(),
|
||||
|map| {
|
||||
_visitor.visit_map(IterateMap::new(
|
||||
@ -473,7 +467,7 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
||||
visitor.visit_enum(s.as_str().into_deserializer())
|
||||
} else {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
if let Some(map) = self.value.downcast_ref::<Map>() {
|
||||
if let Some(map) = self.value.downcast_ref::<crate::Map>() {
|
||||
let mut iter = map.iter();
|
||||
let first = iter.next();
|
||||
let second = iter.next();
|
||||
|
@ -6,18 +6,6 @@ use std::fmt;
|
||||
#[cfg(feature = "no_std")]
|
||||
use std::prelude::v1::*;
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
use crate::Array;
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
use serde::de::SeqAccess;
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
use crate::Map;
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
use serde::de::MapAccess;
|
||||
|
||||
struct DynamicVisitor;
|
||||
|
||||
impl<'d> Visitor<'d> for DynamicVisitor {
|
||||
@ -141,8 +129,8 @@ impl<'d> Visitor<'d> for DynamicVisitor {
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
fn visit_seq<A: SeqAccess<'d>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
|
||||
let mut arr = Array::new();
|
||||
fn visit_seq<A: serde::de::SeqAccess<'d>>(self, mut seq: A) -> Result<Self::Value, A::Error> {
|
||||
let mut arr = crate::Array::new();
|
||||
|
||||
while let Some(v) = seq.next_element()? {
|
||||
arr.push(v);
|
||||
@ -152,8 +140,8 @@ impl<'d> Visitor<'d> for DynamicVisitor {
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
fn visit_map<M: MapAccess<'d>>(self, mut map: M) -> Result<Self::Value, M::Error> {
|
||||
let mut m = Map::new();
|
||||
fn visit_map<M: serde::de::MapAccess<'d>>(self, mut map: M) -> Result<Self::Value, M::Error> {
|
||||
let mut m = crate::Map::new();
|
||||
|
||||
while let Some((k, v)) = map.next_entry::<&str, _>()? {
|
||||
m.insert(k.into(), v);
|
||||
|
@ -1,8 +1,11 @@
|
||||
use crate::{Engine, AST};
|
||||
#![cfg(feature = "metadata")]
|
||||
|
||||
use crate::module::calc_native_fn_hash;
|
||||
use crate::{calc_fn_hash, Engine, AST};
|
||||
use serde::{Deserialize, Serialize};
|
||||
#[cfg(feature = "no_std")]
|
||||
use std::prelude::v1::*;
|
||||
use std::{cmp::Ordering, collections::BTreeMap};
|
||||
use std::{cmp::Ordering, collections::BTreeMap, iter::empty};
|
||||
|
||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
@ -83,6 +86,8 @@ impl Ord for FnParam {
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash, Serialize, Deserialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct FnMetadata {
|
||||
pub base_hash: u64,
|
||||
pub full_hash: u64,
|
||||
pub namespace: FnNamespace,
|
||||
pub access: FnAccess,
|
||||
pub name: String,
|
||||
@ -118,15 +123,23 @@ impl Ord for FnMetadata {
|
||||
|
||||
impl From<&crate::module::FuncInfo> for FnMetadata {
|
||||
fn from(info: &crate::module::FuncInfo) -> Self {
|
||||
let base_hash = calc_fn_hash(&info.name, info.params);
|
||||
let (typ, full_hash) = if info.func.is_script() {
|
||||
(FnType::Script, base_hash)
|
||||
} else {
|
||||
(
|
||||
FnType::Native,
|
||||
calc_native_fn_hash(empty::<&str>(), &info.name, &info.param_types),
|
||||
)
|
||||
};
|
||||
|
||||
Self {
|
||||
base_hash,
|
||||
full_hash,
|
||||
namespace: info.namespace.into(),
|
||||
access: info.access.into(),
|
||||
name: info.name.to_string(),
|
||||
typ: if info.func.is_script() {
|
||||
FnType::Script
|
||||
} else {
|
||||
FnType::Native
|
||||
},
|
||||
typ,
|
||||
num_params: info.params,
|
||||
params: info
|
||||
.param_names
|
||||
@ -169,30 +182,6 @@ impl From<&crate::module::FuncInfo> for FnMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
impl From<crate::ast::ScriptFnMetadata<'_>> for FnMetadata {
|
||||
fn from(info: crate::ast::ScriptFnMetadata) -> Self {
|
||||
Self {
|
||||
namespace: FnNamespace::Global,
|
||||
access: info.access.into(),
|
||||
name: info.name.to_string(),
|
||||
typ: FnType::Script,
|
||||
num_params: info.params.len(),
|
||||
params: info
|
||||
.params
|
||||
.iter()
|
||||
.map(|&s| FnParam {
|
||||
name: s.into(),
|
||||
typ: Some("Dynamic".into()),
|
||||
})
|
||||
.collect(),
|
||||
return_type: Some("Dynamic".into()),
|
||||
signature: info.to_string(),
|
||||
doc_comments: info.comments.iter().map(|&s| s.into()).collect(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Serialize)]
|
||||
#[serde(rename_all = "camelCase")]
|
||||
struct ModuleMetadata {
|
||||
@ -263,7 +252,8 @@ impl Engine {
|
||||
.for_each(|f| global.functions.push(f.into()));
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
_ast.iter_functions()
|
||||
_ast.shared_lib()
|
||||
.iter_fn()
|
||||
.for_each(|f| global.functions.push(f.into()));
|
||||
|
||||
global.functions.sort();
|
||||
|
@ -3,12 +3,10 @@
|
||||
|
||||
mod de;
|
||||
mod deserialize;
|
||||
mod metadata;
|
||||
mod ser;
|
||||
mod serialize;
|
||||
mod str;
|
||||
|
||||
#[cfg(feature = "metadata")]
|
||||
mod metadata;
|
||||
|
||||
pub use de::from_dynamic;
|
||||
pub use ser::to_dynamic;
|
||||
|
@ -9,12 +9,6 @@ use std::fmt;
|
||||
#[cfg(feature = "no_std")]
|
||||
use std::prelude::v1::*;
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
use crate::Array;
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
use crate::Map;
|
||||
|
||||
/// Serializer for [`Dynamic`][crate::Dynamic] which is kept as a reference.
|
||||
struct DynamicSerializer {
|
||||
/// Buffer to hold a temporary key.
|
||||
@ -332,7 +326,7 @@ impl Serializer for &mut DynamicSerializer {
|
||||
|
||||
fn serialize_seq(self, _len: Option<usize>) -> Result<Self::SerializeSeq, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
return Ok(DynamicSerializer::new(Array::new().into()));
|
||||
return Ok(DynamicSerializer::new(crate::Array::new().into()));
|
||||
#[cfg(feature = "no_index")]
|
||||
return Err(EvalAltResult::ErrorMismatchDataType(
|
||||
"".into(),
|
||||
@ -365,7 +359,7 @@ impl Serializer for &mut DynamicSerializer {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
return Ok(TupleVariantSerializer {
|
||||
variant: _variant,
|
||||
array: Array::with_capacity(_len),
|
||||
array: crate::Array::with_capacity(_len),
|
||||
});
|
||||
#[cfg(any(feature = "no_object", feature = "no_index"))]
|
||||
return Err(EvalAltResult::ErrorMismatchDataType(
|
||||
@ -378,7 +372,7 @@ impl Serializer for &mut DynamicSerializer {
|
||||
|
||||
fn serialize_map(self, _len: Option<usize>) -> Result<Self::SerializeMap, Box<EvalAltResult>> {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
return Ok(DynamicSerializer::new(Map::new().into()));
|
||||
return Ok(DynamicSerializer::new(crate::Map::new().into()));
|
||||
#[cfg(feature = "no_object")]
|
||||
return Err(EvalAltResult::ErrorMismatchDataType(
|
||||
"".into(),
|
||||
@ -406,7 +400,7 @@ impl Serializer for &mut DynamicSerializer {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
return Ok(StructVariantSerializer {
|
||||
variant: _variant,
|
||||
map: Map::new(),
|
||||
map: crate::Map::new(),
|
||||
});
|
||||
#[cfg(feature = "no_object")]
|
||||
return Err(EvalAltResult::ErrorMismatchDataType(
|
||||
@ -429,7 +423,7 @@ impl SerializeSeq for DynamicSerializer {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
{
|
||||
let _value = _value.serialize(&mut *self)?;
|
||||
let arr = self._value.downcast_mut::<Array>().unwrap();
|
||||
let arr = self._value.downcast_mut::<crate::Array>().unwrap();
|
||||
arr.push(_value);
|
||||
Ok(())
|
||||
}
|
||||
@ -467,7 +461,7 @@ impl SerializeTuple for DynamicSerializer {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
{
|
||||
let _value = _value.serialize(&mut *self)?;
|
||||
let arr = self._value.downcast_mut::<Array>().unwrap();
|
||||
let arr = self._value.downcast_mut::<crate::Array>().unwrap();
|
||||
arr.push(_value);
|
||||
Ok(())
|
||||
}
|
||||
@ -504,7 +498,7 @@ impl SerializeTupleStruct for DynamicSerializer {
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
{
|
||||
let _value = _value.serialize(&mut *self)?;
|
||||
let arr = self._value.downcast_mut::<Array>().unwrap();
|
||||
let arr = self._value.downcast_mut::<crate::Array>().unwrap();
|
||||
arr.push(_value);
|
||||
Ok(())
|
||||
}
|
||||
@ -565,7 +559,7 @@ impl SerializeMap for DynamicSerializer {
|
||||
)
|
||||
})?;
|
||||
let _value = _value.serialize(&mut *self)?;
|
||||
let map = self._value.downcast_mut::<Map>().unwrap();
|
||||
let map = self._value.downcast_mut::<crate::Map>().unwrap();
|
||||
map.insert(key.into(), _value);
|
||||
Ok(())
|
||||
}
|
||||
@ -590,7 +584,7 @@ impl SerializeMap for DynamicSerializer {
|
||||
EvalAltResult::ErrorMismatchDataType("string".into(), typ.into(), Position::NONE)
|
||||
})?;
|
||||
let _value = _value.serialize(&mut *self)?;
|
||||
let map = self._value.downcast_mut::<Map>().unwrap();
|
||||
let map = self._value.downcast_mut::<crate::Map>().unwrap();
|
||||
map.insert(_key.into(), _value);
|
||||
Ok(())
|
||||
}
|
||||
@ -628,7 +622,7 @@ impl SerializeStruct for DynamicSerializer {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
{
|
||||
let _value = _value.serialize(&mut *self)?;
|
||||
let map = self._value.downcast_mut::<Map>().unwrap();
|
||||
let map = self._value.downcast_mut::<crate::Map>().unwrap();
|
||||
map.insert(_key.into(), _value);
|
||||
Ok(())
|
||||
}
|
||||
@ -657,7 +651,7 @@ impl SerializeStruct for DynamicSerializer {
|
||||
#[cfg(not(any(feature = "no_object", feature = "no_index")))]
|
||||
struct TupleVariantSerializer {
|
||||
variant: &'static str,
|
||||
array: Array,
|
||||
array: crate::Array,
|
||||
}
|
||||
|
||||
#[cfg(not(any(feature = "no_object", feature = "no_index")))]
|
||||
@ -682,7 +676,7 @@ impl serde::ser::SerializeTupleVariant for TupleVariantSerializer {
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
struct StructVariantSerializer {
|
||||
variant: &'static str,
|
||||
map: Map,
|
||||
map: crate::Map,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
@ -707,7 +701,7 @@ impl serde::ser::SerializeStructVariant for StructVariantSerializer {
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
fn make_variant(variant: &'static str, value: Dynamic) -> RhaiResult {
|
||||
let mut map = Map::new();
|
||||
let mut map = crate::Map::new();
|
||||
map.insert(variant.into(), value);
|
||||
Ok(map.into())
|
||||
}
|
||||
|
@ -19,15 +19,6 @@ use std::{
|
||||
str::{Chars, FromStr},
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
use crate::{ast::FloatWrapper, FLOAT};
|
||||
|
||||
#[cfg(feature = "decimal")]
|
||||
use rust_decimal::Decimal;
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
use crate::engine::KEYWORD_IS_DEF_FN;
|
||||
|
||||
/// _(internals)_ A type containing commands to control the tokenizer.
|
||||
#[derive(Debug, Clone, Eq, PartialEq, Hash, Copy)]
|
||||
pub struct TokenizerControlBlock {
|
||||
@ -305,12 +296,12 @@ pub enum Token {
|
||||
///
|
||||
/// Reserved under the `no_float` feature.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
FloatConstant(FloatWrapper<FLOAT>),
|
||||
/// A [`Decimal`] constant.
|
||||
FloatConstant(crate::ast::FloatWrapper<crate::FLOAT>),
|
||||
/// A [`Decimal`][rust_decimal::Decimal] constant.
|
||||
///
|
||||
/// Requires the `decimal` feature.
|
||||
#[cfg(feature = "decimal")]
|
||||
DecimalConstant(Decimal),
|
||||
DecimalConstant(rust_decimal::Decimal),
|
||||
/// An identifier.
|
||||
Identifier(Box<str>),
|
||||
/// A character constant.
|
||||
@ -789,7 +780,7 @@ impl Token {
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
KEYWORD_IS_DEF_FN => Reserved(syntax.into()),
|
||||
crate::engine::KEYWORD_IS_DEF_FN => Reserved(syntax.into()),
|
||||
|
||||
_ => return None,
|
||||
})
|
||||
@ -1184,6 +1175,15 @@ pub fn parse_string_literal(
|
||||
result.push(next_char)
|
||||
}
|
||||
|
||||
// Double wrapper
|
||||
_ if termination_char == next_char
|
||||
&& escape.is_empty()
|
||||
&& stream.peek_next().map_or(false, |c| c == termination_char) =>
|
||||
{
|
||||
eat_next(stream, pos);
|
||||
result.push(termination_char)
|
||||
}
|
||||
|
||||
// Close wrapper
|
||||
_ if termination_char == next_char && escape.is_empty() => {
|
||||
state.is_within_text_terminated_by = None;
|
||||
@ -1534,18 +1534,20 @@ fn get_next_token_inner(
|
||||
|
||||
// If integer parsing is unnecessary, try float instead
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
let num =
|
||||
num.or_else(|_| FloatWrapper::from_str(&out).map(Token::FloatConstant));
|
||||
let num = num.or_else(|_| {
|
||||
crate::ast::FloatWrapper::from_str(&out).map(Token::FloatConstant)
|
||||
});
|
||||
|
||||
// Then try decimal
|
||||
#[cfg(feature = "decimal")]
|
||||
let num =
|
||||
num.or_else(|_| Decimal::from_str(&out).map(Token::DecimalConstant));
|
||||
let num = num.or_else(|_| {
|
||||
rust_decimal::Decimal::from_str(&out).map(Token::DecimalConstant)
|
||||
});
|
||||
|
||||
// Then try decimal in scientific notation
|
||||
#[cfg(feature = "decimal")]
|
||||
let num = num.or_else(|_| {
|
||||
Decimal::from_scientific(&out).map(Token::DecimalConstant)
|
||||
rust_decimal::Decimal::from_scientific(&out).map(Token::DecimalConstant)
|
||||
});
|
||||
|
||||
num.unwrap_or_else(|_| {
|
||||
@ -1990,7 +1992,7 @@ pub fn is_keyword_function(name: impl AsRef<str>) -> bool {
|
||||
| KEYWORD_FN_PTR_CALL | KEYWORD_FN_PTR_CURRY | KEYWORD_IS_DEF_VAR => true,
|
||||
|
||||
#[cfg(not(feature = "no_function"))]
|
||||
KEYWORD_IS_DEF_FN => true,
|
||||
crate::engine::KEYWORD_IS_DEF_FN => true,
|
||||
|
||||
_ => false,
|
||||
}
|
||||
@ -2221,10 +2223,9 @@ impl<'a> Iterator for TokenIterator<'a> {
|
||||
};
|
||||
|
||||
// Run the mapper, if any
|
||||
let token = if let Some(map_func) = self.token_mapper {
|
||||
map_func(token, pos, &self.state)
|
||||
} else {
|
||||
token
|
||||
let token = match self.token_mapper {
|
||||
Some(map_func) => map_func(token, pos, &self.state),
|
||||
None => token,
|
||||
};
|
||||
|
||||
Some((token, pos))
|
||||
|
@ -13,23 +13,10 @@ use std::{
|
||||
str::FromStr,
|
||||
};
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
use crate::{ast::FloatWrapper, FLOAT};
|
||||
|
||||
#[cfg(feature = "decimal")]
|
||||
use rust_decimal::Decimal;
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
use crate::{Array, Blob};
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
use crate::Map;
|
||||
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
#[cfg(not(any(target_arch = "wasm32", target_arch = "wasm64")))]
|
||||
use std::time::Instant;
|
||||
|
||||
use fmt::Debug;
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
#[cfg(any(target_arch = "wasm32", target_arch = "wasm64"))]
|
||||
use instant::Instant;
|
||||
@ -190,26 +177,26 @@ pub enum Union {
|
||||
///
|
||||
/// Not available under `no_float`.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
Float(FloatWrapper<FLOAT>, Tag, AccessMode),
|
||||
Float(crate::ast::FloatWrapper<crate::FLOAT>, Tag, AccessMode),
|
||||
/// _(decimal)_ A fixed-precision decimal value.
|
||||
/// Exported under the `decimal` feature only.
|
||||
#[cfg(feature = "decimal")]
|
||||
Decimal(Box<Decimal>, Tag, AccessMode),
|
||||
Decimal(Box<rust_decimal::Decimal>, Tag, AccessMode),
|
||||
/// An array value.
|
||||
///
|
||||
/// Not available under `no_index`.
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Array(Box<Array>, Tag, AccessMode),
|
||||
Array(Box<crate::Array>, Tag, AccessMode),
|
||||
/// An blob (byte array).
|
||||
///
|
||||
/// Not available under `no_index`.
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Blob(Box<Blob>, Tag, AccessMode),
|
||||
Blob(Box<crate::Blob>, Tag, AccessMode),
|
||||
/// An object map value.
|
||||
///
|
||||
/// Not available under `no_object`.
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Map(Box<Map>, Tag, AccessMode),
|
||||
Map(Box<crate::Map>, Tag, AccessMode),
|
||||
/// A function pointer.
|
||||
FnPtr(Box<FnPtr>, Tag, AccessMode),
|
||||
/// A timestamp value.
|
||||
@ -411,15 +398,15 @@ impl Dynamic {
|
||||
Union::Char(_, _, _) => TypeId::of::<char>(),
|
||||
Union::Int(_, _, _) => TypeId::of::<INT>(),
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
Union::Float(_, _, _) => TypeId::of::<FLOAT>(),
|
||||
Union::Float(_, _, _) => TypeId::of::<crate::FLOAT>(),
|
||||
#[cfg(feature = "decimal")]
|
||||
Union::Decimal(_, _, _) => TypeId::of::<Decimal>(),
|
||||
Union::Decimal(_, _, _) => TypeId::of::<rust_decimal::Decimal>(),
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Union::Array(_, _, _) => TypeId::of::<Array>(),
|
||||
Union::Array(_, _, _) => TypeId::of::<crate::Array>(),
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
Union::Blob(_, _, _) => TypeId::of::<Blob>(),
|
||||
Union::Blob(_, _, _) => TypeId::of::<crate::Blob>(),
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
Union::Map(_, _, _) => TypeId::of::<Map>(),
|
||||
Union::Map(_, _, _) => TypeId::of::<crate::Map>(),
|
||||
Union::FnPtr(_, _, _) => TypeId::of::<FnPtr>(),
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
Union::TimeStamp(_, _, _) => TypeId::of::<Instant>(),
|
||||
@ -450,7 +437,7 @@ impl Dynamic {
|
||||
Union::Char(_, _, _) => "char",
|
||||
Union::Int(_, _, _) => type_name::<INT>(),
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
Union::Float(_, _, _) => type_name::<FLOAT>(),
|
||||
Union::Float(_, _, _) => type_name::<crate::FLOAT>(),
|
||||
#[cfg(feature = "decimal")]
|
||||
Union::Decimal(_, _, _) => "decimal",
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
@ -582,19 +569,19 @@ pub(crate) fn map_std_type_name(name: &str) -> &str {
|
||||
return "Fn";
|
||||
}
|
||||
#[cfg(feature = "decimal")]
|
||||
if name == type_name::<Decimal>() {
|
||||
if name == type_name::<rust_decimal::Decimal>() {
|
||||
return "decimal";
|
||||
}
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
if name == type_name::<Array>() {
|
||||
if name == type_name::<crate::Array>() {
|
||||
return "array";
|
||||
}
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
if name == type_name::<Blob>() {
|
||||
if name == type_name::<crate::Blob>() {
|
||||
return "blob";
|
||||
}
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
if name == type_name::<Map>() {
|
||||
if name == type_name::<crate::Map>() {
|
||||
return "map";
|
||||
}
|
||||
#[cfg(not(feature = "no_std"))]
|
||||
@ -939,14 +926,14 @@ impl Dynamic {
|
||||
pub const fn from_char(value: char) -> Self {
|
||||
Self(Union::Char(value, DEFAULT_TAG_VALUE, ReadWrite))
|
||||
}
|
||||
/// Create a new [`Dynamic`] from a [`FLOAT`].
|
||||
/// Create a new [`Dynamic`] from a [`FLOAT`][crate::FLOAT].
|
||||
///
|
||||
/// Not available under `no_float`.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
#[inline(always)]
|
||||
pub const fn from_float(value: FLOAT) -> Self {
|
||||
pub const fn from_float(value: crate::FLOAT) -> Self {
|
||||
Self(Union::Float(
|
||||
FloatWrapper::new_const(value),
|
||||
crate::ast::FloatWrapper::new_const(value),
|
||||
DEFAULT_TAG_VALUE,
|
||||
ReadWrite,
|
||||
))
|
||||
@ -956,7 +943,7 @@ impl Dynamic {
|
||||
/// Exported under the `decimal` feature only.
|
||||
#[cfg(feature = "decimal")]
|
||||
#[inline(always)]
|
||||
pub fn from_decimal(value: Decimal) -> Self {
|
||||
pub fn from_decimal(value: rust_decimal::Decimal) -> Self {
|
||||
Self(Union::Decimal(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
|
||||
}
|
||||
/// Create a new [`Dynamic`] from an [`Instant`].
|
||||
@ -1104,12 +1091,12 @@ impl Dynamic {
|
||||
///
|
||||
/// # Notes
|
||||
///
|
||||
/// Beware that you need to pass in an [`Array`] type for it to be recognized as an [`Array`].
|
||||
/// A [`Vec<T>`][Vec] does not get automatically converted to an [`Array`], but will be a generic
|
||||
/// Beware that you need to pass in an [`Array`][crate::Array] type for it to be recognized as an [`Array`][crate::Array].
|
||||
/// A [`Vec<T>`][Vec] does not get automatically converted to an [`Array`][crate::Array], but will be a generic
|
||||
/// restricted trait object instead, because [`Vec<T>`][Vec] is not a supported standard type.
|
||||
///
|
||||
/// Similarly, passing in a [`HashMap<String, T>`][std::collections::HashMap] or
|
||||
/// [`BTreeMap<String, T>`][std::collections::BTreeMap] will not get a [`Map`] but a trait object.
|
||||
/// [`BTreeMap<String, T>`][std::collections::BTreeMap] will not get a [`Map`][crate::Map] but a trait object.
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
@ -1143,12 +1130,12 @@ impl Dynamic {
|
||||
return (*val.downcast_ref::<INT>().expect(CHECKED)).into();
|
||||
}
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<FLOAT>() {
|
||||
return (*val.downcast_ref::<FLOAT>().expect(CHECKED)).into();
|
||||
if TypeId::of::<T>() == TypeId::of::<crate::FLOAT>() {
|
||||
return (*val.downcast_ref::<crate::FLOAT>().expect(CHECKED)).into();
|
||||
}
|
||||
#[cfg(feature = "decimal")]
|
||||
if TypeId::of::<T>() == TypeId::of::<Decimal>() {
|
||||
return (*val.downcast_ref::<Decimal>().expect(CHECKED)).into();
|
||||
if TypeId::of::<T>() == TypeId::of::<rust_decimal::Decimal>() {
|
||||
return (*val.downcast_ref::<rust_decimal::Decimal>().expect(CHECKED)).into();
|
||||
}
|
||||
if TypeId::of::<T>() == TypeId::of::<bool>() {
|
||||
return (*val.downcast_ref::<bool>().expect(CHECKED)).into();
|
||||
@ -1176,14 +1163,14 @@ impl Dynamic {
|
||||
};
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
{
|
||||
value = match unsafe_try_cast::<_, Array>(value) {
|
||||
value = match unsafe_try_cast::<_, crate::Array>(value) {
|
||||
Ok(array) => return array.into(),
|
||||
Err(value) => value,
|
||||
};
|
||||
}
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
{
|
||||
value = match unsafe_try_cast::<_, Blob>(value) {
|
||||
value = match unsafe_try_cast::<_, crate::Blob>(value) {
|
||||
Ok(blob) => return Self(Union::Blob(Box::new(blob), DEFAULT_TAG_VALUE, ReadWrite)),
|
||||
Err(value) => value,
|
||||
};
|
||||
@ -1191,7 +1178,7 @@ impl Dynamic {
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
{
|
||||
value = match unsafe_try_cast::<_, Map>(value) {
|
||||
value = match unsafe_try_cast::<_, crate::Map>(value) {
|
||||
Ok(map) => return map.into(),
|
||||
Err(value) => value,
|
||||
};
|
||||
@ -1298,7 +1285,7 @@ impl Dynamic {
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<FLOAT>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<crate::FLOAT>() {
|
||||
return match self.0 {
|
||||
Union::Float(value, _, _) => unsafe_try_cast(*value).ok(),
|
||||
_ => None,
|
||||
@ -1306,7 +1293,7 @@ impl Dynamic {
|
||||
}
|
||||
|
||||
#[cfg(feature = "decimal")]
|
||||
if TypeId::of::<T>() == TypeId::of::<Decimal>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<rust_decimal::Decimal>() {
|
||||
return match self.0 {
|
||||
Union::Decimal(value, _, _) => unsafe_try_cast(*value).ok(),
|
||||
_ => None,
|
||||
@ -1342,7 +1329,7 @@ impl Dynamic {
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<Array>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<crate::Array>() {
|
||||
return match self.0 {
|
||||
Union::Array(value, _, _) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v),
|
||||
_ => None,
|
||||
@ -1350,7 +1337,7 @@ impl Dynamic {
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<Blob>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<crate::Blob>() {
|
||||
return match self.0 {
|
||||
Union::Blob(value, _, _) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v),
|
||||
_ => None,
|
||||
@ -1358,7 +1345,7 @@ impl Dynamic {
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<Map>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<crate::Map>() {
|
||||
return match self.0 {
|
||||
Union::Map(value, _, _) => unsafe_cast_box::<_, T>(value).ok().map(|v| *v),
|
||||
_ => None,
|
||||
@ -1652,14 +1639,14 @@ impl Dynamic {
|
||||
};
|
||||
}
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<FLOAT>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<crate::FLOAT>() {
|
||||
return match self.0 {
|
||||
Union::Float(ref value, _, _) => value.as_ref().as_any().downcast_ref::<T>(),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
#[cfg(feature = "decimal")]
|
||||
if TypeId::of::<T>() == TypeId::of::<Decimal>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<rust_decimal::Decimal>() {
|
||||
return match self.0 {
|
||||
Union::Decimal(ref value, _, _) => value.as_ref().as_any().downcast_ref::<T>(),
|
||||
_ => None,
|
||||
@ -1684,21 +1671,21 @@ impl Dynamic {
|
||||
};
|
||||
}
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<Array>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<crate::Array>() {
|
||||
return match self.0 {
|
||||
Union::Array(ref value, _, _) => value.as_ref().as_any().downcast_ref::<T>(),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<Blob>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<crate::Blob>() {
|
||||
return match self.0 {
|
||||
Union::Blob(ref value, _, _) => value.as_ref().as_any().downcast_ref::<T>(),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<Map>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<crate::Map>() {
|
||||
return match self.0 {
|
||||
Union::Map(ref value, _, _) => value.as_ref().as_any().downcast_ref::<T>(),
|
||||
_ => None,
|
||||
@ -1750,7 +1737,7 @@ impl Dynamic {
|
||||
};
|
||||
}
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<FLOAT>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<crate::FLOAT>() {
|
||||
return match self.0 {
|
||||
Union::Float(ref mut value, _, _) => {
|
||||
value.as_mut().as_mut_any().downcast_mut::<T>()
|
||||
@ -1759,7 +1746,7 @@ impl Dynamic {
|
||||
};
|
||||
}
|
||||
#[cfg(feature = "decimal")]
|
||||
if TypeId::of::<T>() == TypeId::of::<Decimal>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<rust_decimal::Decimal>() {
|
||||
return match self.0 {
|
||||
Union::Decimal(ref mut value, _, _) => {
|
||||
value.as_mut().as_mut_any().downcast_mut::<T>()
|
||||
@ -1786,7 +1773,7 @@ impl Dynamic {
|
||||
};
|
||||
}
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<Array>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<crate::Array>() {
|
||||
return match self.0 {
|
||||
Union::Array(ref mut value, _, _) => {
|
||||
value.as_mut().as_mut_any().downcast_mut::<T>()
|
||||
@ -1795,14 +1782,14 @@ impl Dynamic {
|
||||
};
|
||||
}
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<Blob>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<crate::Blob>() {
|
||||
return match self.0 {
|
||||
Union::Blob(ref mut value, _, _) => value.as_mut().as_mut_any().downcast_mut::<T>(),
|
||||
_ => None,
|
||||
};
|
||||
}
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
if TypeId::of::<T>() == TypeId::of::<Map>() {
|
||||
if TypeId::of::<T>() == TypeId::of::<crate::Map>() {
|
||||
return match self.0 {
|
||||
Union::Map(ref mut value, _, _) => value.as_mut().as_mut_any().downcast_mut::<T>(),
|
||||
_ => None,
|
||||
@ -1864,13 +1851,13 @@ impl Dynamic {
|
||||
_ => Err(self.type_name()),
|
||||
}
|
||||
}
|
||||
/// Cast the [`Dynamic`] as the system floating-point type [`FLOAT`].
|
||||
/// Cast the [`Dynamic`] as the system floating-point type [`FLOAT`][crate::FLOAT].
|
||||
/// Returns the name of the actual type if the cast fails.
|
||||
///
|
||||
/// Not available under `no_float`.
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
#[inline]
|
||||
pub fn as_float(&self) -> Result<FLOAT, &'static str> {
|
||||
pub fn as_float(&self) -> Result<crate::FLOAT, &'static str> {
|
||||
match self.0 {
|
||||
Union::Float(n, _, _) => Ok(*n),
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
@ -1878,13 +1865,13 @@ impl Dynamic {
|
||||
_ => Err(self.type_name()),
|
||||
}
|
||||
}
|
||||
/// _(decimal)_ Cast the [`Dynamic`] as a [`Decimal`](https://docs.rs/rust_decimal).
|
||||
/// _(decimal)_ Cast the [`Dynamic`] as a [`Decimal`][rust_decimal::Decimal].
|
||||
/// Returns the name of the actual type if the cast fails.
|
||||
///
|
||||
/// Exported under the `decimal` feature only.
|
||||
#[cfg(feature = "decimal")]
|
||||
#[inline]
|
||||
pub fn as_decimal(&self) -> Result<Decimal, &'static str> {
|
||||
pub fn as_decimal(&self) -> Result<rust_decimal::Decimal, &'static str> {
|
||||
match self.0 {
|
||||
Union::Decimal(ref n, _, _) => Ok(**n),
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
@ -1979,23 +1966,23 @@ impl From<INT> for Dynamic {
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl From<FLOAT> for Dynamic {
|
||||
impl From<crate::FLOAT> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: FLOAT) -> Self {
|
||||
fn from(value: crate::FLOAT) -> Self {
|
||||
Self(Union::Float(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
|
||||
}
|
||||
}
|
||||
#[cfg(not(feature = "no_float"))]
|
||||
impl From<FloatWrapper<FLOAT>> for Dynamic {
|
||||
impl From<crate::ast::FloatWrapper<crate::FLOAT>> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: FloatWrapper<FLOAT>) -> Self {
|
||||
fn from(value: crate::ast::FloatWrapper<crate::FLOAT>) -> Self {
|
||||
Self(Union::Float(value, DEFAULT_TAG_VALUE, ReadWrite))
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "decimal")]
|
||||
impl From<Decimal> for Dynamic {
|
||||
impl From<rust_decimal::Decimal> for Dynamic {
|
||||
#[inline(always)]
|
||||
fn from(value: Decimal) -> Self {
|
||||
fn from(value: rust_decimal::Decimal) -> Self {
|
||||
Self(Union::Decimal(value.into(), DEFAULT_TAG_VALUE, ReadWrite))
|
||||
}
|
||||
}
|
||||
@ -2026,9 +2013,9 @@ impl FromStr for Dynamic {
|
||||
}
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
impl Dynamic {
|
||||
/// Create a [`Dynamic`] from an [`Array`].
|
||||
/// Create a [`Dynamic`] from an [`Array`][crate::Array].
|
||||
#[inline(always)]
|
||||
pub(crate) fn from_array(array: Array) -> Self {
|
||||
pub(crate) fn from_array(array: crate::Array) -> Self {
|
||||
Self(Union::Array(array.into(), DEFAULT_TAG_VALUE, ReadWrite))
|
||||
}
|
||||
}
|
||||
@ -2067,10 +2054,10 @@ impl<T: Variant + Clone> std::iter::FromIterator<T> for Dynamic {
|
||||
}
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
impl Dynamic {
|
||||
/// Convert the [`Dynamic`] into an [`Array`].
|
||||
/// Convert the [`Dynamic`] into an [`Array`][crate::Array].
|
||||
/// Returns the name of the actual type if the cast fails.
|
||||
#[inline(always)]
|
||||
pub fn into_array(self) -> Result<Array, &'static str> {
|
||||
pub fn into_array(self) -> Result<crate::Array, &'static str> {
|
||||
match self.0 {
|
||||
Union::Array(a, _, _) => Ok(*a),
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
@ -2148,13 +2135,13 @@ impl Dynamic {
|
||||
impl Dynamic {
|
||||
/// Create a [`Dynamic`] from a [`Vec<u8>`].
|
||||
#[inline(always)]
|
||||
pub fn from_blob(blob: Blob) -> Self {
|
||||
pub fn from_blob(blob: crate::Blob) -> Self {
|
||||
Self(Union::Blob(Box::new(blob), DEFAULT_TAG_VALUE, ReadWrite))
|
||||
}
|
||||
/// Convert the [`Dynamic`] into a [`Vec<u8>`].
|
||||
/// Returns the name of the actual type if the cast fails.
|
||||
#[inline(always)]
|
||||
pub fn into_blob(self) -> Result<Blob, &'static str> {
|
||||
pub fn into_blob(self) -> Result<crate::Blob, &'static str> {
|
||||
match self.0 {
|
||||
Union::Blob(a, _, _) => Ok(*a),
|
||||
#[cfg(not(feature = "no_closure"))]
|
||||
@ -2175,9 +2162,9 @@ impl Dynamic {
|
||||
}
|
||||
#[cfg(not(feature = "no_object"))]
|
||||
impl Dynamic {
|
||||
/// Create a [`Dynamic`] from a [`Map`].
|
||||
/// Create a [`Dynamic`] from a [`Map`][crate::Map].
|
||||
#[inline(always)]
|
||||
pub(crate) fn from_map(map: Map) -> Self {
|
||||
pub(crate) fn from_map(map: crate::Map) -> Self {
|
||||
Self(Union::Map(map.into(), DEFAULT_TAG_VALUE, ReadWrite))
|
||||
}
|
||||
}
|
||||
|
@ -16,8 +16,7 @@ use std::{
|
||||
|
||||
/// The system immutable string type.
|
||||
///
|
||||
/// An [`ImmutableString`] wraps an [`Rc`][std::rc::Rc]`<`[`SmartString`][smartstring::SmartString]`>`
|
||||
/// (or [`Arc`][std::sync::Arc]`<`[`SmartString`][smartstring::SmartString]`>` under the `sync` feature)
|
||||
/// An [`ImmutableString`] wraps an `Rc<SmartString>` (or `Arc<SmartString>` under the `sync` feature)
|
||||
/// so that it can be simply shared and not cloned.
|
||||
///
|
||||
/// # Example
|
||||
|
136
tests/blobs.rs
136
tests/blobs.rs
@ -63,6 +63,142 @@ fn test_blobs() -> Result<(), Box<EvalAltResult>> {
|
||||
engine.eval_with_scope::<Blob>(&mut orig_scope.clone(), "x + x")?,
|
||||
[1, 2, 3, 1, 2, 3]
|
||||
);
|
||||
assert_eq!(
|
||||
engine.eval_with_scope::<Blob>(&mut orig_scope.clone(), "x += 999; x")?,
|
||||
[1, 2, 3, 0xe7]
|
||||
);
|
||||
assert_eq!(
|
||||
engine.eval_with_scope::<Blob>(&mut orig_scope.clone(), "x[2] = 999; x")?,
|
||||
[1, 2, 0xe7]
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "only_i32"))]
|
||||
#[test]
|
||||
fn test_blobs_parse() -> Result<(), Box<EvalAltResult>> {
|
||||
let engine = Engine::new();
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } parse_le_int(x,2,0)"
|
||||
)?,
|
||||
0
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } parse_le_int(x,2,9)"
|
||||
)?,
|
||||
0x0908070605040302
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } parse_be_int(x,2,10)"
|
||||
)?,
|
||||
0x0203040506070809
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } parse_le_int(x,-5,99)"
|
||||
)?,
|
||||
0x0f0e0d0c0b
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } parse_le_int(x,-5,2)"
|
||||
)?,
|
||||
0x0c0b
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } parse_le_int(x,-99,99)"
|
||||
)?,
|
||||
0x0706050403020100
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } write_be(x, 3, 3, -98765432); parse_be_int(x, 3, 3)"
|
||||
)?,
|
||||
0xffffff0000000000_u64 as INT
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } write_le(x, 3, 3, -98765432); parse_le_int(x, 3, 3)"
|
||||
)?,
|
||||
0x1cf588
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[cfg(feature = "only_i32")]
|
||||
#[test]
|
||||
fn test_blobs_parse() -> Result<(), Box<EvalAltResult>> {
|
||||
let engine = Engine::new();
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } parse_le_int(x,2,0)"
|
||||
)?,
|
||||
0
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } parse_le_int(x,2,9)"
|
||||
)?,
|
||||
0x05040302
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } parse_be_int(x,2,10)"
|
||||
)?,
|
||||
0x02030405
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } parse_le_int(x,-5,99)"
|
||||
)?,
|
||||
0x0e0d0c0b
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } parse_le_int(x,-5,2)"
|
||||
)?,
|
||||
0x0c0b
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } parse_le_int(x,-99,99)"
|
||||
)?,
|
||||
0x03020100
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } write_be(x, 3, 3, -98765432); parse_be_int(x, 3, 3)"
|
||||
)?,
|
||||
0xfa1cf500_u32 as INT
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
engine.eval::<INT>(
|
||||
"let x = blob(16, 0); for n in range(0, 16) { x[n] = n; } write_le(x, 3, 3, -98765432); parse_le_int(x, 3, 3)"
|
||||
)?,
|
||||
0x1cf588
|
||||
);
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -8,6 +8,10 @@ fn test_string() -> Result<(), Box<EvalAltResult>> {
|
||||
engine.eval::<String>(r#""Test string: \u2764""#)?,
|
||||
"Test string: ❤"
|
||||
);
|
||||
assert_eq!(
|
||||
engine.eval::<String>(r#""Test string: ""\u2764""""#)?,
|
||||
r#"Test string: "❤""#
|
||||
);
|
||||
assert_eq!(
|
||||
engine.eval::<String>("\"Test\rstring: \\u2764\"")?,
|
||||
"Test\rstring: ❤"
|
||||
@ -24,6 +28,10 @@ fn test_string() -> Result<(), Box<EvalAltResult>> {
|
||||
engine.eval::<String>(" `Test string: \\u2764\nhello,\\nworld!`")?,
|
||||
"Test string: \\u2764\nhello,\\nworld!"
|
||||
);
|
||||
assert_eq!(
|
||||
engine.eval::<String>(r#" `Test string: \\u2764\n``hello``,\\n"world"!`"#)?,
|
||||
r#"Test string: \\u2764\n`hello`,\\n"world"!"#
|
||||
);
|
||||
assert_eq!(
|
||||
engine.eval::<String>(" `\nTest string: \\u2764\nhello,\\nworld!`")?,
|
||||
"Test string: \\u2764\nhello,\\nworld!"
|
||||
|
Loading…
Reference in New Issue
Block a user