reorganize module

This commit is contained in:
Timur Gordon
2025-04-04 08:28:07 +02:00
parent 1ea37e2e7f
commit 939b6b4e57
375 changed files with 7580 additions and 191 deletions

View File

@@ -1,176 +0,0 @@
Apache License
Version 2.0, January 2004
http://www.apache.org/licenses/
TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION
1. Definitions.
"License" shall mean the terms and conditions for use, reproduction,
and distribution as defined by Sections 1 through 9 of this document.
"Licensor" shall mean the copyright owner or entity authorized by
the copyright owner that is granting the License.
"Legal Entity" shall mean the union of the acting entity and all
other entities that control, are controlled by, or are under common
control with that entity. For the purposes of this definition,
"control" means (i) the power, direct or indirect, to cause the
direction or management of such entity, whether by contract or
otherwise, or (ii) ownership of fifty percent (50%) or more of the
outstanding shares, or (iii) beneficial ownership of such entity.
"You" (or "Your") shall mean an individual or Legal Entity
exercising permissions granted by this License.
"Source" form shall mean the preferred form for making modifications,
including but not limited to software source code, documentation
source, and configuration files.
"Object" form shall mean any form resulting from mechanical
transformation or translation of a Source form, including but
not limited to compiled object code, generated documentation,
and conversions to other media types.
"Work" shall mean the work of authorship, whether in Source or
Object form, made available under the License, as indicated by a
copyright notice that is included in or attached to the work
(an example is provided in the Appendix below).
"Derivative Works" shall mean any work, whether in Source or Object
form, that is based on (or derived from) the Work and for which the
editorial revisions, annotations, elaborations, or other modifications
represent, as a whole, an original work of authorship. For the purposes
of this License, Derivative Works shall not include works that remain
separable from, or merely link (or bind by name) to the interfaces of,
the Work and Derivative Works thereof.
"Contribution" shall mean any work of authorship, including
the original version of the Work and any modifications or additions
to that Work or Derivative Works thereof, that is intentionally
submitted to Licensor for inclusion in the Work by the copyright owner
or by an individual or Legal Entity authorized to submit on behalf of
the copyright owner. For the purposes of this definition, "submitted"
means any form of electronic, verbal, or written communication sent
to the Licensor or its representatives, including but not limited to
communication on electronic mailing lists, source code control systems,
and issue tracking systems that are managed by, or on behalf of, the
Licensor for the purpose of discussing and improving the Work, but
excluding communication that is conspicuously marked or otherwise
designated in writing by the copyright owner as "Not a Contribution."
"Contributor" shall mean Licensor and any individual or Legal Entity
on behalf of whom a Contribution has been received by Licensor and
subsequently incorporated within the Work.
2. Grant of Copyright License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
copyright license to reproduce, prepare Derivative Works of,
publicly display, publicly perform, sublicense, and distribute the
Work and such Derivative Works in Source or Object form.
3. Grant of Patent License. Subject to the terms and conditions of
this License, each Contributor hereby grants to You a perpetual,
worldwide, non-exclusive, no-charge, royalty-free, irrevocable
(except as stated in this section) patent license to make, have made,
use, offer to sell, sell, import, and otherwise transfer the Work,
where such license applies only to those patent claims licensable
by such Contributor that are necessarily infringed by their
Contribution(s) alone or by combination of their Contribution(s)
with the Work to which such Contribution(s) was submitted. If You
institute patent litigation against any entity (including a
cross-claim or counterclaim in a lawsuit) alleging that the Work
or a Contribution incorporated within the Work constitutes direct
or contributory patent infringement, then any patent licenses
granted to You under this License for that Work shall terminate
as of the date such litigation is filed.
4. Redistribution. You may reproduce and distribute copies of the
Work or Derivative Works thereof in any medium, with or without
modifications, and in Source or Object form, provided that You
meet the following conditions:
(a) You must give any other recipients of the Work or
Derivative Works a copy of this License; and
(b) You must cause any modified files to carry prominent notices
stating that You changed the files; and
(c) You must retain, in the Source form of any Derivative Works
that You distribute, all copyright, patent, trademark, and
attribution notices from the Source form of the Work,
excluding those notices that do not pertain to any part of
the Derivative Works; and
(d) If the Work includes a "NOTICE" text file as part of its
distribution, then any Derivative Works that You distribute must
include a readable copy of the attribution notices contained
within such NOTICE file, excluding those notices that do not
pertain to any part of the Derivative Works, in at least one
of the following places: within a NOTICE text file distributed
as part of the Derivative Works; within the Source form or
documentation, if provided along with the Derivative Works; or,
within a display generated by the Derivative Works, if and
wherever such third-party notices normally appear. The contents
of the NOTICE file are for informational purposes only and
do not modify the License. You may add Your own attribution
notices within Derivative Works that You distribute, alongside
or as an addendum to the NOTICE text from the Work, provided
that such additional attribution notices cannot be construed
as modifying the License.
You may add Your own copyright statement to Your modifications and
may provide additional or different license terms and conditions
for use, reproduction, or distribution of Your modifications, or
for any such Derivative Works as a whole, provided Your use,
reproduction, and distribution of the Work otherwise complies with
the conditions stated in this License.
5. Submission of Contributions. Unless You explicitly state otherwise,
any Contribution intentionally submitted for inclusion in the Work
by You to the Licensor shall be under the terms and conditions of
this License, without any additional terms or conditions.
Notwithstanding the above, nothing herein shall supersede or modify
the terms of any separate license agreement you may have executed
with Licensor regarding such Contributions.
6. Trademarks. This License does not grant permission to use the trade
names, trademarks, service marks, or product names of the Licensor,
except as required for reasonable and customary use in describing the
origin of the Work and reproducing the content of the NOTICE file.
7. Disclaimer of Warranty. Unless required by applicable law or
agreed to in writing, Licensor provides the Work (and each
Contributor provides its Contributions) on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
implied, including, without limitation, any warranties or conditions
of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A
PARTICULAR PURPOSE. You are solely responsible for determining the
appropriateness of using or redistributing the Work and assume any
risks associated with Your exercise of permissions under this License.
8. Limitation of Liability. In no event and under no legal theory,
whether in tort (including negligence), contract, or otherwise,
unless required by applicable law (such as deliberate and grossly
negligent acts) or agreed to in writing, shall any Contributor be
liable to You for damages, including any direct, indirect, special,
incidental, or consequential damages of any character arising as a
result of this License or out of the use or inability to use the
Work (including but not limited to damages for loss of goodwill,
work stoppage, computer failure or malfunction, or any and all
other commercial damages or losses), even if such Contributor
has been advised of the possibility of such damages.
9. Accepting Warranty or Additional Liability. While redistributing
the Work or Derivative Works thereof, You may choose to offer,
and charge a fee for, acceptance of support, warranty, indemnity,
or other liability obligations and/or rights consistent with this
License. However, in accepting such obligations, You may act only
on Your own behalf and on Your sole responsibility, not on behalf
of any other Contributor, and only if You agree to indemnify,
defend, and hold each Contributor harmless for any liability
incurred by, or claims asserted against, such Contributor by reason
of your accepting any such warranty or additional liability.
END OF TERMS AND CONDITIONS

View File

@@ -1,23 +0,0 @@
Permission is hereby granted, free of charge, to any
person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the
Software without restriction, including without
limitation the rights to use, copy, modify, merge,
publish, distribute, sublicense, and/or sell copies of
the Software, and to permit persons to whom the Software
is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice
shall be included in all copies or substantial portions
of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF
ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED
TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR
IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
DEALINGS IN THE SOFTWARE.

