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.
|
||||
|
||||
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<Dynamic>` 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
|
||||
|
@ -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
|
||||
|
@ -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.
|
||||
|
||||
|
@ -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`]. |
|
||||
|
@ -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 |
|
||||
|
@ -115,8 +115,8 @@ pub struct FnPtr(ImmutableString, StaticVec<Dynamic>);
|
||||
impl FnPtr {
|
||||
/// Create a new function pointer.
|
||||
#[inline(always)]
|
||||
pub(crate) fn new_unchecked<S: Into<ImmutableString>>(
|
||||
name: S,
|
||||
pub(crate) fn new_unchecked(
|
||||
name: impl Into<ImmutableString>,
|
||||
curry: StaticVec<Dynamic>,
|
||||
) -> 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.
|
||||
|
@ -144,7 +144,7 @@ macro_rules! make_func {
|
||||
|
||||
/// To Dynamic mapping function.
|
||||
#[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())
|
||||
}
|
||||
|
||||
|
@ -48,7 +48,7 @@ impl StaticModuleResolver {
|
||||
}
|
||||
/// Add a module keyed by its path.
|
||||
#[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);
|
||||
}
|
||||
/// 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);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn push<K: Into<Cow<'a, str>>, T: Variant + Clone>(
|
||||
pub fn push(
|
||||
&mut self,
|
||||
name: K,
|
||||
value: T,
|
||||
name: impl Into<Cow<'a, str>>,
|
||||
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::<i64>("x").unwrap(), 42);
|
||||
/// ```
|
||||
#[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)
|
||||
}
|
||||
|
||||
@ -212,10 +212,10 @@ impl<'a> Scope<'a> {
|
||||
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 42);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn push_constant<K: Into<Cow<'a, str>>, T: Variant + Clone>(
|
||||
pub fn push_constant(
|
||||
&mut self,
|
||||
name: K,
|
||||
value: T,
|
||||
name: impl Into<Cow<'a, str>>,
|
||||
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::<i64>("x").unwrap(), 42);
|
||||
/// ```
|
||||
#[inline(always)]
|
||||
pub fn push_constant_dynamic<K: Into<Cow<'a, str>>>(
|
||||
pub fn push_constant_dynamic(
|
||||
&mut self,
|
||||
name: K,
|
||||
name: impl Into<Cow<'a, str>>,
|
||||
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<K: Into<Cow<'a, str>>>(
|
||||
pub(crate) fn push_dynamic_value(
|
||||
&mut self,
|
||||
name: K,
|
||||
name: impl Into<Cow<'a, str>>,
|
||||
entry_type: EntryType,
|
||||
value: Dynamic,
|
||||
) -> &mut Self {
|
||||
@ -377,7 +377,7 @@ impl<'a> Scope<'a> {
|
||||
/// assert_eq!(my_scope.get_value::<i64>("x").unwrap(), 0);
|
||||
/// ```
|
||||
#[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) {
|
||||
None => {
|
||||
self.push(name, value);
|
||||
|
@ -452,28 +452,19 @@ impl<'de> Deserializer<'de> for &mut DynamicDeserializer<'de> {
|
||||
}
|
||||
|
||||
/// `SeqAccess` implementation for arrays.
|
||||
struct IterateArray<'a, ITER>
|
||||
where
|
||||
ITER: Iterator<Item = &'a Dynamic>,
|
||||
{
|
||||
struct IterateArray<'a, ITER: Iterator<Item = &'a Dynamic>> {
|
||||
/// Iterator for a stream of `Dynamic` values.
|
||||
iter: ITER,
|
||||
}
|
||||
|
||||
#[cfg(not(feature = "no_index"))]
|
||||
impl<'a, ITER> IterateArray<'a, ITER>
|
||||
where
|
||||
ITER: Iterator<Item = &'a Dynamic>,
|
||||
{
|
||||
impl<'a, ITER: Iterator<Item = &'a Dynamic>> 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<Item = &'a Dynamic>,
|
||||
{
|
||||
impl<'a: 'de, 'de, ITER: Iterator<Item = &'a Dynamic>> SeqAccess<'de> for IterateArray<'a, ITER> {
|
||||
type Error = Box<EvalAltResult>;
|
||||
|
||||
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 Variant = Self;
|
||||
|
||||
fn variant_seed<V>(self, seed: V) -> Result<(V::Value, Self::Variant), Self::Error>
|
||||
where
|
||||
V: DeserializeSeed<'de>,
|
||||
{
|
||||
fn variant_seed<V: DeserializeSeed<'de>>(
|
||||
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<T>(mut self, seed: T) -> Result<T::Value, Self::Error>
|
||||
where
|
||||
T: DeserializeSeed<'de>,
|
||||
{
|
||||
fn newtype_variant_seed<T: DeserializeSeed<'de>>(
|
||||
mut self,
|
||||
seed: T,
|
||||
) -> Result<T::Value, Self::Error> {
|
||||
seed.deserialize(&mut self.content)
|
||||
}
|
||||
|
||||
fn tuple_variant<V>(mut self, len: usize, visitor: V) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
fn tuple_variant<V: Visitor<'de>>(
|
||||
mut self,
|
||||
len: usize,
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error> {
|
||||
self.content.deserialize_tuple(len, visitor)
|
||||
}
|
||||
|
||||
fn struct_variant<V>(
|
||||
fn struct_variant<V: Visitor<'de>>(
|
||||
mut self,
|
||||
fields: &'static [&'static str],
|
||||
visitor: V,
|
||||
) -> Result<V::Value, Self::Error>
|
||||
where
|
||||
V: Visitor<'de>,
|
||||
{
|
||||
) -> Result<V::Value, Self::Error> {
|
||||
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)
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user