Refine code and docs.

This commit is contained in:
Stephen Chung 2020-11-03 21:50:14 +08:00
parent f74d947c6b
commit 32f41c69bd
11 changed files with 67 additions and 57 deletions

View File

@ -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

View File

@ -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

View File

@ -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.

View File

@ -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`]. |

View File

@ -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 |

View File

@ -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.

View File

@ -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())
} }

View File

@ -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.

View File

@ -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);

View File

@ -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)
} }
} }

View File

@ -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)
} }