Refine code and docs.
This commit is contained in:
parent
f74d947c6b
commit
32f41c69bd
@ -19,6 +19,10 @@ Breaking changes
|
|||||||
----------------
|
----------------
|
||||||
|
|
||||||
* Custom syntax can no longer start with a keyword (even a _reserved_ one), even if it has been disabled. That is to avoid breaking scripts later when the keyword is no longer disabled.
|
* Custom syntax can no longer start with a keyword (even a _reserved_ one), even if it has been disabled. That is to avoid breaking scripts later when the keyword is no longer disabled.
|
||||||
|
|
||||||
|
Changes to Error Handling
|
||||||
|
------------------------
|
||||||
|
|
||||||
* `EvalAltResult::ErrorAssignmentToUnknownLHS` is moved to `ParseError::AssignmentToInvalidLHS`. `ParseError::AssignmentToCopy` is removed.
|
* `EvalAltResult::ErrorAssignmentToUnknownLHS` is moved to `ParseError::AssignmentToInvalidLHS`. `ParseError::AssignmentToCopy` is removed.
|
||||||
* `EvalAltResult::ErrorDataTooLarge` is simplified.
|
* `EvalAltResult::ErrorDataTooLarge` is simplified.
|
||||||
* `Engine::on_progress` closure signature now returns `Option<Dynamic>` with the termination value passed on to `EvalAltResult::ErrorTerminated`.
|
* `Engine::on_progress` closure signature now returns `Option<Dynamic>` with the termination value passed on to `EvalAltResult::ErrorTerminated`.
|
||||||
@ -30,11 +34,13 @@ New features
|
|||||||
* `f32_float` feature to set `FLOAT` to `f32`.
|
* `f32_float` feature to set `FLOAT` to `f32`.
|
||||||
* Low-level API for custom syntax allowing more flexibility in designing the syntax.
|
* Low-level API for custom syntax allowing more flexibility in designing the syntax.
|
||||||
* `Module::fill_with` to poly-fill a module with another.
|
* `Module::fill_with` to poly-fill a module with another.
|
||||||
|
* Scripts terminated via `Engine::on_progress` can now pass on a value as a termination token.
|
||||||
|
|
||||||
Enhancements
|
Enhancements
|
||||||
------------
|
------------
|
||||||
|
|
||||||
* Essential AST structures like `Expr` and `Stmt` are packed into smaller sizes (16 bytes and 32 bytes on 64-bit), stored inline for more cache friendliness, and de-`Box`ed as much as possible.
|
* Essential AST structures like `Expr` and `Stmt` are packed into smaller sizes (16 bytes and 32 bytes on 64-bit), stored inline for more cache friendliness, and de-`Box`ed as much as possible.
|
||||||
|
* `Scope` is optimized for cache friendliness.
|
||||||
|
|
||||||
|
|
||||||
Version 0.19.3
|
Version 0.19.3
|
||||||
|
@ -24,7 +24,21 @@ engine.on_progress(|&count| { // parameter is '&u64' - number of operations al
|
|||||||
|
|
||||||
The closure passed to `Engine::on_progress` will be called once for every operation.
|
The closure passed to `Engine::on_progress` will be called once for every operation.
|
||||||
Return `Some(token)` to terminate the script immediately, with the provided value
|
Return `Some(token)` to terminate the script immediately, with the provided value
|
||||||
(any [`Dynamic`] value) passed to `EvalAltResult::ErrorTerminated` as a termination token.
|
(any [`Dynamic`]) acting as a termination token.
|
||||||
|
|
||||||
|
|
||||||
|
Termination Token
|
||||||
|
-----------------
|
||||||
|
|
||||||
|
The [`Dynamic`] value returned by the closure for `Engine::on_progress` is a _termination token_.
|
||||||
|
A script that is manually terminated returns with `Err(EvalAltResult::ErrorTerminated)`
|
||||||
|
wrapping this value.
|
||||||
|
|
||||||
|
The termination token is commonly used to provide information on the _reason_ or _source_
|
||||||
|
behind the termination decision.
|
||||||
|
|
||||||
|
If the termination token is not needed, simply return `Some(().into())` to terminate the script
|
||||||
|
run with [`()`] as the token.
|
||||||
|
|
||||||
|
|
||||||
Operations Count vs. Progress Percentage
|
Operations Count vs. Progress Percentage
|
||||||
|
@ -29,8 +29,9 @@ due to 64-bit arithmetic requiring more CPU cycles to complete.
|
|||||||
Minimize Size of `Dynamic`
|
Minimize Size of `Dynamic`
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|
||||||
Turning on [`no_float`] and [`only_i32`] on 32-bit targets makes the critical [`Dynamic`] data type only 8 bytes long.
|
Turning on [`no_float`] or [`f32_float`] and [`only_i32`] on 32-bit targets makes the critical [`Dynamic`]
|
||||||
Normally [`Dynamic`] can be up to 16 bytes (e.g. on x86/x64 CPU's) in order to hold an `i64` or `f64`.
|
data type only 8 bytes long.
|
||||||
|
Normally [`Dynamic`] can be up to 12-16 bytes in order to hold an `i64` or `f64`.
|
||||||
|
|
||||||
A small [`Dynamic`] helps performance due to better cache efficiency.
|
A small [`Dynamic`] helps performance due to better cache efficiency.
|
||||||
|
|
||||||
|
@ -42,13 +42,14 @@ are typically used for a WASM build:
|
|||||||
| Feature | Description |
|
| Feature | Description |
|
||||||
| :-----------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
| :-----------: | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
|
||||||
| [`unchecked`] | When a WASM module panics, it doesn't crash the entire web app; however this also disables [maximum number of operations] and [progress] tracking so a script can still run indefinitely - the web app must terminate it itself. |
|
| [`unchecked`] | When a WASM module panics, it doesn't crash the entire web app; however this also disables [maximum number of operations] and [progress] tracking so a script can still run indefinitely - the web app must terminate it itself. |
|
||||||
| [`only_i32`] | JavaScript has only one `number` type and we're only supporting `wasm32` here (so far). |
|
| [`only_i32`] | WASM supports 32-bit and 64-bit integers, but most scripts will only need 32-bit. |
|
||||||
|
| [`f32_float`] | WASM supports 32-bit single-precision and 64-bit double-precision floating-point numbers, but single-precision is usually fine for most uses. |
|
||||||
| [`no_module`] | A WASM module cannot load modules from the file system, so usually this is not needed, but the savings are minimal; alternatively, a custom [module resolver] can be provided that loads other Rhai scripts. |
|
| [`no_module`] | A WASM module cannot load modules from the file system, so usually this is not needed, but the savings are minimal; alternatively, a custom [module resolver] can be provided that loads other Rhai scripts. |
|
||||||
|
|
||||||
The following features are typically _not_ used because they don't make sense in a WASM build:
|
The following features are typically _not_ used because they don't make sense in a WASM build:
|
||||||
|
|
||||||
| Feature | Why unnecessary |
|
| Feature | Why unnecessary |
|
||||||
| :-----------: | ------------------------------------------------------------------ |
|
| :-----------: | ------------------------------------------------------------------------------------------------------ |
|
||||||
| [`sync`] | WASM is single-threaded. |
|
| [`sync`] | WASM is single-threaded. |
|
||||||
| [`no_std`] | `std` lib works fine with WASM. |
|
| [`no_std`] | `std` lib works fine with WASM. |
|
||||||
| [`internals`] | WASM usually doesn't need to access Rhai internal data structures. |
|
| [`internals`] | WASM usually doesn't need to access Rhai internal data structures, unless you are walking the [`AST`]. |
|
||||||
|
@ -17,7 +17,7 @@ more control over what a script can (or cannot) do.
|
|||||||
| `sync` | no | restricts all values types to those that are `Send + Sync`. Under this feature, all Rhai types, including [`Engine`], [`Scope`] and [`AST`], are all `Send + Sync` |
|
| `sync` | no | restricts all values types to those that are `Send + Sync`. Under this feature, all Rhai types, including [`Engine`], [`Scope`] and [`AST`], are all `Send + Sync` |
|
||||||
| `no_optimize` | no | disables [script optimization] |
|
| `no_optimize` | no | disables [script optimization] |
|
||||||
| `no_float` | no | disables floating-point numbers and math |
|
| `no_float` | no | disables floating-point numbers and math |
|
||||||
| `f32_float` | no | sets the system floating-point type to `f32` instead of `f64` |
|
| `f32_float` | no | sets the system floating-point type to `f32` instead of `f64`. `FLOAT` is set to `f32` |
|
||||||
| `only_i32` | no | sets the system integer type to `i32` and disable all other integer types. `INT` is set to `i32` |
|
| `only_i32` | no | sets the system integer type to `i32` and disable all other integer types. `INT` is set to `i32` |
|
||||||
| `only_i64` | no | sets the system integer type to `i64` and disable all other integer types. `INT` is set to `i64` |
|
| `only_i64` | no | sets the system integer type to `i64` and disable all other integer types. `INT` is set to `i64` |
|
||||||
| `no_index` | no | disables [arrays] and indexing features |
|
| `no_index` | no | disables [arrays] and indexing features |
|
||||||
|
@ -115,8 +115,8 @@ pub struct FnPtr(ImmutableString, StaticVec<Dynamic>);
|
|||||||
impl FnPtr {
|
impl FnPtr {
|
||||||
/// Create a new function pointer.
|
/// Create a new function pointer.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub(crate) fn new_unchecked<S: Into<ImmutableString>>(
|
pub(crate) fn new_unchecked(
|
||||||
name: S,
|
name: impl Into<ImmutableString>,
|
||||||
curry: StaticVec<Dynamic>,
|
curry: StaticVec<Dynamic>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Self(name.into(), curry)
|
Self(name.into(), curry)
|
||||||
@ -147,7 +147,6 @@ impl FnPtr {
|
|||||||
pub fn is_anonymous(&self) -> bool {
|
pub fn is_anonymous(&self) -> bool {
|
||||||
self.0.starts_with(FN_ANONYMOUS)
|
self.0.starts_with(FN_ANONYMOUS)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Call the function pointer with curried arguments (if any).
|
/// Call the function pointer with curried arguments (if any).
|
||||||
///
|
///
|
||||||
/// If this function is a script-defined function, it must not be marked private.
|
/// If this function is a script-defined function, it must not be marked private.
|
||||||
|
@ -144,7 +144,7 @@ macro_rules! make_func {
|
|||||||
|
|
||||||
/// To Dynamic mapping function.
|
/// To Dynamic mapping function.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn map_dynamic<T: Variant + Clone>(data: T) -> Result<Dynamic, Box<EvalAltResult>> {
|
pub fn map_dynamic(data: impl Variant + Clone) -> Result<Dynamic, Box<EvalAltResult>> {
|
||||||
Ok(data.into_dynamic())
|
Ok(data.into_dynamic())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,7 +48,7 @@ impl StaticModuleResolver {
|
|||||||
}
|
}
|
||||||
/// Add a module keyed by its path.
|
/// Add a module keyed by its path.
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn insert<S: Into<String>>(&mut self, path: S, module: Module) {
|
pub fn insert(&mut self, path: impl Into<String>, module: Module) {
|
||||||
self.0.insert(path.into(), module);
|
self.0.insert(path.into(), module);
|
||||||
}
|
}
|
||||||
/// Remove a module given its path.
|
/// Remove a module given its path.
|
||||||
|
24
src/scope.rs
24
src/scope.rs
@ -168,10 +168,10 @@ impl<'a> Scope<'a> {
|
|||||||
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn push<K: Into<Cow<'a, str>>, T: Variant + Clone>(
|
pub fn push(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: K,
|
name: impl Into<Cow<'a, str>>,
|
||||||
value: T,
|
value: impl Variant + Clone,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.push_dynamic_value(name, EntryType::Normal, Dynamic::from(value))
|
self.push_dynamic_value(name, EntryType::Normal, Dynamic::from(value))
|
||||||
}
|
}
|
||||||
@ -189,7 +189,7 @@ impl<'a> Scope<'a> {
|
|||||||
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn push_dynamic<K: Into<Cow<'a, str>>>(&mut self, name: K, value: Dynamic) -> &mut Self {
|
pub fn push_dynamic(&mut self, name: impl Into<Cow<'a, str>>, value: Dynamic) -> &mut Self {
|
||||||
self.push_dynamic_value(name, EntryType::Normal, value)
|
self.push_dynamic_value(name, EntryType::Normal, value)
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -212,10 +212,10 @@ impl<'a> Scope<'a> {
|
|||||||
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn push_constant<K: Into<Cow<'a, str>>, T: Variant + Clone>(
|
pub fn push_constant(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: K,
|
name: impl Into<Cow<'a, str>>,
|
||||||
value: T,
|
value: impl Variant + Clone,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.push_dynamic_value(name, EntryType::Constant, Dynamic::from(value))
|
self.push_dynamic_value(name, EntryType::Constant, Dynamic::from(value))
|
||||||
}
|
}
|
||||||
@ -240,9 +240,9 @@ impl<'a> Scope<'a> {
|
|||||||
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn push_constant_dynamic<K: Into<Cow<'a, str>>>(
|
pub fn push_constant_dynamic(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: K,
|
name: impl Into<Cow<'a, str>>,
|
||||||
value: Dynamic,
|
value: Dynamic,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
self.push_dynamic_value(name, EntryType::Constant, value)
|
self.push_dynamic_value(name, EntryType::Constant, value)
|
||||||
@ -250,9 +250,9 @@ impl<'a> Scope<'a> {
|
|||||||
|
|
||||||
/// Add (push) a new entry with a `Dynamic` value to the Scope.
|
/// Add (push) a new entry with a `Dynamic` value to the Scope.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub(crate) fn push_dynamic_value<K: Into<Cow<'a, str>>>(
|
pub(crate) fn push_dynamic_value(
|
||||||
&mut self,
|
&mut self,
|
||||||
name: K,
|
name: impl Into<Cow<'a, str>>,
|
||||||
entry_type: EntryType,
|
entry_type: EntryType,
|
||||||
value: Dynamic,
|
value: Dynamic,
|
||||||
) -> &mut Self {
|
) -> &mut Self {
|
||||||
@ -377,7 +377,7 @@ impl<'a> Scope<'a> {
|
|||||||
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 0);
|
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 0);
|
||||||
/// ```
|
/// ```
|
||||||
#[inline(always)]
|
#[inline(always)]
|
||||||
pub fn set_value<T: Variant + Clone>(&mut self, name: &'a str, value: T) -> &mut Self {
|
pub fn set_value(&mut self, name: &'a str, value: impl Variant + Clone) -> &mut Self {
|
||||||
match self.get_index(name) {
|
match self.get_index(name) {
|
||||||
None => {
|
None => {
|
||||||
self.push(name, value);
|
self.push(name, value);
|
||||||
|
@ -452,28 +452,19 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// `SeqAccess` implementation for arrays.
|
/// `SeqAccess` implementation for arrays.
|
||||||
struct IterateArray<'a, ITER>
|
struct IterateArray<'a, ITER: Iterator<Item = &'a Dynamic>> {
|
||||||
where
|
|
||||||
ITER: Iterator<Item = &'a Dynamic>,
|
|
||||||
{
|
|
||||||
/// Iterator for a stream of `Dynamic` values.
|
/// Iterator for a stream of `Dynamic` values.
|
||||||
iter: ITER,
|
iter: ITER,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "no_index"))]
|
#[cfg(not(feature = "no_index"))]
|
||||||
impl<'a, ITER> IterateArray<'a, ITER>
|
impl<'a, ITER: Iterator<Item = &'a Dynamic>> IterateArray<'a, ITER> {
|
||||||
where
|
|
||||||
ITER: Iterator<Item = &'a Dynamic>,
|
|
||||||
{
|
|
||||||
pub fn new(iter: ITER) -> Self {
|
pub fn new(iter: ITER) -> Self {
|
||||||
Self { iter }
|
Self { iter }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a: 'de, 'de, ITER> SeqAccess<'de> for IterateArray<'a, ITER>
|
impl<'a: 'de, 'de, ITER: Iterator<Item = &'a Dynamic>> SeqAccess<'de> for IterateArray<'a, ITER> {
|
||||||
where
|
|
||||||
ITER: Iterator<Item = &'a Dynamic>,
|
|
||||||
{
|
|
||||||
type Error = Box<EvalAltResult>;
|
type Error = Box<EvalAltResult>;
|
||||||
|
|
||||||
fn next_element_seed<T: DeserializeSeed<'de>>(
|
fn next_element_seed<T: DeserializeSeed<'de>>(
|
||||||
@ -555,10 +546,10 @@ impl<'t, 'de> EnumAccess<'de> for EnumDeserializer<'t, 'de> {
|
|||||||
type Error = Box<EvalAltResult>;
|
type Error = Box<EvalAltResult>;
|
||||||
type Variant = Self;
|
type Variant = Self;
|
||||||
|
|
||||||
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
|
fn variant_seed<V: DeserializeSeed<'de>>(
|
||||||
where
|
self,
|
||||||
V: DeserializeSeed<'de>,
|
seed: V,
|
||||||
{
|
) -> Result<(V::Value, Self::Variant), Self::Error> {
|
||||||
seed.deserialize(self.tag.into_deserializer())
|
seed.deserialize(self.tag.into_deserializer())
|
||||||
.map(|v| (v, self))
|
.map(|v| (v, self))
|
||||||
}
|
}
|
||||||
@ -572,28 +563,26 @@ impl<'t, 'de> VariantAccess<'de> for EnumDeserializer<'t, 'de> {
|
|||||||
Deserialize::deserialize(&mut self.content)
|
Deserialize::deserialize(&mut self.content)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn newtype_variant_seed<T>(mut self, seed: T) -> Result<T::Value, Self::Error>
|
fn newtype_variant_seed<T: DeserializeSeed<'de>>(
|
||||||
where
|
mut self,
|
||||||
T: DeserializeSeed<'de>,
|
seed: T,
|
||||||
{
|
) -> Result<T::Value, Self::Error> {
|
||||||
seed.deserialize(&mut self.content)
|
seed.deserialize(&mut self.content)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn tuple_variant<V>(mut self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
|
fn tuple_variant<V: Visitor<'de>>(
|
||||||
where
|
mut self,
|
||||||
V: Visitor<'de>,
|
len: usize,
|
||||||
{
|
visitor: V,
|
||||||
|
) -> Result<V::Value, Self::Error> {
|
||||||
self.content.deserialize_tuple(len, visitor)
|
self.content.deserialize_tuple(len, visitor)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn struct_variant<V>(
|
fn struct_variant<V: Visitor<'de>>(
|
||||||
mut self,
|
mut self,
|
||||||
fields: &'static [&'static str],
|
fields: &'static [&'static str],
|
||||||
visitor: V,
|
visitor: V,
|
||||||
) -> Result<V::Value, Self::Error>
|
) -> Result<V::Value, Self::Error> {
|
||||||
where
|
|
||||||
V: Visitor<'de>,
|
|
||||||
{
|
|
||||||
self.content.deserialize_struct("", fields, visitor)
|
self.content.deserialize_struct("", fields, visitor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -66,7 +66,7 @@ macro_rules! reg_functions {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn make_greeting<T: std::fmt::Display>(n: T) -> String {
|
fn make_greeting(n: impl std::fmt::Display) -> String {
|
||||||
format!("{} kitties", n)
|
format!("{} kitties", n)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user