View File

@@ -1,37 +0,0 @@
# Sample Applications
## Standard Examples
| Example | Description |
| --------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------- |
| [`arrays_and_structs`](arrays_and_structs.rs) | shows how to register a Rust type and using it with arrays |
| [`callback`](callback.rs) | shows how to store a Rhai closure and call it later within Rust |
| [`custom_types_and_methods`](custom_types_and_methods.rs) | shows how to register a Rust type and methods/getters/setters for it |
| [`custom_types`](custom_types.rs) | shows how to register a Rust type and methods/getters/setters using the `CustomType` trait. |
| [`definitions`](./definitions) | shows how to generate definition files for use with the [Rhai Language Server](https://github.com/rhaiscript/lsp) (requires the `metadata` feature) |
| [`hello`](hello.rs) | simple example that evaluates an expression and prints the result |
| [`pause_and_resume`](pause_and_resume.rs) | shows how to pause/resume/stop an `Engine` running in a separate thread via an MPSC channel |
| [`reuse_scope`](reuse_scope.rs) | evaluates two pieces of code in separate runs, but using a common `Scope` |
| [`serde`](serde.rs) | example to serialize and deserialize Rust types with [`serde`](https://crates.io/crates/serde) (requires the `serde` feature) |
| [`simple_fn`](simple_fn.rs) | shows how to register a simple Rust function |
| [`strings`](strings.rs) | shows different ways to register Rust functions taking string arguments |
| [`threading`](threading.rs) | shows how to communicate in duplex with an `Engine` running in a separate thread via a pair of MPSC channels |
## Scriptable Event Handler With State Examples
Because of its popularity, included are sample implementations for the pattern
[_Scriptable Event Handler With State_](https://rhai.rs/book/patterns/events.html) in different styles.
| Example | Handler Script | Description |
| ------------------------------------------ | ------------------------------------------------------------------ | :---------------------------------------------------------: |
| [`event_handler_main`](event_handler_main) | [`event_handler_main/script.rhai`](event_handler_main/script.rhai) | [_Main Style_](https://rhai.rs/book/patterns/events-1.html) |
| [`event_handler_js`](event_handler_js) | [`event_handler_js/script.rhai`](event_handler_js/script.rhai) | [_JS Style_](https://rhai.rs/book/patterns/events-2.html) |
| [`event_handler_map`](event_handler_map) | [`event_handler_map/script.rhai`](event_handler_map/script.rhai) | [_Map Style_](https://rhai.rs/book/patterns/events-3.html) |
## Running Examples
Examples can be run with the following command:
```sh
cargo run --example {example_name}
```

View File

@@ -1,67 +0,0 @@
//! An example showing how to register a Rust type and use it with arrays.
#[cfg(any(feature = "no_index", feature = "no_object"))]
fn main() {
panic!("This example does not run under 'no_index' or 'no_object'.")
}
use rhai::{Engine, EvalAltResult};
#[cfg(not(feature = "no_index"))]
#[cfg(not(feature = "no_object"))]
fn main() -> Result<(), Box<EvalAltResult>> {
#[derive(Debug, Clone)]
struct TestStruct {
x: i64,
}
impl TestStruct {
pub fn new() -> Self {
Self { x: 1 }
}
pub fn update(&mut self) {
self.x += 1000;
}
}
let mut engine = Engine::new();
engine
.register_type_with_name::<TestStruct>("TestStruct")
.register_fn("new_ts", TestStruct::new)
.register_fn("update", TestStruct::update);
#[cfg(feature = "metadata")]
{
println!("Functions registered:");
engine
.gen_fn_signatures(false)
.into_iter()
.for_each(|func| println!("{func}"));
println!();
}
let result = engine.eval::<TestStruct>(
"
let x = new_ts();
x.update();
x
",
)?;
println!("{result:?}");
let result = engine.eval::<TestStruct>(
"
let x = [ new_ts() ];
x[0].update();
x[0]
",
)?;
println!("{result:?}");
Ok(())
}

View File

@@ -1,42 +0,0 @@
//! This example stores a Rhai closure for later use as a callback.
use rhai::{Engine, EvalAltResult, FnPtr};
// To call a Rhai closure at a later time, you'd need three things:
// 1) an `Engine` (with all needed functions registered),
// 2) a compiled `AST`,
// 3) the closure (of type `FnPtr`).
fn main() -> Result<(), Box<EvalAltResult>> {
let engine = Engine::new();
// This script creates a closure which captures a variable and returns it.
let ast = engine.compile(
"
let x = 18;
// The following closure captures 'x'
return |a, b| {
x += 1; // x is incremented each time
(x + a) * b
};
",
)?;
let closure = engine.eval_ast::<FnPtr>(&ast)?;
// Create a closure by encapsulating the `Engine`, `AST` and `FnPtr`.
// In a real application, you'd be handling errors.
let func = move |x: i64, y: i64| -> i64 { closure.call(&engine, &ast, (x, y)).unwrap() };
// Now we can call `func` anywhere just like a normal function!
let r1 = func(1, 2);
// Notice that each call to `func` returns a different value
// because the captured `x` is always changing!
let r2 = func(1, 2);
let r3 = func(1, 2);
println!("The Answers: {r1}, {r2}, {r3}"); // prints 40, 42, 44
Ok(())
}

View File

@@ -1,85 +0,0 @@
//! An example showing how to register a Rust type and methods/getters/setters using the `CustomType` trait.
#[cfg(feature = "no_object")]
fn main() {
panic!("This example does not run under 'no_object'.");
}
use rhai::{CustomType, Engine, EvalAltResult, TypeBuilder};
#[cfg(not(feature = "no_object"))]
fn main() -> Result<(), Box<EvalAltResult>> {
#[derive(Debug, Clone, CustomType)]
#[rhai_type(extra = Self::build_extra)]
struct TestStruct {
x: i64,
}
impl TestStruct {
pub fn new() -> Self {
Self { x: 1 }
}
pub fn update(&mut self) {
self.x += 1000;
}
pub fn calculate(&mut self, data: i64) -> i64 {
self.x * data
}
fn build_extra(builder: &mut TypeBuilder<Self>) {
builder
.with_name("TestStruct")
.with_fn("new_ts", Self::new)
.with_fn("update", Self::update)
.with_fn("calc", Self::calculate)
.is_iterable();
}
}
impl IntoIterator for TestStruct {
type Item = i64;
type IntoIter = std::vec::IntoIter<Self::Item>;
#[inline]
#[must_use]
fn into_iter(self) -> Self::IntoIter {
vec![self.x - 1, self.x, self.x + 1].into_iter()
}
}
let mut engine = Engine::new();
engine.build_type::<TestStruct>();
#[cfg(feature = "metadata")]
{
println!("Functions registered:");
engine
.gen_fn_signatures(false)
.into_iter()
.for_each(|func| println!("{func}"));
println!();
}
let result = engine.eval::<i64>(
"
let x = new_ts();
x.x = 42;
for n in x {
x.x += n;
print(`n = ${n}, total = ${x.x}`);
}
x.update();
x.calc(x.x)
",
)?;
println!("result: {result}"); // prints 1085764
Ok(())
}

View File

@@ -1,114 +0,0 @@
//! An example showing how to register a Rust type and methods/getters/setters for it.
#[cfg(feature = "no_object")]
fn main() {
panic!("This example does not run under 'no_object'.");
}
use rhai::{CustomType, Engine, EvalAltResult, TypeBuilder};
#[cfg(not(feature = "no_object"))]
fn main() -> Result<(), Box<EvalAltResult>> {
/// This is a test structure. If the metadata feature
/// is enabled, this comment will be exported.
#[derive(Debug, Clone, CustomType)]
#[rhai_type(extra = Self::build_extra)]
struct TestStruct {
/// A number.
///
/// ```js
/// let t = new_ts();
/// print(t.x); // Get the value of x.
/// t.x = 42; // Set the value of x.
/// ```
x: i64,
}
impl TestStruct {
pub fn new() -> Self {
Self { x: 1 }
}
pub fn update(&mut self) {
self.x += 1000;
}
pub fn calculate(&mut self, data: i64) -> i64 {
self.x * data
}
fn build_extra(builder: &mut TypeBuilder<Self>) {
builder
.with_fn("new_ts", TestStruct::new)
.with_fn("update", TestStruct::update)
.with_fn("calc", TestStruct::calculate);
}
}
let mut engine = Engine::new();
engine.build_type::<TestStruct>();
#[cfg(feature = "metadata")]
{
println!("Functions registered:");
engine
.gen_fn_signatures(false)
.into_iter()
.for_each(|func| println!("{func}"));
println!();
let docs: serde_json::Value =
serde_json::from_str(&engine.gen_fn_metadata_to_json(false).unwrap()).unwrap();
// compare comments from the type.
assert_eq!(
docs["customTypes"][0]["docComments"],
serde_json::json!([
"/// This is a test structure. If the metadata feature",
"/// is enabled, this comment will be exported."
])
);
// compare comments from the getter.
assert_eq!(
docs["functions"][1]["docComments"],
serde_json::json!([
"/// A number.",
"///",
"/// ```js",
"/// let t = new_ts();",
"/// print(t.x); // Get the value of x.",
"/// t.x = 42; // Set the value of x.",
"/// ```"
])
);
// compare comments from the setter.
assert_eq!(
docs["functions"][3]["docComments"],
serde_json::json!([
"/// A number.",
"///",
"/// ```js",
"/// let t = new_ts();",
"/// print(t.x); // Get the value of x.",
"/// t.x = 42; // Set the value of x.",
"/// ```"
])
);
}
let result = engine.eval::<i64>(
"
let x = new_ts();
x.x = 42;
x.update();
x.calc(x.x)
",
)?;
println!("result: {result}"); // prints 1085764
Ok(())
}

File diff suppressed because it is too large Load Diff

View File

@@ -1,14 +0,0 @@
module static;
op minus(int, int) -> int;
module general_kenobi {
const CONSTANT: int;
/// Returns a string where "hello there" is repeated `n` times.
fn hello_there(n: int) -> String;
}
let hello_there: string;
const HELLO: string;

View File

@@ -1,259 +0,0 @@
module static;
op ==(int, int) -> bool;
op !=(int, int) -> bool;
op >(int, int) -> bool;
op >=(int, int) -> bool;
op <(int, int) -> bool;
op <=(int, int) -> bool;
op &(int, int) -> int;
op |(int, int) -> int;
op ^(int, int) -> int;
op ..(int, int) -> Range<int>;
op ..=(int, int) -> RangeInclusive<int>;
op ==(bool, bool) -> bool;
op !=(bool, bool) -> bool;
op >(bool, bool) -> bool;
op >=(bool, bool) -> bool;
op <(bool, bool) -> bool;
op <=(bool, bool) -> bool;
op &(bool, bool) -> bool;
op |(bool, bool) -> bool;
op ^(bool, bool) -> bool;
op ==((), ()) -> bool;
op !=((), ()) -> bool;
op >((), ()) -> bool;
op >=((), ()) -> bool;
op <((), ()) -> bool;
op <=((), ()) -> bool;
op +(int, int) -> int;
op -(int, int) -> int;
op *(int, int) -> int;
op /(int, int) -> int;
op %(int, int) -> int;
op **(int, int) -> int;
op >>(int, int) -> int;
op <<(int, int) -> int;
op +(float, float) -> float;
op -(float, float) -> float;
op *(float, float) -> float;
op /(float, float) -> float;
op %(float, float) -> float;
op **(float, float) -> float;
op ==(float, float) -> bool;
op !=(float, float) -> bool;
op >(float, float) -> bool;
op >=(float, float) -> bool;
op <(float, float) -> bool;
op <=(float, float) -> bool;
op +(float, int) -> float;
op -(float, int) -> float;
op *(float, int) -> float;
op /(float, int) -> float;
op %(float, int) -> float;
op **(float, int) -> float;
op ==(float, int) -> bool;
op !=(float, int) -> bool;
op >(float, int) -> bool;
op >=(float, int) -> bool;
op <(float, int) -> bool;
op <=(float, int) -> bool;
op +(int, float) -> float;
op -(int, float) -> float;
op *(int, float) -> float;
op /(int, float) -> float;
op %(int, float) -> float;
op **(int, float) -> float;
op ==(int, float) -> bool;
op !=(int, float) -> bool;
op >(int, float) -> bool;
op >=(int, float) -> bool;
op <(int, float) -> bool;
op <=(int, float) -> bool;
op +(Decimal, Decimal) -> Decimal;
op -(Decimal, Decimal) -> Decimal;
op *(Decimal, Decimal) -> Decimal;
op /(Decimal, Decimal) -> Decimal;
op %(Decimal, Decimal) -> Decimal;
op **(Decimal, Decimal) -> Decimal;
op ==(Decimal, Decimal) -> bool;
op !=(Decimal, Decimal) -> bool;
op >(Decimal, Decimal) -> bool;
op >=(Decimal, Decimal) -> bool;
op <(Decimal, Decimal) -> bool;
op <=(Decimal, Decimal) -> bool;
op +(Decimal, int) -> Decimal;
op -(Decimal, int) -> Decimal;
op *(Decimal, int) -> Decimal;
op /(Decimal, int) -> Decimal;
op %(Decimal, int) -> Decimal;
op **(Decimal, int) -> Decimal;
op ==(Decimal, int) -> bool;
op !=(Decimal, int) -> bool;
op >(Decimal, int) -> bool;
op >=(Decimal, int) -> bool;
op <(Decimal, int) -> bool;
op <=(Decimal, int) -> bool;
op +(int, Decimal) -> Decimal;
op -(int, Decimal) -> Decimal;
op *(int, Decimal) -> Decimal;
op /(int, Decimal) -> Decimal;
op %(int, Decimal) -> Decimal;
op **(int, Decimal) -> Decimal;
op ==(int, Decimal) -> bool;
op !=(int, Decimal) -> bool;
op >(int, Decimal) -> bool;
op >=(int, Decimal) -> bool;
op <(int, Decimal) -> bool;
op <=(int, Decimal) -> bool;
op +(String, String) -> String;
op -(String, String) -> String;
op ==(String, String) -> bool;
op !=(String, String) -> bool;
op >(String, String) -> bool;
op >=(String, String) -> bool;
op <(String, String) -> bool;
op <=(String, String) -> bool;
op +(char, char) -> String;
op ==(char, char) -> bool;
op !=(char, char) -> bool;
op >(char, char) -> bool;
op >=(char, char) -> bool;
op <(char, char) -> bool;
op <=(char, char) -> bool;
op +(char, String) -> String;
op ==(char, String) -> bool;
op !=(char, String) -> bool;
op >(char, String) -> bool;
op >=(char, String) -> bool;
op <(char, String) -> bool;
op <=(char, String) -> bool;
op +(String, char) -> String;
op -(String, char) -> String;
op ==(String, char) -> bool;
op !=(String, char) -> bool;
op >(String, char) -> bool;
op >=(String, char) -> bool;
op <(String, char) -> bool;
op <=(String, char) -> bool;
op +((), String) -> String;
op ==((), String) -> bool;
op !=((), String) -> bool;
op >((), String) -> bool;
op >=((), String) -> bool;
op <((), String) -> bool;
op <=((), String) -> bool;
op +(String, ()) -> String;
op ==(String, ()) -> bool;
op !=(String, ()) -> bool;
op >(String, ()) -> bool;
op >=(String, ()) -> bool;
op <(String, ()) -> bool;
op <=(String, ()) -> bool;
op +(Blob, Blob) -> Blob;
op +(Blob, char) -> Blob;
op ==(Blob, Blob) -> bool;
op !=(Blob, Blob) -> bool;
op ==(Range<int>, RangeInclusive<int>) -> bool;
op !=(Range<int>, RangeInclusive<int>) -> bool;
op ==(RangeInclusive<int>, Range<int>) -> bool;
op !=(RangeInclusive<int>, Range<int>) -> bool;
op ==(Range<int>, Range<int>) -> bool;
op !=(Range<int>, Range<int>) -> bool;
op ==(RangeInclusive<int>, RangeInclusive<int>) -> bool;
op !=(RangeInclusive<int>, RangeInclusive<int>) -> bool;
op ==(?, ?) -> bool;
op !=(?, ?) -> bool;
op >(?, ?) -> bool;
op >=(?, ?) -> bool;
op <(?, ?) -> bool;
op <=(?, ?) -> bool;
op &=(bool, bool);
op |=(bool, bool);
op +=(int, int);
op -=(int, int);
op *=(int, int);
op /=(int, int);
op %=(int, int);
op **=(int, int);
op >>=(int, int);
op <<=(int, int);
op &=(int, int);
op |=(int, int);
op ^=(int, int);
op +=(float, float);
op -=(float, float);
op *=(float, float);
op /=(float, float);
op %=(float, float);
op **=(float, float);
op +=(float, int);
op -=(float, int);
op *=(float, int);
op /=(float, int);
op %=(float, int);
op **=(float, int);
op +=(Decimal, Decimal);
op -=(Decimal, Decimal);
op *=(Decimal, Decimal);
op /=(Decimal, Decimal);
op %=(Decimal, Decimal);
op **=(Decimal, Decimal);
op +=(Decimal, int);
op -=(Decimal, int);
op *=(Decimal, int);
op /=(Decimal, int);
op %=(Decimal, int);
op **=(Decimal, int);
op +=(String, String);
op -=(String, String);
op +=(String, char);
op -=(String, char);
op +=(char, String);
op +=(char, char);
op +=(Array, Array);
op +=(Array, ?);
op +=(Blob, Blob);
op +=(Blob, int);
op +=(Blob, char);
op +=(Blob, String);
op in(?, Array) -> bool;
op in(String, String) -> bool;
op in(char, String) -> bool;
op in(int, Range<int>) -> bool;
op in(int, RangeInclusive<int>) -> bool;
op in(String, Map) -> bool;
op in(int, Blob) -> bool;

View File

@@ -1,261 +0,0 @@
module static;
/// Display any data to the standard output.
///
/// # Example
///
/// ```rhai
/// let answer = 42;
///
/// print(`The Answer is ${answer}`);
/// ```
fn print(data: ?);
/// Display any data to the standard output in debug format.
///
/// # Example
///
/// ```rhai
/// let answer = 42;
///
/// debug(answer);
/// ```
fn debug(data: ?);
/// Get the type of a value.
///
/// # Example
///
/// ```rhai
/// let x = "hello, world!";
///
/// print(x.type_of()); // prints "string"
/// ```
fn type_of(data: ?) -> String;
/// Create a function pointer to a named function.
///
/// If the specified name is not a valid function name, an error is raised.
///
/// # Example
///
/// ```rhai
/// let f = Fn("foo"); // function pointer to 'foo'
///
/// f.call(42); // call: foo(42)
/// ```
fn Fn(fn_name: String) -> FnPtr;
/// Call a function pointed to by a function pointer,
/// passing following arguments to the function call.
///
/// If an appropriate function is not found, an error is raised.
///
/// # Example
///
/// ```rhai
/// let f = Fn("foo"); // function pointer to 'foo'
///
/// f.call(1, 2, 3); // call: foo(1, 2, 3)
/// ```
fn call(fn_ptr: FnPtr, ...args: ?) -> ?;
/// Call a function pointed to by a function pointer, binding the `this` pointer
/// to the object of the method call, and passing on following arguments to the function call.
///
/// If an appropriate function is not found, an error is raised.
///
/// # Example
///
/// ```rhai
/// fn add(x) {
/// this + x
/// }
///
/// let f = Fn("add"); // function pointer to 'add'
///
/// let x = 41;
///
/// let r = x.call(f, 1); // call: add(1) with 'this' = 'x'
///
/// print(r); // prints 42
/// ```
fn call(obj: ?, fn_ptr: FnPtr, ...args: ?) -> ?;
/// Curry a number of arguments into a function pointer and return it as a new function pointer.
///
/// # Example
///
/// ```rhai
/// fn foo(x, y, z) {
/// x + y + z
/// }
///
/// let f = Fn("foo");
///
/// let g = f.curry(1, 2); // curried arguments: 1, 2
///
/// g.call(3); // call: foo(1, 2, 3)
/// ```
fn curry(fn_ptr: FnPtr, ...args: ?) -> FnPtr;
/// Return `true` if a script-defined function exists with a specified name and
/// number of parameters.
///
/// # Example
///
/// ```rhai
/// fn foo(x) { }
///
/// print(is_def_fn("foo", 1)); // prints true
/// print(is_def_fn("foo", 2)); // prints false
/// print(is_def_fn("foo", 0)); // prints false
/// print(is_def_fn("bar", 1)); // prints false
/// ```
fn is_def_fn(fn_name: String, num_params: int) -> bool;
/// Return `true` if a variable matching a specified name is defined.
///
/// # Example
///
/// ```rhai
/// let x = 42;
///
/// print(is_def_var("x")); // prints true
/// print(is_def_var("foo")); // prints false
///
/// {
/// let y = 1;
/// print(is_def_var("y")); // prints true
/// }
///
/// print(is_def_var("y")); // prints false
/// ```
fn is_def_var(var_name: String) -> bool;
/// Return `true` if the variable is shared.
///
/// # Example
///
/// ```rhai
/// let x = 42;
///
/// print(is_shared(x)); // prints false
///
/// let f = || x; // capture 'x', making it shared
///
/// print(is_shared(x)); // prints true
/// ```
fn is_shared(variable: ?) -> bool;
/// Evaluate a text script within the current scope.
///
/// # Example
///
/// ```rhai
/// let x = 42;
///
/// eval("let y = x; x = 123;");
///
/// print(x); // prints 123
/// print(y); // prints 42
/// ```
fn eval(script: String) -> ?;
/// Return `true` if the string contains another string.
///
/// This function also drives the `in` operator.
///
/// # Example
///
/// ```rhai
/// let x = "hello world!";
///
/// // The 'in' operator calls 'contains' in the background
/// if "world" in x {
/// print("found!");
/// }
/// ```
fn contains(string: String, find: String) -> bool;
/// Return `true` if the string contains a character.
///
/// This function also drives the `in` operator.
///
/// # Example
///
/// ```rhai
/// let x = "hello world!";
///
/// // The 'in' operator calls 'contains' in the background
/// if 'w' in x {
/// print("found!");
/// }
/// ```
fn contains(string: String, ch: char) -> bool;
/// Return `true` if a value falls within the exclusive range.
///
/// This function also drives the `in` operator.
///
/// # Example
///
/// ```rhai
/// let r = 1..100;
///
/// // The 'in' operator calls 'contains' in the background
/// if 42 in r {
/// print("found!");
/// }
/// ```
fn contains(range: Range<int>, value: int) -> bool;
/// Return `true` if a value falls within the inclusive range.
///
/// This function also drives the `in` operator.
///
/// # Example
///
/// ```rhai
/// let r = 1..=100;
///
/// // The 'in' operator calls 'contains' in the background
/// if 42 in r {
/// print("found!");
/// }
/// ```
fn contains(range: RangeInclusive<int>, value: int) -> bool;
/// Return `true` if a key exists within the object map.
///
/// This function also drives the `in` operator.
///
/// # Example
///
/// ```rhai
/// let m = #{a:1, b:2, c:3};
///
/// // The 'in' operator calls 'contains' in the background
/// if "c" in m {
/// print("found!");
/// }
/// ```
fn contains(map: Map, string: String) -> bool;
/// Return `true` if a value is found within the BLOB.
///
/// This function also drives the `in` operator.
///
/// # Example
///
/// ```rhai
/// let b = blob();
///
/// b += 1; b += 2; b += 3; b += 4; b += 5;
///
/// // The 'in' operator calls 'contains' in the background
/// if 3 in b {
/// print("found!");
/// }
/// ```
fn contains(blob: Blob, value: int) -> bool;

View File

@@ -1,5 +0,0 @@
module static;
let hello_there: string;
const HELLO: string;

View File

@@ -1,6 +0,0 @@
module general_kenobi;
const CONSTANT: int;
/// Returns a string where "hello there" is repeated `n` times.
fn hello_there(n: int) -> String;

View File

@@ -1,49 +0,0 @@
{
"modules": {
"general_kenobi": {
"functions": [
{
"baseHash": 3873007749982070651,
"fullHash": 5865213555928423624,
"namespace": "internal",
"access": "public",
"name": "hello_there",
"type": "native",
"numParams": 1,
"params": [
{
"name": "n",
"type": "i64"
}
],
"returnType": "String",
"signature": "hello_there(n: i64) -> String",
"docComments": [
"/// Returns a string where \"hello there\" is repeated `n` times."
]
}
]
}
},
"functions": [
{
"baseHash": 12461724250411739075,
"fullHash": 14530626537296006176,
"namespace": "global",
"access": "public",
"name": "minus",
"type": "native",
"numParams": 2,
"params": [
{
"type": "i64"
},
{
"type": "i64"
}
],
"returnType": "i64",
"signature": "minus(_: i64, _: i64) -> i64"
}
]
}

View File

@@ -1,70 +0,0 @@
use rhai::plugin::*;
use rhai::{Engine, EvalAltResult, Scope};
#[export_module]
pub mod general_kenobi {
/// General Kenobi's Constant.
pub const CONSTANT: i64 = 42;
/// Returns a string where "hello there" is repeated `n` times.
pub fn hello_there(n: i64) -> String {
use std::convert::TryInto;
"hello there ".repeat(n.try_into().unwrap())
}
}
fn main() -> Result<(), Box<EvalAltResult>> {
let mut engine = Engine::new();
let mut scope = Scope::new();
// This variable will also show up in the definitions, since it will be part of the scope.
scope.push("hello_there", "hello there");
// This constant will also show up in the definitions, since it will be part of the scope.
scope.push_constant("HELLO", "hello there");
#[cfg(not(feature = "no_module"))]
engine.register_static_module("general_kenobi", exported_module!(general_kenobi).into());
// Custom operators also show up in definitions.
#[cfg(not(feature = "no_custom_syntax"))]
{
engine.register_custom_operator("minus", 100).unwrap();
engine.register_fn("minus", |a: i64, b: i64| a - b);
}
engine.run_with_scope(
&mut scope,
"hello_there = general_kenobi::hello_there(4 minus 2);",
)?;
// Generate definitions for the contents of the engine and the scope.
engine
.definitions_with_scope(&scope)
.write_to_dir("examples/definitions/.rhai/definitions")
.unwrap();
// Alternatively we can write all of the above to a single file.
engine
.definitions_with_scope(&scope)
.write_to_file("examples/definitions/.rhai/all_in_one.d.rhai")
.unwrap();
// Skip standard packages if not needed (e.g. they are provided elsewhere).
engine
.definitions_with_scope(&scope)
.include_standard_packages(false)
.write_to_file("examples/definitions/.rhai/all_in_one_without_standard.d.rhai")
.unwrap();
// Write function definitions as JSON.
let json = engine
.definitions()
.include_standard_packages(false)
.json()
.unwrap();
std::fs::write("examples/definitions/.rhai/defs.json", json).unwrap();
Ok(())
}

View File

@@ -1,3 +0,0 @@
// The following will be valid based on the definitions.
hello_there = general_kenobi::hello_there(123);
print(hello_there);

View File

@@ -1,168 +0,0 @@
//! Implementation of the Event Handler With State Pattern - JS Style
#[cfg(any(feature = "no_function", feature = "no_object"))]
pub fn main() {
panic!("This example does not run under 'no_function' or 'no_object'.")
}
#[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "no_object"))]
pub fn main() {
use rhai::{CallFnOptions, Dynamic, Engine, Map, Scope, AST};
use std::io::{stdin, stdout, Write};
const SCRIPT_FILE: &str = "event_handler_js/script.rhai";
#[derive(Debug)]
struct Handler {
pub engine: Engine,
pub scope: Scope<'static>,
pub states: Dynamic,
pub ast: AST,
}
fn print_scope(scope: &Scope) {
for (i, (name, constant, value)) in scope.iter_raw().enumerate() {
#[cfg(not(feature = "no_closure"))]
let value_is_shared = if value.is_shared() { " (shared)" } else { "" };
#[cfg(feature = "no_closure")]
let value_is_shared = "";
println!(
"[{}] {}{}{} = {:?}",
i + 1,
if constant { "const " } else { "" },
name,
value_is_shared,
*value.read_lock::<Dynamic>().unwrap(),
)
}
println!();
}
println!("Events Handler Example - JS Style");
println!("==================================");
let mut input = String::new();
// Read script file
print!("Script file [{}]: ", SCRIPT_FILE);
stdout().flush().expect("flush stdout");
input.clear();
stdin().read_line(&mut input).expect("read input");
let path = match input.trim() {
"" => SCRIPT_FILE,
path => path,
};
// Create Engine
let engine = Engine::new();
// Use an object map to hold state
let mut states = Map::new();
// Default states can be added
states.insert("bool_state".into(), Dynamic::FALSE);
// Convert the object map into 'Dynamic'
let mut states: Dynamic = states.into();
// Create a custom 'Scope' to hold state
let mut scope = Scope::new();
// Add any system-provided state into the custom 'Scope'.
// Constants can be used to optimize the script.
scope.push_constant("MY_CONSTANT", 42_i64);
// Compile the handler script.
println!("> Loading script file: {path}");
let ast = match engine.compile_file_with_scope(&scope, path.into()) {
Ok(ast) => ast,
Err(err) => {
eprintln!("! Error: {err}");
println!("Cannot continue. Bye!");
return;
}
};
println!("> Script file loaded.");
println!();
println!("quit = exit program");
println!("scope = print scope");
println!("states = print states");
println!("event arg = run function with argument");
println!();
// Run the 'init' function to initialize the state, retaining variables.
let options = CallFnOptions::new()
.eval_ast(false)
.bind_this_ptr(&mut states);
let result = engine.call_fn_with_options::<()>(options, &mut scope, &ast, "init", ());
if let Err(err) = result {
eprintln!("! {err}")
}
// Create handler instance
let mut handler = Handler {
engine,
scope,
states,
ast,
};
// Events loop
loop {
print!("event> ");
stdout().flush().expect("flush stdout");
// Read event
input.clear();
stdin().read_line(&mut input).expect("read input");
let mut fields = input.trim().splitn(2, ' ');
let event = fields.next().expect("event").trim();
let arg = fields.next().unwrap_or("").to_string();
// Process event
match event {
"quit" => break,
"scope" => {
print_scope(&handler.scope);
continue;
}
"states" => {
println!("{:?}", handler.states);
println!();
continue;
}
// Map all other events to function calls
_ => {
let engine = &handler.engine;
let scope = &mut handler.scope;
let ast = &handler.ast;
let options = CallFnOptions::new()
.eval_ast(false)
.bind_this_ptr(&mut handler.states);
let result = engine.call_fn_with_options::<()>(options, scope, ast, event, (arg,));
if let Err(err) = result {
eprintln!("! {err}")
}
}
}
}
println!("Bye!");
}

View File

@@ -1,50 +0,0 @@
//! Implementation of the Event Handler With State Pattern - JS Style
/// Initialize user-provided state.
fn init() {
// Can detect system-provided default states!
// Add 'bool_state' as new state variable if one does not exist
if "bool_state" !in this {
this.bool_state = false;
}
// Add 'value' as new state variable (overwrites any existing)
this.value = 0;
// Can also add OOP-style functions!
this.log = |x| print(`State = ${this.value}, data = ${x}`);
}
/// 'start' event handler
fn start(data) {
if this.bool_state {
throw "Already started!";
}
if this.value <= 0 {
throw "Conditions not yet ready to start!";
}
// Constant 'MY_CONSTANT' in custom scope is also visible!
print(`MY_CONSTANT = ${MY_CONSTANT}`);
this.value += parse_int(data);
this.bool_state = true;
}
/// 'end' event handler
fn end(data) {
if !this.bool_state {
throw "Not yet started!";
}
if this.value > 0 {
throw "Conditions not yet ready to end!";
}
this.value = parse_int(data);
this.bool_state = false;
}
/// 'update' event handler
fn update(data) {
let data = parse_int(data);
this.value += data;
this.log(data);
}

View File

@@ -1,139 +0,0 @@
//! Implementation of the Event Handler With State Pattern - Main Style
#[cfg(feature = "no_function")]
pub fn main() {
panic!("This example does not run under 'no_function'.")
}
#[cfg(not(feature = "no_function"))]
pub fn main() {
use rhai::{CallFnOptions, Dynamic, Engine, Scope, AST};
use std::io::{stdin, stdout, Write};
const SCRIPT_FILE: &str = "event_handler_main/script.rhai";
#[derive(Debug)]
struct Handler {
pub engine: Engine,
pub scope: Scope<'static>,
pub ast: AST,
}
fn print_scope(scope: &Scope) {
for (i, (name, constant, value)) in scope.iter_raw().enumerate() {
#[cfg(not(feature = "no_closure"))]
let value_is_shared = if value.is_shared() { " (shared)" } else { "" };
#[cfg(feature = "no_closure")]
let value_is_shared = "";
println!(
"[{}] {}{}{} = {:?}",
i + 1,
if constant { "const " } else { "" },
name,
value_is_shared,
*value.read_lock::<Dynamic>().unwrap(),
)
}
println!();
}
println!("Events Handler Example - Main Style");
println!("===================================");
let mut input = String::new();
// Read script file
print!("Script file [{SCRIPT_FILE}]: ");
stdout().flush().expect("flush stdout");
input.clear();
stdin().read_line(&mut input).expect("read input");
let path = match input.trim() {
"" => SCRIPT_FILE,
path => path,
};
// Create Engine
let engine = Engine::new();
// Create a custom 'Scope' to hold state
let mut scope = Scope::new();
// Add any system-provided state into the custom 'Scope'.
// Constants can be used to optimize the script.
scope.push_constant("MY_CONSTANT", 42_i64);
// Compile the handler script.
println!("> Loading script file: {path}");
let ast = match engine.compile_file_with_scope(&scope, path.into()) {
Ok(ast) => ast,
Err(err) => {
eprintln!("! Error: {}", err);
println!("Cannot continue. Bye!");
return;
}
};
println!("> Script file loaded.");
println!();
println!("quit = exit program");
println!("scope = print scope");
println!("event arg = run function with argument");
println!();
// Run the 'init' function to initialize the state, retaining variables.
let options = CallFnOptions::new().eval_ast(false).rewind_scope(false);
let result = engine.call_fn_with_options::<()>(options, &mut scope, &ast, "init", ());
if let Err(err) = result {
eprintln!("! {err}")
}
// Create handler instance
let mut handler = Handler { engine, scope, ast };
// Events loop
loop {
print!("event> ");
stdout().flush().expect("flush stdout");
// Read event
input.clear();
stdin().read_line(&mut input).expect("read input");
let mut fields = input.trim().splitn(2, ' ');
let event = fields.next().expect("event").trim();
let arg = fields.next().unwrap_or("").to_string();
// Process event
match event {
"quit" => break,
"scope" => {
print_scope(&handler.scope);
continue;
}
// Map all other events to function calls
_ => {
let engine = &handler.engine;
let scope = &mut handler.scope;
let ast = &handler.ast;
let result = engine.call_fn::<()>(scope, ast, event, (arg,));
if let Err(err) = result {
eprintln!("! {err}")
}
}
}
}
println!("Bye!");
}

View File

@@ -1,56 +0,0 @@
//! Implementation of the Event Handler With State Pattern - Main Style
/// Initialize user-provided state (shadows system-provided state, if any).
fn init() {
// Add 'bool_state' and 'value' as new state variables
let bool_state = false;
let value = 0;
// Constants can also be added!
const EXTRA_CONSTANT = "hello, world!";
}
/// Without 'OOP' support, the can only be a function.
fn log(value, data) {
print(`State = ${value}, data = ${data}`);
}
/// 'start' event handler
fn start(data) {
if bool_state {
throw "Already started!";
}
if value <= 0 {
throw "Conditions not yet ready to start!";
}
// Constants 'MY_CONSTANT' and 'EXTRA_CONSTANT'
// in custom scope are also visible!
print(`MY_CONSTANT = ${MY_CONSTANT}`);
print(`EXTRA_CONSTANT = ${EXTRA_CONSTANT}`);
value += parse_int(data);
bool_state = true;
}
/// 'end' event handler
fn end(data) {
if !bool_state {
throw "Not yet started!";
}
if value > 0 {
throw "Conditions not yet ready to end!";
}
value = parse_int(data);
bool_state = false;
}
/// 'update' event handler
fn update(data) {
let data = parse_int(data);
value += data;
// Without OOP support, can only call function
log(value, data);
}

View File

@@ -1,151 +0,0 @@
//! Implementation of the Event Handler With State Pattern - Map Style
#[cfg(any(feature = "no_function", feature = "no_object"))]
pub fn main() {
panic!("This example does not run under 'no_function' or 'no_object'.")
}
#[cfg(not(feature = "no_function"))]
#[cfg(not(feature = "no_object"))]
pub fn main() {
use rhai::{Dynamic, Engine, Map, Scope, AST};
use std::io::{stdin, stdout, Write};
const SCRIPT_FILE: &str = "event_handler_map/script.rhai";
#[derive(Debug)]
struct Handler {
pub engine: Engine,
pub scope: Scope<'static>,
pub ast: AST,
}
fn print_scope(scope: &Scope) {
for (i, (name, constant, value)) in scope.iter_raw().enumerate() {
#[cfg(not(feature = "no_closure"))]
let value_is_shared = if value.is_shared() { " (shared)" } else { "" };
#[cfg(feature = "no_closure")]
let value_is_shared = "";
println!(
"[{}] {}{}{} = {:?}",
i + 1,
if constant { "const " } else { "" },
name,
value_is_shared,
*value.read_lock::<Dynamic>().unwrap(),
)
}
println!();
}
println!("Events Handler Example - Map Style");
println!("==================================");
let mut input = String::new();
// Read script file
print!("Script file [{}]: ", SCRIPT_FILE);
stdout().flush().expect("flush stdout");
input.clear();
stdin().read_line(&mut input).expect("read input");
let path = match input.trim() {
"" => SCRIPT_FILE,
path => path,
};
// Create Engine
let mut engine = Engine::new();
// Prevent shadowing of `state`
#[allow(deprecated)]
engine.on_def_var(|_, info, _| Ok(info.name() != "state"));
// Create a custom 'Scope' to hold state
let mut scope = Scope::new();
// Add any system-provided state into the custom 'Scope'.
// Constants can be used to optimize the script.
scope.push_constant("MY_CONSTANT", 42_i64);
// Use an object map to hold state
let mut states = Map::new();
// Default states can be added
states.insert("bool_state".into(), Dynamic::FALSE);
// Add the main states-holding object map and call it 'state'
scope.push("state", states);
// Compile the handler script.
println!("> Loading script file: {path}");
let ast = match engine.compile_file_with_scope(&scope, path.into()) {
Ok(ast) => ast,
Err(err) => {
eprintln!("! Error: {err}");
println!("Cannot continue. Bye!");
return;
}
};
println!("> Script file loaded.");
println!();
println!("quit = exit program");
println!("scope = print scope");
println!("event arg = run function with argument");
println!();
// Run the 'init' function to initialize the state, retaining variables.
let result = engine.call_fn::<()>(&mut scope, &ast, "init", ());
if let Err(err) = result {
eprintln!("! {err}")
}
// Create handler instance
let mut handler = Handler { engine, scope, ast };
// Events loop
loop {
print!("event> ");
stdout().flush().expect("flush stdout");
// Read event
input.clear();
stdin().read_line(&mut input).expect("read input");
let mut fields = input.trim().splitn(2, ' ');
let event = fields.next().expect("event").trim();
let arg = fields.next().unwrap_or("").to_string();
// Process event
match event {
"quit" => break,
"scope" => {
print_scope(&handler.scope);
continue;
}
// Map all other events to function calls
_ => {
let engine = &handler.engine;
let scope = &mut handler.scope;
let ast = &handler.ast;
let result = engine.call_fn::<()>(scope, ast, event, (arg,));
if let Err(err) = result {
eprintln!("! {err}")
}
}
}
}
println!("Bye!");
}

View File

@@ -1,58 +0,0 @@
//! Implementation of the Event Handler With State Pattern - Map Style
/// Initialize user-provided state.
/// State is stored inside an object map bound to 'state'.
fn init() {
// Add 'bool_state' as new state variable if one does not exist
if "bool_state" !in state {
state.bool_state = false;
}
// Add 'obj_state' as new state variable (overwrites any existing)
state.value = 0;
// Can also add OOP-style functions!
state.log = |x| print(`State = ${this.value}, data = ${x}`);
}
/// 'start' event handler
fn start(data) {
// Can detect system-provided default states!
// Access state variables in 'state'
if state.bool_state {
throw "Already started!";
}
// New values can be added to the state
state.start_mode = data;
if state.value <= 0 {
throw "Conditions not yet ready to start!";
}
// Constant 'MY_CONSTANT' in custom scope is also visible!
print(`MY_CONSTANT = ${MY_CONSTANT}`);
state.value = parse_int(data);
state.bool_state = true;
}
/// 'end' event handler
fn end(data) {
if !state.bool_state || "start_mode" !in state {
throw "Not yet started!";
}
if state.value > 0 {
throw "Conditions not yet ready to end!";
}
state.value = parse_int(data);
state.bool_state = false;
}
/// 'update' event handler
fn update(data) {
let data = parse_int(data);
state.value += data;
// Call user-defined function OOP-style!
state.log(data);
}

View File

@@ -1,15 +0,0 @@
//! A simple example that evaluates an expression and prints the result.
use rhai::{Engine, EvalAltResult};
fn main() -> Result<(), Box<EvalAltResult>> {
let engine = Engine::new();
engine.run(r#"print("hello, world!")"#)?;
let result = engine.eval::<i64>("40 + 2")?;
println!("The Answer: {result}"); // prints 42
Ok(())
}

View File

@@ -1,112 +0,0 @@
//! An advanced example showing how to pause/resume/stop an `Engine` via an MPSC channel.
#[cfg(feature = "unchecked")]
fn main() {
panic!("This example does not run under 'unchecked'.");
}
use rhai::{Dynamic, Engine};
#[cfg(feature = "sync")]
use std::sync::Mutex;
#[cfg(not(feature = "unchecked"))]
fn main() {
let (tx, rx) = std::sync::mpsc::channel::<String>();
#[cfg(feature = "sync")]
let rx = Mutex::new(rx);
// Spawn thread with Engine, capturing the channel
std::thread::spawn(move || {
// Create Engine
let mut engine = Engine::new();
engine.on_progress(move |_ops| {
#[cfg(feature = "sync")]
if _ops % 5 != 0 {
return None;
}
#[cfg(feature = "sync")]
let rx = &*rx.lock().unwrap();
let mut paused = false;
loop {
match rx.try_recv() {
Ok(cmd) => match cmd.as_str() {
"pause" => {
println!("[Thread] Script paused. Type 'resume' to continue or 'stop' to terminate.");
paused = true;
}
"resume" => {
println!("[Thread] Resuming script...");
return None;
}
"stop" => {
println!("[Thread] Stopping script...");
return Some(Dynamic::UNIT);
}
cmd if paused => {
println!("[Thread] I don't understand '{cmd}'!");
println!("Type 'resume' to continue script, or 'stop' to terminate!");
}
_ => {
println!("[Thread] I don't understand '{cmd}'!");
return None;
}
},
Err(_) if paused => (),
Err(_) => return None,
}
std::thread::sleep(std::time::Duration::from_millis(100));
}
});
// Run script
let _ = engine
.run(
r#"
let counter = 0;
loop {
print("[Script] One Potato...");
sleep(1);
counter += 1;
print("[Script] Two Potatoes...");
sleep(1);
print(`[Script] Boring Counter: ${counter}...`);
sleep(1);
print("[Script] Three Potatoes...");
sleep(1);
}
"#,
)
.expect_err("Error expected");
println!("[Thread] Script stopped!");
});
println!("[Main] Type 'pause' or 'stop' to control the script.");
let mut input = String::new();
loop {
input.clear();
match std::io::stdin().read_line(&mut input) {
Ok(0) => (),
Ok(_) => match tx.send(input.trim().to_string()) {
Ok(_) => (),
Err(_) => break,
},
Err(_) => break,
}
}
}

View File

@@ -1,22 +0,0 @@
//! An example that evaluates two pieces of code in separate runs, but using a common `Scope`.
use rhai::{Engine, EvalAltResult, Scope};
fn main() -> Result<(), Box<EvalAltResult>> {
let engine = Engine::new();
let mut scope = Scope::new();
engine.run_with_scope(&mut scope, "let x = 4 + 5")?;
println!("x = {}", scope.get_value::<i64>("x").unwrap());
for _ in 0..10 {
let result = engine.eval_with_scope::<i64>(&mut scope, "x += 1; x")?;
println!("result: {result}");
}
println!("x = {}", scope.get_value::<i64>("x").unwrap());
Ok(())
}

View File

@@ -1,86 +0,0 @@
//! An example to serialize and deserialize Rust types.
#[cfg(feature = "no_object")]
fn main() {
panic!("This example does not run under 'no_object'.")
}
#[cfg(not(feature = "no_object"))]
fn main() {
use rhai::serde::{from_dynamic, to_dynamic};
use rhai::{Dynamic, Engine, Map};
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
struct Point {
x: f64,
y: f64,
}
#[derive(Debug, Clone, PartialEq, Serialize, Deserialize)]
struct MyStruct {
a: i64,
b: Vec<String>,
c: bool,
d: Point,
}
pub fn ser() {
let x = MyStruct {
a: 42,
b: vec!["hello".into(), "world".into()],
c: true,
d: Point {
x: 123.456,
y: 999.0,
},
};
println!("Source struct: {x:#?}");
// Convert the 'MyStruct' into a 'Dynamic'
let map: Dynamic = to_dynamic(x).unwrap();
assert!(map.is::<Map>());
println!("Serialized to Dynamic: {map:#?}");
}
pub fn de() {
let engine = Engine::new();
let result: Dynamic = engine
.eval(
r#"
#{
a: 42,
b: [ "hello", "world" ],
c: true,
d: #{ x: 123.456, y: 999.0 }
}
"#,
)
.unwrap();
println!("Source Dynamic: {result:#?}");
// Convert the 'Dynamic' object map into 'MyStruct'
let x: MyStruct = from_dynamic(&result).unwrap();
assert_eq!(
x,
MyStruct {
a: 42,
b: vec!["hello".into(), "world".into()],
c: true,
d: Point {
x: 123.456,
y: 999.0,
},
}
);
println!("Deserialized to struct: {x:#?}");
}
ser();
println!();
de();
}

View File

@@ -1,19 +0,0 @@
//! An example showing how to register a simple Rust function.
use rhai::{Engine, EvalAltResult};
fn add(x: i64, y: i64) -> i64 {
x + y
}
fn main() -> Result<(), Box<EvalAltResult>> {
let mut engine = Engine::new();
engine.register_fn("add", add);
let result = engine.eval::<i64>("add(40, 2)")?;
println!("Answer: {result}"); // prints 42
Ok(())
}

View File

@@ -1,79 +0,0 @@
//! An example that registers a variety of functions that operate on strings.
//! Remember to use `ImmutableString` or `&str` instead of `String` as parameters.
use rhai::{Engine, EvalAltResult, ImmutableString, Scope};
use std::io::{stdin, stdout, Write};
/// Trim whitespace from a string. The original string argument is changed.
///
/// This version uses `&mut ImmutableString`
fn trim_string(s: &mut ImmutableString) {
*s = s.trim().into();
}
/// Notice this is different from the built-in Rhai 'len' function for strings
/// which counts the actual number of Unicode _characters_ in a string.
///
/// This version simply counts the number of _bytes_ in the UTF-8 representation.
///
/// This version uses `&str`.
fn count_string_bytes(s: &str) -> i64 {
s.len() as i64
}
/// This version uses `ImmutableString` and `&str`.
fn find_substring(s: ImmutableString, sub: &str) -> i64 {
s.find(sub).map(|x| x as i64).unwrap_or(-1)
}
fn main() -> Result<(), Box<EvalAltResult>> {
// Create a `raw` Engine with no built-in string functions.
let mut engine = Engine::new_raw();
engine
// Register string functions
.register_fn("trim", trim_string)
.register_fn("len", count_string_bytes)
.register_fn("index_of", find_substring)
// Register string functions using closures
.register_fn("display", |label: &str, value: i64| {
println!("{label}: {value}")
})
.register_fn("display", |label: ImmutableString, value: &str| {
println!(r#"{label}: "{value}""#) // Quote the input string
});
let mut scope = Scope::new();
let mut input = String::new();
loop {
scope.clear();
println!("Type something. Press Ctrl-C to exit.");
print!("strings> ");
stdout().flush().expect("couldn't flush stdout");
input.clear();
if let Err(err) = stdin().read_line(&mut input) {
panic!("input error: {}", err);
}
scope.push("x", input.clone());
println!("Line: {}", input.replace('\r', "\\r").replace('\n', "\\n"));
engine.run_with_scope(
&mut scope,
r#"
display("Length", x.len());
x.trim();
display("Trimmed", x);
display("Trimmed Length", x.len());
display("Index of \"!!!\"", x.index_of("!!!"));
"#,
)?;
println!();
}
}

View File

@@ -1,69 +0,0 @@
//! An advanced example showing how to communicate with an `Engine` running in a separate thread via
//! an MPSC channel.
use rhai::Engine;
#[cfg(feature = "sync")]
use std::sync::Mutex;
fn main() {
// Channel: Script -> Master
let (tx_script, rx_master) = std::sync::mpsc::channel();
// Channel: Master -> Script
let (tx_master, rx_script) = std::sync::mpsc::channel();
#[cfg(feature = "sync")]
let (tx_script, rx_script) = (Mutex::new(tx_script), Mutex::new(rx_script));
// Spawn thread with Engine
std::thread::spawn(move || {
// Create Engine
let mut engine = Engine::new();
// Register API
// Notice that the API functions are blocking
#[cfg(not(feature = "sync"))]
engine
.register_fn("get", move || rx_script.recv().unwrap_or_default())
.register_fn("put", move |v: i64| tx_script.send(v).unwrap());
#[cfg(feature = "sync")]
engine
.register_fn("get", move || rx_script.lock().unwrap().recv().unwrap())
.register_fn("put", move |v: i64| {
tx_script.lock().unwrap().send(v).unwrap()
});
// Run script
engine
.run(
r#"
print("Starting script loop...");
loop {
let x = get();
print(`Script Read: ${x}`);
x += 1;
print(`Script Write: ${x}`);
put(x);
}
"#,
)
.unwrap();
});
// This is the main processing thread
println!("Starting main loop...");
let mut value: i64 = 0;
while value < 10 {
println!("Value: {value}");
// Send value to script
tx_master.send(value).unwrap();
// Receive value from script
value = rx_master.recv().unwrap();
}
}