Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 24 additions & 1 deletion CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,7 +1,30 @@
Rhai Release Notes
==================

Version 1.23.0
Version 1.24.0
==============

Bug fixes
---------

* The binary bit-wise operators `&`, `|` and `^` now work correctly with `INT` operands.
* The methods `contains`, `get`, `filter` and `to_json` for object maps are now marked pure.
* The methods `contains`, `get`, `parse_le_int`, `parse_be_int`, `parse_le_float` and `parse_be_float` for BLOB's are now marked pure.

Enhancements
------------

* The method `map` is added to object maps.


Version 1.23.3
==============

This version maintains compatibility by restricting the [`ahash`](https://crates.io/crates/ahash)
dependency to `<=0.8.11` because higher versions break `no-std` builds.


Version 1.23.4
==============

Bug fixes
Expand Down
2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ members = [".", "codegen"]

[package]
name = "rhai"
version = "1.23.0"
version = "1.23.4"
rust-version = "1.66.0"
edition = "2018"
resolver = "2"
Expand Down
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,16 @@ Targets and builds
* Minimum Rust version 1.66.0


Versions
--------

The [`ahash`](https://crates.io/crates/ahash) crate that Rhai depends on has a breaking change since version `0.8.12` which bumps [`getrandom`](https://crates.io/crates/getrandom) to version `0.3`, braking certain `no-std` and `wasm` builds.

Version [`1.23.3`](https://crates.io/crates/rhai/1.23.3): Use this version when building for `no-std`

Version [`1.23.4`](https://crates.io/crates/rhai/1.23.4): This is the main version for `std` builds.


Standard features
-----------------

Expand Down
27 changes: 14 additions & 13 deletions build.rs
Original file line number Diff line number Diff line change
@@ -1,28 +1,29 @@
use std::env;
use std::{
env,
fs::File,
io::{Read, Write},
};

fn main() {
let out_dir = env::var_os("OUT_DIR").unwrap();

// Tell Cargo that if the given environment variable changes, to rerun this build script.
println!("cargo:rerun-if-changed=build.template");
println!("cargo:rerun-if-env-changed=RHAI_AHASH_SEED");
println!("cargo:rerun-if-env-changed=RHAI_HASHING_SEED");
let mut contents = String::new();

let mut contents =
std::fs::read_to_string("build.template").expect("cannot read from `build.template`");
File::open("build.template")
.expect("cannot open `build.template`")
.read_to_string(&mut contents)
.expect("cannot read from `build.template`");

let seed = env::var("RHAI_HASHING_SEED")
.or_else(|_| env::var("RHAI_AHASH_SEED"))
.map_or_else(|_| "None".into(), |s| format!("Some({s})"));

contents = contents.replace("{{HASHING_SEED}}", &seed);

let hashing_env_path = std::path::Path::new(&out_dir).join("hashing_env.rs");

std::fs::write(&hashing_env_path, contents).unwrap_or_else(|error| {
panic!(
"cannot write to `{}`: {error:?}",
hashing_env_path.display()
)
});
File::create("src/config/hashing_env.rs")
.expect("cannot create `hashing_env.rs`")
.write_all(contents.as_bytes())
.expect("cannot write to `config/hashing_env.rs`");
}
2 changes: 2 additions & 0 deletions build.template
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
//! This file is automatically recreated during build time by `build.rs` from `build.template`.

pub const HASHING_SEED: Option<[u64; 4]> = {{HASHING_SEED}};
2 changes: 1 addition & 1 deletion codegen/ui_tests/export_mod_raw_return.stderr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
error[E0599]: `bool` is not an iterator
--> ui_tests/export_mod_raw_return.rs:12:33
|
9 | #[export_module]
9 | #[export_module]
| ---------------- in this procedural macro expansion
...
12 | pub fn test_fn(input: Point) -> bool {
Expand Down
4 changes: 2 additions & 2 deletions codegen/ui_tests/non_clonable.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ note: required by a bound in `rhai::Dynamic::cast`
| ^^^^^ required by this bound in `Dynamic::cast`
help: consider annotating `NonClonable` with `#[derive(Clone)]`
|
4 + #[derive(Clone)]
5 | struct NonClonable {
4 + #[derive(Clone)]
5 | struct NonClonable {
|
4 changes: 2 additions & 2 deletions codegen/ui_tests/non_clonable_second.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ note: required by a bound in `rhai::Dynamic::cast`
| ^^^^^ required by this bound in `Dynamic::cast`
help: consider annotating `NonClonable` with `#[derive(Clone)]`
|
4 + #[derive(Clone)]
5 | struct NonClonable {
4 + #[derive(Clone)]
5 | struct NonClonable {
|
4 changes: 2 additions & 2 deletions codegen/ui_tests/rhai_fn_non_clonable_return.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,6 @@ note: required by a bound in `rhai::Dynamic::from`
= note: this error originates in the attribute macro `export_fn` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `NonClonable` with `#[derive(Clone)]`
|
4 + #[derive(Clone)]
5 | struct NonClonable {
4 + #[derive(Clone)]
5 | struct NonClonable {
|
7 changes: 2 additions & 5 deletions codegen/ui_tests/rhai_mod_inner_cfg_false.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -7,13 +7,10 @@ error[E0433]: failed to resolve: could not find `test_mod` in `test_module`
note: found an item that was configured out
--> ui_tests/rhai_mod_inner_cfg_false.rs:12:13
|
11 | #[cfg(feature = "unset_feature")]
| ------------------------- the item is gated behind the `unset_feature` feature
12 | pub mod test_mod {
| ^^^^^^^^
note: the item is gated behind the `unset_feature` feature
--> ui_tests/rhai_mod_inner_cfg_false.rs:11:11
|
11 | #[cfg(feature = "unset_feature")]
| ^^^^^^^^^^^^^^^^^^^^^^^^^

warning: unexpected `cfg` condition value: `unset_feature`
--> ui_tests/rhai_mod_inner_cfg_false.rs:11:11
Expand Down
6 changes: 3 additions & 3 deletions codegen/ui_tests/rhai_mod_non_clonable_return.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ note: required by a bound in `rhai::Dynamic::from`
| ^^^^^ required by this bound in `Dynamic::from`
= note: this error originates in the attribute macro `export_module` (in Nightly builds, run with -Z macro-backtrace for more info)
help: consider annotating `NonClonable` with `#[derive(Clone)]`
|
3 + #[derive(Clone)]
4 | struct NonClonable {
|
3 + #[derive(Clone)]
4 | struct NonClonable {
|
2 changes: 1 addition & 1 deletion codegen/ui_tests/rhai_mod_unknown_type.stderr
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
error[E0412]: cannot find type `Pointer` in this scope
--> ui_tests/rhai_mod_unknown_type.rs:12:27
|
4 | pub struct Point {
4 | pub struct Point {
| ---------------- similarly named struct `Point` defined here
...
12 | pub fn test_fn(input: Pointer) -> bool {
Expand Down
4 changes: 3 additions & 1 deletion src/config/hashing_env.rs
Original file line number Diff line number Diff line change
@@ -1 +1,3 @@
include!(concat!(env!("OUT_DIR"), "/hashing_env.rs"));
//! This file is automatically recreated during build time by `build.rs` from `build.template`.

pub const HASHING_SEED: Option<[u64; 4]> = None;
12 changes: 12 additions & 0 deletions src/func/builtin.rs
Original file line number Diff line number Diff line change
Expand Up @@ -293,6 +293,9 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
PowerOf => return impl_op!(INT => power(as_int, as_int)),
RightShift => return impl_op!(INT => Ok(shift_right(as_int, as_int))),
LeftShift => return impl_op!(INT => Ok(shift_left(as_int, as_int))),
Ampersand => return impl_op!(INT => Ok(binary_and(as_int, as_int))),
Pipe => return impl_op!(INT => Ok(binary_or(as_int, as_int))),
XOr => return impl_op!(INT => Ok(binary_xor(as_int, as_int))),
_ => (),
}

Expand Down Expand Up @@ -324,6 +327,9 @@ pub fn get_builtin_binary_op_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Option<
false,
))
}
Ampersand => return impl_op!(INT => as_int & as_int),
Pipe => return impl_op!(INT => as_int | as_int),
XOr => return impl_op!(INT => as_int ^ as_int),
_ => (),
}

Expand Down Expand Up @@ -811,6 +817,9 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
PowerOfAssign => return impl_op!(INT => power(as_int, as_int)),
RightShiftAssign => return impl_op!(INT => Ok(shift_right(as_int, as_int))),
LeftShiftAssign => return impl_op!(INT => Ok(shift_left(as_int, as_int))),
AndAssign => return impl_op!(INT => Ok(binary_and(as_int, as_int))),
OrAssign => return impl_op!(INT => Ok(binary_or(as_int, as_int))),
XOrAssign => return impl_op!(INT => Ok(binary_xor(as_int, as_int))),
_ => (),
}

Expand Down Expand Up @@ -846,6 +855,9 @@ pub fn get_builtin_op_assignment_fn(op: &Token, x: &Dynamic, y: &Dynamic) -> Opt
false,
))
}
AndAssign => return impl_op!(INT &= as_int),
OrAssign => return impl_op!(INT |= as_int),
XOrAssign => return impl_op!(INT ^= as_int),
_ => (),
}

Expand Down
25 changes: 20 additions & 5 deletions src/packages/arithmetic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -198,9 +198,21 @@ def_package! {
pub ArithmeticPackage(lib) {
lib.set_standard_lib(true);

combine_with_exported_module!(lib, "int", int_functions);
// Only register integer functions that are not built-in
combine_with_exported_module!(lib, "int", non_builtin_int_functions);

// Avoid dead code warnings
#[cfg(not(feature = "unchecked"))]
{
let _ = arith_basic::INT::functions::is_zero;
let _ = arith_basic::INT::functions::is_odd;
let _ = arith_basic::INT::functions::is_even;
}

// Register other arithmetic functions for integers
reg_functions!(lib += signed_basic; INT);

// Basic arithmetic for other integer types
#[cfg(not(feature = "only_i32"))]
#[cfg(not(feature = "only_i64"))]
{
Expand Down Expand Up @@ -231,8 +243,14 @@ def_package! {
}
}

#[cfg(not(feature = "unchecked"))]
gen_arithmetic_functions!(arith_basic => INT);

gen_signed_functions!(signed_basic => INT);

/// These integer functions are not part of the built-in set so they must be registered.
#[export_module]
mod int_functions {
mod non_builtin_int_functions {
/// Return true if the number is zero.
#[rhai_fn(get = "is_zero", name = "is_zero")]
pub const fn is_zero(x: INT) -> bool {
Expand All @@ -250,9 +268,6 @@ mod int_functions {
}
}

gen_arithmetic_functions!(arith_basic => INT);
gen_signed_functions!(signed_basic => INT);

#[cfg(not(feature = "no_float"))]
#[export_module]
mod f32_functions {
Expand Down
23 changes: 14 additions & 9 deletions src/packages/blob_basic.rs
Original file line number Diff line number Diff line change
Expand Up @@ -155,7 +155,7 @@ pub mod blob_functions {
///
/// print(text.contains('x')); // prints false
/// ```
#[rhai_fn(name = "contains")]
#[rhai_fn(name = "contains", pure)]
pub fn contains(blob: &mut Blob, value: INT) -> bool {
blob.contains(&u8::try_from(value & 0x00ff).unwrap())
}
Expand All @@ -178,6 +178,7 @@ pub mod blob_functions {
///
/// print(b.get(99)); // prints 0
/// ```
#[rhai_fn(pure)]
pub fn get(blob: &mut Blob, index: INT) -> INT {
if blob.is_empty() {
return 0;
Expand Down Expand Up @@ -1003,7 +1004,7 @@ mod parse_int_functions {
///
/// print(x.to_hex()); // prints "0302"
/// ```
#[rhai_fn(name = "parse_le_int")]
#[rhai_fn(name = "parse_le_int", pure)]
pub fn parse_le_int_range(blob: &mut Blob, range: ExclusiveRange) -> INT {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
Expand All @@ -1024,7 +1025,7 @@ mod parse_int_functions {
///
/// print(x.to_hex()); // prints "040302"
/// ```
#[rhai_fn(name = "parse_le_int")]
#[rhai_fn(name = "parse_le_int", pure)]
pub fn parse_le_int_range_inclusive(blob: &mut Blob, range: InclusiveRange) -> INT {
let start = INT::max(*range.start(), 0);
let end = INT::min(INT::max(*range.end(), start), INT::MAX - 1);
Expand All @@ -1051,6 +1052,7 @@ mod parse_int_functions {
///
/// print(x.to_hex()); // prints "0302"
/// ```
#[rhai_fn(pure)]
pub fn parse_le_int(blob: &mut Blob, start: INT, len: INT) -> INT {
parse_int(blob, start, len, true)
}
Expand All @@ -1069,7 +1071,7 @@ mod parse_int_functions {
///
/// print(x.to_hex()); // prints "02030000...00"
/// ```
#[rhai_fn(name = "parse_be_int")]
#[rhai_fn(name = "parse_be_int", pure)]
pub fn parse_be_int_range(blob: &mut Blob, range: ExclusiveRange) -> INT {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
Expand All @@ -1090,7 +1092,7 @@ mod parse_int_functions {
///
/// print(x.to_hex()); // prints "0203040000...00"
/// ```
#[rhai_fn(name = "parse_be_int")]
#[rhai_fn(name = "parse_be_int", pure)]
pub fn parse_be_int_range_inclusive(blob: &mut Blob, range: InclusiveRange) -> INT {
let start = INT::max(*range.start(), 0);
let end = INT::min(INT::max(*range.end(), start), INT::MAX - 1);
Expand All @@ -1117,6 +1119,7 @@ mod parse_int_functions {
///
/// print(x.to_hex()); // prints "02030000...00"
/// ```
#[rhai_fn(pure)]
pub fn parse_be_int(blob: &mut Blob, start: INT, len: INT) -> INT {
parse_int(blob, start, len, false)
}
Expand Down Expand Up @@ -1155,7 +1158,7 @@ mod parse_float_functions {
///
/// * If number of bytes in `range` < number of bytes for `FLOAT`, zeros are padded.
/// * If number of bytes in `range` > number of bytes for `FLOAT`, extra bytes are ignored.
#[rhai_fn(name = "parse_le_float")]
#[rhai_fn(name = "parse_le_float", pure)]
pub fn parse_le_float_range(blob: &mut Blob, range: ExclusiveRange) -> FLOAT {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
Expand All @@ -1166,7 +1169,7 @@ mod parse_float_functions {
///
/// * If number of bytes in `range` < number of bytes for `FLOAT`, zeros are padded.
/// * If number of bytes in `range` > number of bytes for `FLOAT`, extra bytes are ignored.
#[rhai_fn(name = "parse_le_float")]
#[rhai_fn(name = "parse_le_float", pure)]
pub fn parse_le_float_range_inclusive(blob: &mut Blob, range: InclusiveRange) -> FLOAT {
let start = INT::max(*range.start(), 0);
let end = INT::min(INT::max(*range.end(), start), INT::MAX - 1);
Expand All @@ -1183,6 +1186,7 @@ mod parse_float_functions {
///
/// * If number of bytes in range < number of bytes for `FLOAT`, zeros are padded.
/// * If number of bytes in range > number of bytes for `FLOAT`, extra bytes are ignored.
#[rhai_fn(pure)]
pub fn parse_le_float(blob: &mut Blob, start: INT, len: INT) -> FLOAT {
parse_float(blob, start, len, true)
}
Expand All @@ -1191,7 +1195,7 @@ mod parse_float_functions {
///
/// * If number of bytes in `range` < number of bytes for `FLOAT`, zeros are padded.
/// * If number of bytes in `range` > number of bytes for `FLOAT`, extra bytes are ignored.
#[rhai_fn(name = "parse_be_float")]
#[rhai_fn(name = "parse_be_float", pure)]
pub fn parse_be_float_range(blob: &mut Blob, range: ExclusiveRange) -> FLOAT {
let start = INT::max(range.start, 0);
let end = INT::max(range.end, start);
Expand All @@ -1202,7 +1206,7 @@ mod parse_float_functions {
///
/// * If number of bytes in `range` < number of bytes for `FLOAT`, zeros are padded.
/// * If number of bytes in `range` > number of bytes for `FLOAT`, extra bytes are ignored.
#[rhai_fn(name = "parse_be_float")]
#[rhai_fn(name = "parse_be_float", pure)]
pub fn parse_be_float_range_inclusive(blob: &mut Blob, range: InclusiveRange) -> FLOAT {
let start = INT::max(*range.start(), 0);
let end = INT::min(INT::max(*range.end(), start), INT::MAX - 1);
Expand All @@ -1219,6 +1223,7 @@ mod parse_float_functions {
///
/// * If number of bytes in range < number of bytes for `FLOAT`, zeros are padded.
/// * If number of bytes in range > number of bytes for `FLOAT`, extra bytes are ignored.
#[rhai_fn(pure)]
pub fn parse_be_float(blob: &mut Blob, start: INT, len: INT) -> FLOAT {
parse_float(blob, start, len, false)
}
Expand Down
Loading
Loading