Skip to content

Commit

Permalink
Merge pull request #497 from schungx/master
Browse files Browse the repository at this point in the history
Version 1.3
  • Loading branch information
schungx committed Dec 12, 2021
2 parents 15abbbb + 5eaf852 commit aa9b488
Show file tree
Hide file tree
Showing 30 changed files with 794 additions and 502 deletions.
22 changes: 10 additions & 12 deletions CHANGELOG.md
Expand Up @@ -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`
Expand All @@ -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
--------------------------
Expand All @@ -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
=============

Expand Down
3 changes: 2 additions & 1 deletion README.md
Expand Up @@ -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).

Expand Down
9 changes: 3 additions & 6 deletions src/api/compile.rs
Expand Up @@ -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.
///
Expand Down Expand Up @@ -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.
///
Expand Down Expand Up @@ -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()) {
Expand Down
1 change: 0 additions & 1 deletion src/api/deprecated.rs
Expand Up @@ -4,7 +4,6 @@ use crate::{
Dynamic, Engine, EvalAltResult, FnPtr, ImmutableString, NativeCallContext, RhaiResult, Scope,
AST,
};

#[cfg(feature = "no_std")]
use std::prelude::v1::*;

Expand Down
3 changes: 1 addition & 2 deletions src/api/limits.rs
Expand Up @@ -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`.
Expand Down
12 changes: 6 additions & 6 deletions src/api/mod.rs
Expand Up @@ -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.
///
Expand All @@ -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(())
Expand Down
54 changes: 32 additions & 22 deletions src/api/register.rs
Expand Up @@ -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)]
Expand Down Expand Up @@ -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()`
Expand Down Expand Up @@ -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`].
Expand Down Expand Up @@ -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.
///
Expand Down Expand Up @@ -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>()
Expand All @@ -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.
///
Expand Down Expand Up @@ -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>()
Expand All @@ -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.
///
Expand Down Expand Up @@ -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>()
Expand All @@ -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.
///
Expand Down Expand Up @@ -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>()
Expand All @@ -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.
///
Expand Down

0 comments on commit aa9b488

Please sign in to comment.