From 32f41c69bdb57c042fbdf72c76d73d408276bcd7 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Tue, 3 Nov 2020 21:50:14 +0800 Subject: [PATCH] Refine code and docs. --- RELEASES.md | 6 ++++ doc/src/safety/progress.md | 16 +++++++++- doc/src/start/builds/performance.md | 5 +-- doc/src/start/builds/wasm.md | 13 ++++---- doc/src/start/features.md | 2 +- src/fn_native.rs | 5 ++- src/fn_register.rs | 2 +- src/module/resolvers/stat.rs | 2 +- src/scope.rs | 24 +++++++-------- src/serde_impl/de.rs | 47 +++++++++++------------------ tests/plugins.rs | 2 +- 11 files changed, 67 insertions(+), 57 deletions(-) diff --git a/RELEASES.md b/RELEASES.md index af4262ba..9c654cdd 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -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. + +Changes to Error Handling +------------------------ + * `EvalAltResult::ErrorAssignmentToUnknownLHS` is moved to `ParseError::AssignmentToInvalidLHS`. `ParseError::AssignmentToCopy` is removed. * `EvalAltResult::ErrorDataTooLarge` is simplified. * `Engine::on_progress` closure signature now returns `Option` with the termination value passed on to `EvalAltResult::ErrorTerminated`. @@ -30,11 +34,13 @@ New features * `f32_float` feature to set `FLOAT` to `f32`. * Low-level API for custom syntax allowing more flexibility in designing the syntax. * `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 ------------ * 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 diff --git a/doc/src/safety/progress.md b/doc/src/safety/progress.md index 99158470..39e274df 100644 --- a/doc/src/safety/progress.md +++ b/doc/src/safety/progress.md @@ -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. 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 diff --git a/doc/src/start/builds/performance.md b/doc/src/start/builds/performance.md index 78ca762e..35ee122b 100644 --- a/doc/src/start/builds/performance.md +++ b/doc/src/start/builds/performance.md @@ -29,8 +29,9 @@ due to 64-bit arithmetic requiring more CPU cycles to complete. 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. -Normally [`Dynamic`] can be up to 16 bytes (e.g. on x86/x64 CPU's) in order to hold an `i64` or `f64`. +Turning on [`no_float`] or [`f32_float`] and [`only_i32`] on 32-bit targets makes the critical [`Dynamic`] +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. diff --git a/doc/src/start/builds/wasm.md b/doc/src/start/builds/wasm.md index fbbc9007..0875a778 100644 --- a/doc/src/start/builds/wasm.md +++ b/doc/src/start/builds/wasm.md @@ -42,13 +42,14 @@ are typically used for a WASM build: | 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. | -| [`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. | The following features are typically _not_ used because they don't make sense in a WASM build: -| Feature | Why unnecessary | -| :-----------: | ------------------------------------------------------------------ | -| [`sync`] | WASM is single-threaded. | -| [`no_std`] | `std` lib works fine with WASM. | -| [`internals`] | WASM usually doesn't need to access Rhai internal data structures. | +| Feature | Why unnecessary | +| :-----------: | ------------------------------------------------------------------------------------------------------ | +| [`sync`] | WASM is single-threaded. | +| [`no_std`] | `std` lib works fine with WASM. | +| [`internals`] | WASM usually doesn't need to access Rhai internal data structures, unless you are walking the [`AST`]. | diff --git a/doc/src/start/features.md b/doc/src/start/features.md index 60508ed4..85a13168 100644 --- a/doc/src/start/features.md +++ b/doc/src/start/features.md @@ -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` | | `no_optimize` | no | disables [script optimization] | | `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_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 | diff --git a/src/fn_native.rs b/src/fn_native.rs index 56488ac2..ef30149c 100644 --- a/src/fn_native.rs +++ b/src/fn_native.rs @@ -115,8 +115,8 @@ pub struct FnPtr(ImmutableString, StaticVec); impl FnPtr { /// Create a new function pointer. #[inline(always)] - pub(crate) fn new_unchecked>( - name: S, + pub(crate) fn new_unchecked( + name: impl Into, curry: StaticVec, ) -> Self { Self(name.into(), curry) @@ -147,7 +147,6 @@ impl FnPtr { pub fn is_anonymous(&self) -> bool { self.0.starts_with(FN_ANONYMOUS) } - /// Call the function pointer with curried arguments (if any). /// /// If this function is a script-defined function, it must not be marked private. diff --git a/src/fn_register.rs b/src/fn_register.rs index 4a8ac472..f1e1f50e 100644 --- a/src/fn_register.rs +++ b/src/fn_register.rs @@ -144,7 +144,7 @@ macro_rules! make_func { /// To Dynamic mapping function. #[inline(always)] -pub fn map_dynamic(data: T) -> Result> { +pub fn map_dynamic(data: impl Variant + Clone) -> Result> { Ok(data.into_dynamic()) } diff --git a/src/module/resolvers/stat.rs b/src/module/resolvers/stat.rs index 4b64ad91..5d895e9d 100644 --- a/src/module/resolvers/stat.rs +++ b/src/module/resolvers/stat.rs @@ -48,7 +48,7 @@ impl StaticModuleResolver { } /// Add a module keyed by its path. #[inline(always)] - pub fn insert>(&mut self, path: S, module: Module) { + pub fn insert(&mut self, path: impl Into, module: Module) { self.0.insert(path.into(), module); } /// Remove a module given its path. diff --git a/src/scope.rs b/src/scope.rs index 970ecba0..1f2befb3 100644 --- a/src/scope.rs +++ b/src/scope.rs @@ -168,10 +168,10 @@ impl<'a> Scope<'a> { /// assert_eq!(my_scope.get_value::("x").unwrap(), 42); /// ``` #[inline(always)] - pub fn push>, T: Variant + Clone>( + pub fn push( &mut self, - name: K, - value: T, + name: impl Into>, + value: impl Variant + Clone, ) -> &mut Self { self.push_dynamic_value(name, EntryType::Normal, Dynamic::from(value)) } @@ -189,7 +189,7 @@ impl<'a> Scope<'a> { /// assert_eq!(my_scope.get_value::("x").unwrap(), 42); /// ``` #[inline(always)] - pub fn push_dynamic>>(&mut self, name: K, value: Dynamic) -> &mut Self { + pub fn push_dynamic(&mut self, name: impl Into>, value: Dynamic) -> &mut Self { self.push_dynamic_value(name, EntryType::Normal, value) } @@ -212,10 +212,10 @@ impl<'a> Scope<'a> { /// assert_eq!(my_scope.get_value::("x").unwrap(), 42); /// ``` #[inline(always)] - pub fn push_constant>, T: Variant + Clone>( + pub fn push_constant( &mut self, - name: K, - value: T, + name: impl Into>, + value: impl Variant + Clone, ) -> &mut Self { self.push_dynamic_value(name, EntryType::Constant, Dynamic::from(value)) } @@ -240,9 +240,9 @@ impl<'a> Scope<'a> { /// assert_eq!(my_scope.get_value::("x").unwrap(), 42); /// ``` #[inline(always)] - pub fn push_constant_dynamic>>( + pub fn push_constant_dynamic( &mut self, - name: K, + name: impl Into>, value: Dynamic, ) -> &mut Self { 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. #[inline] - pub(crate) fn push_dynamic_value>>( + pub(crate) fn push_dynamic_value( &mut self, - name: K, + name: impl Into>, entry_type: EntryType, value: Dynamic, ) -> &mut Self { @@ -377,7 +377,7 @@ impl<'a> Scope<'a> { /// assert_eq!(my_scope.get_value::("x").unwrap(), 0); /// ``` #[inline(always)] - pub fn set_value(&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) { None => { self.push(name, value); diff --git a/src/serde_impl/de.rs b/src/serde_impl/de.rs index be0a5633..c040b191 100644 --- a/src/serde_impl/de.rs +++ b/src/serde_impl/de.rs @@ -452,28 +452,19 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> { } /// `SeqAccess` implementation for arrays. -struct IterateArray<'a, ITER> -where - ITER: Iterator, -{ +struct IterateArray<'a, ITER: Iterator> { /// Iterator for a stream of `Dynamic` values. iter: ITER, } #[cfg(not(feature = "no_index"))] -impl<'a, ITER> IterateArray<'a, ITER> -where - ITER: Iterator, -{ +impl<'a, ITER: Iterator> IterateArray<'a, ITER> { pub fn new(iter: ITER) -> Self { Self { iter } } } -impl<'a: 'de, 'de, ITER> SeqAccess<'de> for IterateArray<'a, ITER> -where - ITER: Iterator, -{ +impl<'a: 'de, 'de, ITER: Iterator> SeqAccess<'de> for IterateArray<'a, ITER> { type Error = Box; fn next_element_seed>( @@ -555,10 +546,10 @@ impl<'t, 'de> EnumAccess<'de> for EnumDeserializer<'t, 'de> { type Error = Box; type Variant = Self; - fn variant_seed(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error> - where - V: DeserializeSeed<'de>, - { + fn variant_seed>( + self, + seed: V, + ) -> Result<(V::Value, Self::Variant), Self::Error> { seed.deserialize(self.tag.into_deserializer()) .map(|v| (v, self)) } @@ -572,28 +563,26 @@ impl<'t, 'de> VariantAccess<'de> for EnumDeserializer<'t, 'de> { Deserialize::deserialize(&mut self.content) } - fn newtype_variant_seed(mut self, seed: T) -> Result - where - T: DeserializeSeed<'de>, - { + fn newtype_variant_seed>( + mut self, + seed: T, + ) -> Result { seed.deserialize(&mut self.content) } - fn tuple_variant(mut self, len: usize, visitor: V) -> Result - where - V: Visitor<'de>, - { + fn tuple_variant>( + mut self, + len: usize, + visitor: V, + ) -> Result { self.content.deserialize_tuple(len, visitor) } - fn struct_variant( + fn struct_variant>( mut self, fields: &'static [&'static str], visitor: V, - ) -> Result - where - V: Visitor<'de>, - { + ) -> Result { self.content.deserialize_struct("", fields, visitor) } } diff --git a/tests/plugins.rs b/tests/plugins.rs index ce36d6bd..84da570c 100644 --- a/tests/plugins.rs +++ b/tests/plugins.rs @@ -66,7 +66,7 @@ macro_rules! reg_functions { } } -fn make_greeting(n: T) -> String { +fn make_greeting(n: impl std::fmt::Display) -> String { format!("{} kitties", n) }