From b70fd35f4a89de1285160959e8d15978883628d0 Mon Sep 17 00:00:00 2001 From: Stephen Chung Date: Tue, 28 Jul 2020 10:25:57 +0800 Subject: [PATCH] Revise docs. --- README.md | 5 +-- doc/src/about/features.md | 13 +++--- doc/src/language/fn-namespaces.md | 71 ++++++++++++++++++------------ doc/src/language/functions.md | 2 +- doc/src/language/method.md | 22 ++++++++- doc/src/language/modules/import.md | 15 +++++-- doc/src/language/overload.md | 10 ++--- doc/src/start/features.md | 2 +- src/module.rs | 2 +- 9 files changed, 91 insertions(+), 51 deletions(-) diff --git a/README.md b/README.md index 1516abcc..7aef538c 100644 --- a/README.md +++ b/README.md @@ -27,12 +27,11 @@ Standard features * Easily [call a script-defined function](https://schungx.github.io/rhai/engine/call-fn.html) from Rust. * Fairly low compile-time overhead. * Fairly efficient evaluation (1 million iterations in 0.3 sec on a single core, 2.3 GHz Linux VM). -* Relatively little `unsafe` code (yes there are some for performance reasons, and most `unsafe` code is limited to - one single source file, all with names starting with `"unsafe_"`). +* Relatively little `unsafe` code (yes there are some for performance reasons). * Re-entrant scripting engine can be made `Send + Sync` (via the `sync` feature). * [Function overloading](https://schungx.github.io/rhai/language/overload.html). * [Operator overloading](https://schungx.github.io/rhai/rust/operators.html). -* Dynamic dispatch via [function pointers](https://schungx.github.io/rhai/language/fn-ptr.html). +* Dynamic dispatch via [function pointers](https://schungx.github.io/rhai/language/fn-ptr.html) with additional support for [currying](https://schungx.github.io/rhai/language/fn-curry.html). * Some support for [object-oriented programming (OOP)](https://schungx.github.io/rhai/language/oop.html). * Organize code base with dynamically-loadable [modules](https://schungx.github.io/rhai/language/modules.html). * Serialization/deserialization support via [serde](https://crates.io/crates/serde) (requires the `serde` feature). diff --git a/doc/src/about/features.md b/doc/src/about/features.md index 13b2e4c1..ffa28cdc 100644 --- a/doc/src/about/features.md +++ b/doc/src/about/features.md @@ -35,23 +35,20 @@ Dynamic * Organize code base with dynamically-loadable [modules]. -* Dynamic dispatch via [function pointers]. +* Dynamic dispatch via [function pointers] with additional support for [currying]. * Some support for [object-oriented programming (OOP)][OOP]. -* Serialization/deserialization support via [`serde`]. - Safe ---- -* Relatively little `unsafe` code (yes there are some for performance reasons, and most `unsafe` code is limited to - one single source file, all with names starting with `"unsafe_"`). +* Relatively little `unsafe` code (yes there are some for performance reasons). + +* Sand-boxed - the scripting [`Engine`], if declared immutable, cannot mutate the containing environment unless explicitly permitted (e.g. via a `RefCell`). Rugged ------ -* Sand-boxed - the scripting [`Engine`], if declared immutable, cannot mutate the containing environment unless explicitly permitted (e.g. via a `RefCell`). - * Protected against malicious attacks (such as [stack-overflow][maximum call stack depth], [over-sized data][maximum length of strings], and [runaway scripts][maximum number of operations] etc.) that may come from untrusted third-party user-land scripts. * Track script evaluation [progress] and manually terminate a script run. @@ -61,6 +58,8 @@ Flexible * Re-entrant scripting [`Engine`] can be made `Send + Sync` (via the [`sync`] feature). +* Serialization/deserialization support via [`serde`](https://crates.io/crates/serde). + * Support for [minimal builds] by excluding unneeded language [features]. * Supports [most build targets](targets.md) including `no-std` and [WASM]. diff --git a/doc/src/language/fn-namespaces.md b/doc/src/language/fn-namespaces.md index 5bd8e16f..9516f1e6 100644 --- a/doc/src/language/fn-namespaces.md +++ b/doc/src/language/fn-namespaces.md @@ -69,17 +69,22 @@ The only practical way to ensure that a function is a correct one is to use [mod i.e. define the function in a separate module and then [`import`] it: ```rust -message.rhai: +---------------- +| message.rhai | +---------------- - fn message() { "Hello!" } +fn message() { "Hello!" } -script.rhai: - fn say_hello() { - import "message" as msg; - print(msg::message()); - } - say_hello(); +--------------- +| script.rhai | +--------------- + +fn say_hello() { + import "message" as msg; + print(msg::message()); +} +say_hello(); ``` @@ -94,18 +99,23 @@ defined _within the script_. When called later, those functions will be searche current global namespace and may not be found. ```rust -greeting.rhai: +----------------- +| greeting.rhai | +----------------- - fn message() { "Hello!" }; +fn message() { "Hello!" }; - fn say_hello() { print(message()); } +fn say_hello() { print(message()); } - say_hello(); // 'message' is looked up in the global namespace +say_hello(); // 'message' is looked up in the global namespace -script.rhai: - import "greeting" as g; - g::say_hello(); // <- error: function not found - 'message' +--------------- +| script.rhai | +--------------- + +import "greeting" as g; +g::say_hello(); // <- error: function not found - 'message' ``` In the example above, although the module `greeting.rhai` loads fine (`"Hello!"` is printed), @@ -118,24 +128,29 @@ as possible and avoid cross-calling them from each other. A [function pointer] to call another function within a module-defined function: ```rust -greeting.rhai: +----------------- +| greeting.rhai | +----------------- - fn message() { "Hello!" }; +fn message() { "Hello!" }; - fn say_hello(msg_func) { // 'msg_func' is a function pointer - print(msg_func.call()); // call via the function pointer - } +fn say_hello(msg_func) { // 'msg_func' is a function pointer + print(msg_func.call()); // call via the function pointer +} - say_hello(); // 'message' is looked up in the global namespace +say_hello(); // 'message' is looked up in the global namespace -script.rhai: - import "greeting" as g; +--------------- +| script.rhai | +--------------- - fn my_msg() { - import "greeting" as g; // <- must import again here... - g::message() // <- ... otherwise will not find module 'g' - } +import "greeting" as g; - g::say_hello(Fn("my_msg")); // prints 'Hello!' +fn my_msg() { + import "greeting" as g; // <- must import again here... + g::message() // <- ... otherwise will not find module 'g' +} + +g::say_hello(Fn("my_msg")); // prints 'Hello!' ``` diff --git a/doc/src/language/functions.md b/doc/src/language/functions.md index b6c0a85f..d8f67502 100644 --- a/doc/src/language/functions.md +++ b/doc/src/language/functions.md @@ -16,7 +16,7 @@ fn sub(x, y,) { // trailing comma in parameters list is OK add(2, 3) == 5; -sub(2, 3,) == -1; // trailing comma in arguments list is OK +sub(2, 3,) == -1; // trailing comma in arguments list is OK ``` diff --git a/doc/src/language/method.md b/doc/src/language/method.md index c2e9e99e..290d1a06 100644 --- a/doc/src/language/method.md +++ b/doc/src/language/method.md @@ -37,12 +37,30 @@ array[0].update(); // <- call in method-call style will update 'a' ``` -`&mut` is Efficient ------------------- +Number of Parameters +-------------------- + +Native Rust methods registered with an [`Engine`] take _one additional parameter_ more than +an equivalent method coded in script, where the object is accessed via the `this` pointer instead. + +The following table illustrates the differences: + +| Function type | Parameters | Object reference | Function signature | +| :-----------: | :--------: | :--------------------: | :-----------------------------------------------------: | +| Native Rust | _n_ + 1 | First `&mut` parameter | `fn method`
`(obj: &mut T, x: U, y: V) {}` | +| Rhai script | _n_ | `this` | `fn method(x, y) {}` | + + +`&mut` is Efficient (Except for `ImmutableString`) +------------------------------------------------ Using a `&mut` first parameter is highly encouraged when using types that are expensive to clone, even when the intention is not to mutate that argument, because it avoids cloning that argument value. +For example, the `len` method of an [array] has the signature: `Fn(&mut Array) -> INT`. +The array itself is not modified in any way, but using a `&mut` parameter avoids a cloning that would +otherwise have happened if the signature were `Fn(Array) -> INT`. + For primary types that are cheap to clone (e.g. those that implement `Copy`), including `ImmutableString`, this is not necessary. diff --git a/doc/src/language/modules/import.md b/doc/src/language/modules/import.md index dc94b5a8..5e0a377a 100644 --- a/doc/src/language/modules/import.md +++ b/doc/src/language/modules/import.md @@ -63,7 +63,9 @@ cause a stack overflow in the [`Engine`], unless stopped by setting a limit for For instance, importing itself always causes an infinite recursion: ```rust -// This file is 'hello.rhai' +-------------- +| hello.rhai | +-------------- import "hello" as foo; // import itself - infinite recursion! @@ -73,11 +75,18 @@ foo::do_something(); Modules cross-referencing also cause infinite recursion: ```rust -// This file is 'hello.rhai' - references 'world.rhai' +-------------- +| hello.rhai | +-------------- + import "world" as foo; foo::do_something(); -// This file is 'world.rhai' - references 'hello.rhai' + +-------------- +| world.rhai | +-------------- + import "hello" as bar; bar::do_something_else(); ``` diff --git a/doc/src/language/overload.md b/doc/src/language/overload.md index bb291ca3..0b6b4ea8 100644 --- a/doc/src/language/overload.md +++ b/doc/src/language/overload.md @@ -9,15 +9,15 @@ and _number_ of parameters, but not parameter _types_ since all parameters are t New definitions _overwrite_ previous definitions of the same name and number of parameters. ```rust -fn foo(x,y,z) { print("Three!!! " + x + "," + y + "," + z) } +fn foo(x,y,z) { print("Three!!! " + x + "," + y + "," + z); } -fn foo(x) { print("One! " + x) } +fn foo(x) { print("One! " + x); } -fn foo(x,y) { print("Two! " + x + "," + y) } +fn foo(x,y) { print("Two! " + x + "," + y); } -fn foo() { print("None.") } +fn foo() { print("None."); } -fn foo(x) { print("HA! NEW ONE! " + x) } // overwrites previous definition +fn foo(x) { print("HA! NEW ONE! " + x); } // overwrites previous definition foo(1,2,3); // prints "Three!!! 1,2,3" diff --git a/doc/src/start/features.md b/doc/src/start/features.md index f2286a38..0d31d077 100644 --- a/doc/src/start/features.md +++ b/doc/src/start/features.md @@ -24,7 +24,7 @@ more control over what a script can (or cannot) do. | `no_function` | Disable script-defined [functions]. | | `no_module` | Disable loading external [modules]. | | `no_std` | Build for `no-std`. Notice that additional dependencies will be pulled in to replace `std` features. | -| `serde` | Enable serialization/deserialization via [`serde`]. Notice that the [`serde`](https://crates.io/crates/serde) crate will be pulled in together with its dependencies. | +| `serde` | Enable serialization/deserialization via `serde`. Notice that the [`serde`](https://crates.io/crates/serde) crate will be pulled in together with its dependencies. | | `internals` | Expose internal data structures (e.g. [`AST`] nodes). Beware that Rhai internals are volatile and may change from version to version. | diff --git a/src/module.rs b/src/module.rs index b88cbc59..8eacde7b 100644 --- a/src/module.rs +++ b/src/module.rs @@ -432,7 +432,7 @@ impl Module { /// let mut module = Module::new(); /// let hash = module.set_raw_fn("double_or_not", /// // Pass parameter types via a slice with TypeId's - /// &[std::any::TypeId::of::(), std::any::TypeId::of::() ], + /// &[std::any::TypeId::of::(), std::any::TypeId::of::()], /// // Fixed closure signature /// |engine, lib, args| { /// // 'args' is guaranteed to be the right length and of the correct types